一.上期回顾
1.判断条件改掉,即if(arr[j]<arr[j+1]
2.删除赋值语句arr[0]=arr[low];
二.插入排序
本期的插入排序包括直接插入排序,折半插入排序,希尔排序三种排序方法,下面,我会依次展开描述。
2.1直接插入排序
原理:对已排好的序列,往其中插入新元素的过程,直接插入排序适用于接近有序(顺序有序时间复杂度最小,逆序有序时间复杂度最大)的序列,这个原理类似我们打牌的抓牌环节,我们手上的牌已排好的前提下抓取一张牌放入合适位置,对于一个数组,我们找到合适的插入位置后,将待插入位置元素及其之后的元素后移,为插入元素腾出空间即可完成排序。案例:定义一个整形数组arr[]={5,9,2,3,1,4,7,6,8},对其进行升序排序。
#include <stdio.h>
//直接插入排序
void Insertion_sort(int arr[],int length)
{
//升序
int i,j;
for(j=1;j<length;j++)//j是待插入元素下标
{
i=j-1;
int key=arr[j];
while(i>=0&&arr[i]>key)
{
arr[i+1]=arr[i];
i=i-1;
}
arr[i+1]=key;//插入元素
}
//验证
for(int i=0;i<length;i++)
printf("%d ",arr[i]);
printf("\n");
}
int main()
{
int arr[]={5,9,2,3,1,4,7,6,8};
Insertion_sort(arr,sizeof(arr)/sizeof(int));
return 0;
}
2.2折半插入排序
折半插入排序是相对直接插入排序,明显的优势就是能快速找到插入位置,故时间复杂度相对直接插入排序较高,由于依旧是在有序序列找位置插入元素,所以利用折半方法可以找到插入位置,然后进行元素后移,插入待插元素即可完成排序。
#include <stdio.h>
//折半插入排序
void half_insertion_sort(int arr[],int length)
{
//升序
for(int i=1;i<length;i++)//依次插入元素
{
int low=1,high=i-1;
arr[0]=arr[i];//待插元素存于哨兵位置
while(low<=high)
{
int mid=(low+high)/2;
if(arr[i]<arr[mid])
high=mid-1;
else
low=mid+1;
}
//通过分析(你可以手动计算)插入的位置一定是high+1
//我们只需将high+1至i-1的元素后移即可
for(int j=i-1;j>=high+1;j--)
arr[j+1]=arr[j];
//插入元素
arr[high+1]=arr[0];
}
//验证
for(int i=1;i<length;i++)
printf("%d ",arr[i]);
printf("\n");
}
int main()
{
int arr[]={0,5,9,2,3,1,4,7,6,8};
half_insertion_sort(arr,sizeof(arr)/sizeof(int));
return 0;
}
2.3希尔排序
希尔排序就是通过不断把数据放到不同的区间,来逐步逼近有序的过程,通过间隔序列数组(所有元素满足互质,元素按下表递减,最后一个元素必须是1),通过序列数组长度次的直接插入排序实现整体数组排序。
#include <stdio.h>
//dk为待排序元素的间隔
void shell_Insert(int array[],int dk,int length)
{
int i=0,j=0;
//升序
for(i=1+dk;i<length;i++)
{
if(array[i]<array[i-dk])
{
array[0]=array[i];//哨兵位置存放待插入元素
for(j=i-dk;j>0&&array[j]>array[0];j-=dk)//j>0防止访问越界
array[j+dk]=array[j];
array[j+dk]=array[0];//插入元素
}
}
}
//希尔排序
void shell_sort(int array[],int delta[],int t,int length)//参数依次是要排序的数组 间隔序列 以及排序趟数
{
for(int k=1;k<=t;k++)
{
shell_Insert(array,delta[k],length);
}
//验证
for(int i=1;i<length;i++)
printf("%d ",array[i]);
printf("\n");
}
int main()
{
int arr[]={5,9,2,3,1,4,7,6,8};
int delta[]={5,3,1};
shell_sort(arr,delta,sizeof(delta)/sizeof(int),sizeof(arr)/sizeof(int));
return 0;
}
三.结语
3.1本期疑问
1.如何实现不带哨兵的折半插入排序?
2,分析三种算法的优劣?