您的位置:首页 > 其它

插入排序与希尔排序

2016-02-23 09:26 267 查看
插入排序就像打“斗地主”一样,手中的牌按大小顺序排列,当新拿到一张牌,插入手中合适的位置。对于数组的插入排序,在新数据插入到合适位置之前,必须给该数据腾出空间(需要对大于该数据的原数据进行移位)。

插入排序的原理相对较简单,插入排序对于有序的序列效率很高,详见下面代码。

希尔排序是插入排序的加强版,希尔排序增加了一个“步长”(也有的叫增量),既将现有的数据按照一定的步长分组,对该组内的数据进行排序;这个“步长”也会随着每次组内排序完毕重新生成新的步长(步长渐短),直到最后步长为“1”。

下面用以下数据为例:

         int array[10] = {9,8,7,1,2,3,6,5,4,0};

当step = 10/2,          {9,3},{8,6},{7,5},{1,4},{2,0}各为一组,分别插入排序

结果:  array[10] = {3,6,5,1,0,9,8,7,4,2};

当step = 5/2,            {3,5,0,8,4},{6,1,9,7,2}各为一组,分别插入排序 

结果:  array[10] = {0,1,3,2,4,6,5,7,8,9};

当step = 2/2,            {0,1,3,2,4,6,5,7,8,9}为一组,进行插入排序 

结果:  array[10] = {9,8,7,1,2,3,6,5,4,0};

初次看“插入排序”时,误以为类似冒泡,因为有位置交换;但是,冒泡的关键是交换,而插入的关键是”移位“。

时间复杂度

在调试“插入排序”与“希尔排序”的代码时,原以为“希尔排序”的时间复杂度更高,因为代码中“插入排序”用了2个for循环O(n^2),而“希尔排序”是2个for循环加一个while循环O(n^3),在经过调试发现“希尔排序”的时间复杂度相对要低。因为:

插入一次只能移动一个位置;而希尔排序按照不同step对元素进行插入排序,刚开始元素很无序的时候,step最大,插入排序的元素个数很少(速度快),而且一次性挪动了多个位置;当元素基本有序了,step很小,移位的次数也变少(插入排序对于有序的序列效率很高)。 

在代码中我加入了“计数count”证实了这一点。

稳定性

稳定性通俗地讲就是能保证排序前2个相等的数其所在序列的前后位置和排序后它们两个的前后位置顺序相同。例如:如果array[i] = array[j],array[i]原来在array[j]位置前面,排序后array[i]还是要在array[j]位置前。

插入排序(稳定):如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,所以插入排序是稳定的。
希尔排序(不稳定):由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

#include<stdio.h>
using namespace std;

//插入排序
void InsertSort(int array[], int num)
{
int step = 1;
int count = 0;
for(int i=step; i<num; i++)
{
int key = array[i];//key为插入排序,将数组中的第一个数据作为插入排序,然后依次遍历;
int j = i-step;
//if(array[i]<array[i-step])//1.这里可以增加一个判断,如果成立,说明前面顺序已经排好,无需再进行后面的
{
while(j>=0 && key < array[j])//key与j范围内的值比较,j会随着i的增大而增大。
{
array[j+step] = array[j];
j--;//j递减
++count;
}
array[j+step] = key;

for(int x=0;x<num;x++)
printf("%d ",array[x] );
printf("\n ");
}
}
printf("count = %d ", count);
printf("\n ");
}

//希尔排序
void shellSort(int array[], int num)
{
int step = 0; //步长
int count = 0; //移位次数计算
for (step = num/2; step > 0; step/= 2) //步长,最终步长必须为“1”
{
for (int i = step; i < num; i++)//从数组第step个元素开始
{
if (array[i] < array[i - step])//1.这里增加一个判断,如果成立,说明前面顺序已经排好,无需再进行后面的//2.每个元素与自己组内的数据进行直接插入排序
{
int key = array[i]; //key,当作插入值
int j = i - step; //j, key之前的值(插入值之前的值),距离为step的为一组值
while (j >= 0 && key < array[j] )//j确保在数组范围内
{
array[j + step] = array[j];//移位(距离为step)
j -= step; //j是一个变量,j随着step的移动而改变
++count;

}
array[j + step] = key;//key插入合适的位置(此时j可能为1个步长,也可能为多个步长),

for(int x=0;x<num;x++)
printf("%d ",array[x]);
printf("\n ");
}
}
}
printf("count = %d ", count);
printf("\n ");
}

int main()
{
printf("==============Test Insert Sort ==============\n");
int array[ ] = {9,8,7,1,2,3,6,5,4,0};
int array2[ ] = {9,8,7,6,5,4,3,2,1,0};
int array3[ ] = {9,8,7,1,2,3,6,5,4,0,19,18,17,11,12,13,16,15,14,10};
int array4[ ] = {9,8,7,1,2,3,6,5,4,0,19,18,17,11,12,13,16,15,14,10,29,28,27,21,22,23,26,25,24,20};
int array5[ ] = {29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
InsertSort(array2,sizeof(array2)/sizeof(array[0]));
printf("\n ");

printf("==============Test Shell Sort ==============\n");
int array1[ ] = {9,8,7,1,2,3,6,5,4,0};
int array12[ ] = {9,8,7,6,5,4,3,2,1,0};
int array14[ ] = {9,8,7,1,2,3,6,5,4,0,19,18,17,11,12,13,16,15,14,10,29,28,27,21,22,23,26,25,24,20};
int array15[ ] = {29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
shellSort(array12,sizeof(array2)/sizeof(array2[0]));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: