算法之路——插入排序篇1

  本文共有两个关于插入排序的算法,是我自己看书之后的代码实现及自己的理解分析。中间还夹杂着我犯的错误和改正的地方。不当之处,还希望不吝赐教!

1.直接插入排序
2.折半插入排序

(表插入排序将在下一篇文章)

代码如下:

/*sort_insertion_sort.h文件*/

#ifndef sort_insertion_sort
#define sort_insertion_sort

#define MAXSIZE 100
typedef int KeyType;

typedef struct {
KeyType data;
//其他的属性
}RedType,* PRedType;

typedef struct {
RedType list[MAXSIZE];
int length;
}SqList, * PSqList;

#define K_T "%d" //用于输入输出 如 printf(K_T, p->list[i].data);

#define OK 0
#define P_NULL 1
#define TOOBIG 2
#define NUM_ERROR 3

int comp(void * d1, void * d2);
int inputList (PSqList p,int length);
int outputList (PSqList p);
int SInsertSort (PSqList p, int (*comp)(void *,void *));
int BInsertSort (PSqList p, int (*comp)(void *,void *));

#endif

/*sort_insertion_sort.cpp文件*/

//关于插入排序的代码练习,
#include <stdio.h>
#include <stdlib.h>
#include "sort_insertion_sort.h"

int comp(void * d1, void * d2)
{//比较函数
return (((PRedType)d1)->data - ((PRedType)d2)->data );
}
int inputList (PSqList p,int length)
{//输入序列

if (p == NULL)
return P_NULL; //1,指针是空的
if (length > MAXSIZE)
return TOOBIG; //2,要输入的序列太多

int i = 0;
for (i = 0; i < length; i++)
if (scanf(K_T,&(p->list[i].data)) != 1)
return NUM_ERROR; //3,输入的数字有误

p->length = length;
return OK; //0
}

int outputList (PSqList p)
{//输出序列
if (p == NULL)
return P_NULL;

int i = 0;
for (i =0; i < p->length; i++)
printf (K_T"\t",p->list[i].data);
putchar('\n');
return OK;
}//outputList

int SInsertSort (PSqList p, int (*comp)(void *,void *))
{
//直接插入排序
if (p == NULL)
return P_NULL;

RedType tmp;
int i = 0, j = 0;

for (i = 1; i < p->length; i++) //i表示将要被插入的下标
{
tmp = p->list[i]; //保存第i个数据

//找到合适的位置
for (j = i - 1 ; j >= 0 && comp(&(p->list[j]), &tmp) > 0; j--) //#####
p->list[j+1] = p->list[j];

p->list[j+1] = tmp; //插入
}
return OK;
}//SInsertSort



int BInsertSort (PSqList p, int (*comp)(void *,void *))
{
if (p == NULL)
return P_NULL;

//折半插入排序
RedType tmp;
int low, high, i, j;
low = high = 0;
i = 0;
int status; //记录每次比较的结果
for (i = 1; i < p->length; i++)
{
if (comp(&(p->list[i]),&(p->list[i-1])) < 0) //!!!!
{
tmp = p->list[i];
low = 0;
high = i - 1;
while (low <= high) //原来:while (low < high)
{
status = comp (&(p->list[i]), &(p->list[(low+high)/2]));
if ( status == 0)
{
high = (low+high)/2; //用high记录要插入的位置
break;
}//if
else
{
if (status < 0)
high = (low+high)/2 - 1;
else
low = (low + high)/2 +1;
}//else
}//while

// if (comp (&(p->list[i]), &(p->list[high])) < 0) // @@@@@
// high--;

for (j = i-1; j > high; j--)
p->list[j+1] = p->list[j];
p->list[high+1] = tmp;
}
}
return OK;
}//BInsertSort

//以下是我这次写代码是出现的问题的总结和决绝方法。

/*
1. ####处的“comp(&(p->list[j]), &tmp)”;只能是tmp。我之前写的是“comp(&(p->list[j]), &(p->list[i]))”是不可以的,虽然tmp是由
p->list[i]赋值而来,可是p->list[i]随着while()的进行很可能会被p->list[i-1]覆盖,就会出错。所以只能用tmp。

2. 二分法里,最后当low == high时,还不能确定第i个元素改插入的位置,因为不能确定第high个元素与第i个元素的大小关系,所以需要@@@@
处的判断,如果第i个元素比第high个元素小,就把high减小1,之后可以确定第i个元素钙放的位置,才是自减过后的high+1的位置。
不过,如果在while循环里加上个"="的话,出来的high位置的值一定是小于或等于第i个元素的位置,并且第二个元素也会放在正确的位置,
所以这个解决方法更好


3.(while(low < high)的情况,没有“=”)还要注意:当在插入第二个元素时,如果仅仅只有二分法的循环是判断不出来第二个元素的位置的,因为low = 0;high = i - 1;之后low==high==0
不会进入循环的。因此第一个元素和第二个元素的大小关系不知道。所以需要!!!!处的判断,而且该判断还有个好处,不需要的移动的元素不会进入二分
查找
*/

/*这是main.cpp文件*/
#include <stdio.h>
#include <stdlib.h>
#include "sort_insertion_sort.h"
int main (int argc, char * argv)
{
int status;
PSqList test;
test = (PSqList)malloc(sizeof(SqList));
int n = 0 ;
printf("请输入第一组待排序的数的个数(输入0结束循环):");

while (1)
{
while (scanf("%d",&n) != 1)
{
puts("输入有误!请重新输入!");
while(getchar() != '\n');
}

if (n == 0) //结束
break;
if (status = inputList(test, n) != 0)
{
puts("输入的数字有误!");
while(getchar() != '\n');
//exit(status);
}
//BInsertSort (test,comp);
SInsertSort (test,comp);
outputList (test);
printf("请输入下一组待排序的数的个数(输入0结束循环):");
}
free(test);
return 0;
}



posted @ 2012-02-24 13:40  svking  阅读(217)  评论(0编辑  收藏  举报