插入排序
1、简单插入排序
当你拿到一副扑克牌,如何将牌中的同花顺理起来呢?
思路:每次拿牌的时候,新牌需要合适的位置进行插入,从而形成长度增加1的有序序列。
如动图所示过程:
组序列为6、5、3、1、8、7、2、4,首先6和5比较,6比5大交互位置,接着3和5比较,6比3大交互位置,3和5比,交互位置,现在的序列就是3、5、6、1、8、7、2、4,这个时候要把1插入到序列中,首先在序列中查找以确定1所应插入的位置,然后进行插入操作,从6起向左顺序查找,由于1小于3,所以1插入的位置就是3的前面,一般情况下,第i(i大于等于1)个记录进行插入操作时,R1、R2,...,是排好序的有序数列,取出第i个元素,在序列中找到一个合适的位置并将它插入到该位置上即可。
/*****************简单插入排序*************/
#include <stdio.h>
#define MAX 10
void insert(int* a);
void print(int *a);
int main()
{
int a[MAX] = {9,8,7,6,5,4,3,2,1,0};
insert(a);
print(a);
return 0;
}
void insert(int* a) //简单插入排序
{
int i,j;
int temp;
for(i = 1;i < MAX;i++)
{
temp = a[i]; //此处引入变量temp,用来保存待比较的值
if(a[i - 1] > temp) //如果待比较的值比它前一个数小
{ //进行下一步的比较插入步骤
for(j = i - 1;j >= 0;j--) //待比较值的前一个数开始倒序遍历
{ //此处为i - 1
if(a[j] > temp) //如果待比较的值比它前面遍历的值小
{
a[j + 1] = a[j]; //将大的值复制一份给后面,为插入留出空间
}
else
{
break;
}
}
a[j + 1] = temp; //遍历比较过程结束,此时的j已经变为-1,将待插入的
} //temp保存的值放到开头
}
}
void print(int *a) //数组打印函数
{
int i;
for(i = 0;i < MAX;i++)
printf("%3d",a[i]);
printf("\n");
}
简单插入排序的性能分析:
平均性能 :
最好情况 | 最差情况 | 平均情况 | |
比较次数 | n | ||
移动次数 | 0 |
2、希尔排序
1959年Shell发明,第一个突破O(n^2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版》的合著者Robert Sedgewick提出的。
算法描述
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
- 步长通常为2^n±1
/*****************希尔排序*************/
#include <stdio.h>
#define MAX 10
void shell(int* a);
void print(int *a);
int main()
{
int a[MAX] = {84,83,88,87,61,50,70,60,80,99};
shell(a);
print(a);
return 0;
}
void shell(int* a) //简单插入排序
{
int i,j;
int temp;
int s[] = {1,3,5};
int k = 2;
int step = s[k];
while(k >= 0)
{
for(i = step;i < MAX;i++) //当步长为初始值5时,i从第6个元素开始向后遍历
{ //数组此时被分成两部分
temp = a[i]; //temp保存第二组第一个元素
if(a[i - step] > temp) //一组中的第一个值大于二组的第一个值
{
for(j = i - step;j >= 0;j -= step) //step为步长,将数组间相同位置的数值
{ //进行遍历
if(a[j] > temp) //如果一组中的第一个值大于二组的第一个值
{
a[j + step] = a[j]; //将第一组的第一个数复制到后面一组相同位置
}
else
{
break;
}
}
a[j + step] = temp; //将数组开头的值变更为temp保存的值
}
}
step = s[--k]; //步长减小,继续循环
}
}
void print(int *a) //数组打印函数
{
int i;
for(i = 0;i < MAX;i++)
printf("%3d",a[i]);
printf("\n");
}