您的位置:首页 > 其它

插入排序

2016-01-12 19:49 169 查看
插入排序是一种经典的排序算法,其中心思想就是:

给定一组数据,划分为有序区和无序区,在无序区的元素选出一个插入到有序区,使之仍然有序,重复以上步骤,直到无序区不再有元素为止。

直接插入排序

一开始我们认为一个元素就是有序的,直接插入排序就是认为第一个元素有序,然后从第二个元素开始比较,插入到前面,共需比较n-1次,第n次移动的最多次数是n次,总共的移动次数n*(n-1)/2,所以时间复杂度o(n^2),由于是原地排序,只需要一个额外的变量保存插入值,空间复杂度是o(1);

//直接插入排序
void insert_sort(int a[], int size)
{
int i, j;
for (i=1; i<size; i++)//从第二个开始向前比较,一直到最后一个
{
int val = a[i];//先把a[i]保存起来,避免后面移位的时候覆盖到
j = i-1; //这里主要是为了比较大小和移位方便
while (j>=0 && a[j]>val) //j>=0,不能越界,如果前面的数大于后面的数,就执行下面的移位操作,给val的插入留出空间。
{
a[j+1] = a[j];//移位,不插入
j--;//再比较前一个,看是否可以插入
}
a[j+1] = val; //退出的情况只有两种,一种j=-1,那么在0位置插入val,一种a[j]<val,那么在后面可以插入val;
}
}


折半插入排序

折半插入排序的核心思想是直接在寻找插入位置的时候用到了二分查找,直接插入排序是一个一个的往前比较,而折半是在有序区中利用二分查找出合适位置,后面的元素后移移位,直接将待排序的值放入那个合适的位置。折半插入排序只是减少了比较的次数,而移动的次数还是一样的,所以复杂度和直接插入排序还是一样的。

int binary_find(int a[], int size, int key)
{
int low, mid, high;
low = 0;
high = size-1;
while (low <= high)
{
mid = (low+high)>> 1;
if (key >= a[mid]){
low = mid+1;
}else{
high = mid-1;
}
}
return low;
}

void binary_sort(int a[], int size)
{
int i, j, k, val;
for (i=1; i<size; i++)
{
val = a[i];
j = binary_find(a, i, a[i]);//寻找到合适的插入位置
for (k=i-1; k>=j; k--)
{
a[k+1] = a[k];
}
a[j] = val;
}
}


希尔排序

在实践中发现,插入排序是一种当数据基本有序的时候很快的排序算法,但是数据基本无序的时候移动次数就会很多,希尔排序是通过逐步缩小排序的增量来减少无序,增加有序的算法,是直接插入排序的改良版。其算法的时间复杂度和增量序列的取法有关,不过一般我们都认为是o(nlog2n),增量序列的取法有很多种,但需注意的是,应使增量序列的值没有除1之外的公因子,并且最后一个增量值必须为1.

void shell_insert(int a[], int size, int gap)
{
int i, j, k, m;
for (i=0; i<gap; i++)//一共有gap个序列,共进行gap个直接插入排序
{
for (j=i+gap; j<size; j+=gap)//每一个序列的直接插入排序
{
k = a[j];
m = j-gap;
while (m>=0 && a[m]>k)
{
a[m+gap] = a[m];
m -= gap;
}
a[m+gap] = k;
}
}
}

void shell_sort(int a[], int size)
{
int gap[4] = {5, 3, 2, 1};//增量数组,逐步缩小增量
int i;
for (i=0; i<4; i++)
{
shell_insert(a, size, gap[i]);
}
}


注:以上代码未经大量测试,可能有误,仅供参考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: