直接插入排序、二分法插入排序、表插入排序、Shell排序
下面分别依次介绍插入排序中的直接插入排序、二分法插入排序、表插入排序、Shell排序
一、直接插入排序
有点类似于打扑克时候,每抓一张牌把小的放左边,大的放右边。也即手上的这部分牌永远是从小到大排好序的,每抓一张牌均依次跟最右边的比较,知道找到一张比它小的或相等的,插在这张牌的后面。
C语言实现方式:
void InsertionSort(int *data, int len) { if(len <= 1) return; for(int i = 1; i < len; i++) { int value = data[i]; int j = i - 1;
//注:若能将data的第0个元素作为哨兵,待排序从第1个元素起,那么每次可以把data[0]=data[i],直接判断data[j]>data[0],从而不必要判断j>=0 while(j >= 0 && data[j] > value) { data[j + 1] = data[j];//大的记录往后移 j--; } data[j + 1] = value; //插入记录 } }
二、二分直接插入排序法
直接插入排序法中每次遇到第i+1个记录,均需顺序与前面i, i-1,...个记录去比较,由于前面i个记录已经是排序好的了,故可以参考二分查找的方式进行,即先与第(i+1)/2个记录比较,从而逐渐缩小范围,减少比较次数。
三、表插入排序
对于顺序存取的数组,每次插入的过程都伴随着大量的记录后移操作,为此我们可以考虑改造记录的类型结构,采用双向链表,这样就可以免去了移动操作,只需要修改目标位置前后的指针值就可以了。
四、SHELL排序
Shell排序法又称缩小增量法,由D.L.Shell在1959年提出,是对直接插入排序法的改进。其主要思想是:直接插入排序中,当初始序列为逆序时,时间效率最差。若初始序列基本有序时,则大多数记录不需要插入,时间效率大大提高。另外,当记录数n较小时,n2值受n的值影响不大。Shell排序正是从这两个方面考虑对直接插入排序进行改进。
1)先取一个整数d1<n, 把全部记录分成d1个组,所有距离为d1倍数的记录放在一组中,先在各组内排序
2)然后取d2<d1重复上述分组和排序工作
3)直到di=1,即所有记录放在一组中为止
各组内的排序可以采用直接插入法,也可以采用后面讲到的其它排序方法,如直接选择排序
对于增量的选择:Shell提出:d1 = n/2, d2=d1/2,依次类推;Knuth提出d1=n/3,d2=d1/3,依次类推。最后增量为1.还有其它选择,但何种最佳尚无法证明。无论如何,最后增量必须为1。
void ShellSort(int data[], int length) { for(int inc = length / 2; inc > 0; inc /= 2) { for(int i = inc; i < length; i++)//类似于插入排序,相当于根据每隔inc个抽取形成一组,然后应用插入排序方法对每组进行排序,这里从每组的第2个开始循环 { //对于每一条记录,按照inc的间隔插入前面的记录中 int value = data[i]; int j = i - inc; while(j >= 0 && data[j] > value) { data[j + inc] = data[j]; j -= inc; } data[j + inc] = value; } } }