1.插入排序:
插入排序可以视为两步操作,一步是插入,一步是排序。插入排序的基本思想是将一条记录插入到已经有序的序列中,继而得到一个有序的,数据个数加一的新序列。
2.直接插入排序:
直接插入排序把待排序序列视为两部分:一部分是有序序列,通常在排序开始之时将序列中的第一个数据视为有序序列;另一部分为待排序序列,有序序列之后的数据视为待排序序列。
下面给出使用直接插入排序算法将待排序序列转化为降序序列的代码实现:
void InsertSort(int* arr,int n)
{
int i=0;
int j=0;
for(i=1;i<n;i++)
{
//将数据插入有序表
int tmp=arr[i];//设置哨兵
if(tmp>arr[i-1])
{
//将比当前数据大的元素依次后移
for(j=i-1;j>=0&&tmp>arr[j];j--)
arr[j+1]=arr[j];
arr[j+1]=tmp;
}
}
}
直接插入算法的时间复杂度为O(n^2),因为在判断语句中,不会改变两个键值大小相同的记录在序列中的顺序,所以该算法是一个稳定的算法。
3.折半插入排序:
折半插入排序是对直接插入排序的改进。在直接插入排序中,主要的时间消耗在于数据的比较和移动上。由于在前半部分的序列已经有序,在为新数据寻找插入点时,可以采用折半查找的方法来提高寻找速度。
折半查入中的核心是插入点的查找,若插入点为k,找到插入点后,将有序序列中插入点之后的数据依次后移一位,将新数据插入到下标为k处。
使用折半排序的算法实现如下:
int BinarySort(int* arr,int n)
{
int i=0;
int j=0;
int low=0;
int high=0;
int m=0;
for(i=1;i<n;i++)
{
tmp=arr[i];
low=0;
high=i-1;
while(low<=high)
{
m=(low+hight)/2;
if(tmp>arr[m])
high=m-1;
else
low=m+1;
}
//移动有序序列中插入点之后的元素
for(j=i-1;j>=high+1;j--)
arr[j+1]=arr[j];
arr[high+1]=tmp;//将待排序数据插入有序序列
}
}
折半插入排序节省了排序过程中比较的次数,但是移动的次数与直接插入排序相同,所以其时间复杂度仍O(n^2).。分析算法可知,在两个数据关键字相同时,不会交换数据顺序,所以该算法是一个稳定的算法。
4.希尔排序:
希尔排序的基本思想是:先取定一个小于n的整数d1作为第一个增量,把序列的全部元素分为d1个组,所有相互间的距离为d1整数倍的元素放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(d2
void ShellSort(int* arr,int n)
{
int i=0;
int j=0;
int d=0;
int tmp=0;
d=n/2;
while(d>0)
{
for(i=d;i<n;i++)
{
tmp=arr[i];
j=i-d;
while(j>=0&&tmp>arr[j])//对每组中的数据进行排序
{
arr[j+d]=arr[j];
j=j-d;
}
arr[j+d]=tmp;
}
d=d/2;
}
}
希尔排序的核心算法仍为直接插入排序,但是希尔算法比直接插入排序多设置了一个步长增量,从而有效地减少了每轮排序比较的次数和比较的轮数,明显降低了时间消耗。
希尔排序的时间复杂度难以估计,通常认为时O(n^1.3)。另外希尔排序是一个不稳定的算法。