学习目标:
1.了解插入排序思想
2.掌握直接插入排序和代码实现
3.掌握折半插入排序和代码实现
4.掌握希尔排序和代码实现
学习内容:
插入排序的思想是什么?
1.插入排序的思想:每次将一个待排序记录,按照其关键字的大小插入到前面已经排好序的子序列中。
前提:前面有已经排好序的子序列(若是插入的最初状态,子序列就是空的)
目的:插入待排序记录
手段:先在子序列查找,找到可插入位置后插入
故由于查找的手段不同,插入排序可以分为直接插入(顺序查找),折半插入(折半查找),希尔排序(先将排序表分为若个子块,而每个子块中使用直接插入排序,通过实现将子序列基本有序化,提高直接插入排序的效率)
直接插入排序
1.直接插入排序:采用顺序查询的思想将在已经排好序的序列中寻找该插入的位置
2.算法效率分析:
- 空间复杂度:可以使用常数个辅助单元存放待插入元素的关键字,也可以使用guard位置(数组的0号位置);故空间复杂度仅为O(1).
- 时间复杂度:算法中耗时的过程为比较元素关键字过程和向后移动元素的过程 ;
最好的情况是排序表中元素都有序,每次执行过程只需要比较一次,时间复杂度仅为O(n)。
最坏的情况是排序表中元素反序,这时比较次数和移动次数都达到最大,时间复杂度为O(n2).
平均情况下因为排序表元素的随机性,总的比较次数和总的移动次数均为n2/4,所以时间复杂度为O(n2).
注:直接插入排序的效率受待排序表的初始状态的影响
- 稳定性(有):因为每次插入元素都是从后向前先比较后移动,所以不会出现相同元素的位置变化。
- 适用性:顺序存储的线性表和链式存储的线性表都可以使用。
链式存储线性表的代码实现
顺序存储的线性表的代码实现
折半插入排序
1.折半插入排序:采用折半查找的思想在已经排好序的序列中寻找该插入的位置
2.算法效率分析:
- 空间复杂度:代码没有开辟额外空间,故空间复杂度仅为O(1).
- 时间复杂度:虽然折半查找加快了查找插入位置的过程,但是依旧需要遍历每一个元素,元素的移动次数没有改变,所以时间复杂度依然是O(n2).
- 稳定性(有):不会出现相同元素的位置变化。
- 适用性:仅适用于顺序存储线性表。
希尔排序
1.希尔排序:因为在要排序序列基本有序的情况下,直接插入排序的效率会更高。
通过选取一个小于n的步长将排序表分为多个子块,不断递减的步长使每次的待排序分块长度逐渐变大,最后对整表进行排序。
- 空间复杂度:代码没有开辟额外空间,故空间复杂度仅为O(1).
- 时间复杂度:时间复杂度是O(n1.3)~O(n2).
- 稳定性(没有):会出现相同元素的位置变化。
- 适用性:仅适用于顺序存储线性表。
代码实现:
直接插入排序的代码实现
#include <stdio.h>
#define MaxNum 10
void InsertSort(int *A,int n){
int i,j;
//第一次循环从数组中第二个位置开始(数组0位置为guard)
for (i=2;i<n;i++){//从前向后循环
if(A[i]<A[i-1]){//若i位置元素小于i-1位置元素
A[0]=A[i];//将i位置元素赋值给guard
for(j = i-1;A[j]>A[0];--j){//j指向i位置元素的前一个位置,并比较该位置元素是否小于guard
A[j+1]=A[j];//若大于guard,则将该位置元素后移
}
//每次循环结束j就会指向前一个位置
//若前一个位置不满足条件,跳出循环,此时j指向的是该插入位置的前一个
A[j+1] = A[0];//故j+1,后移一位到可插入位置
}
}
}
int main(){
int A[MaxNum];
A[0] = 0;//guard point
int n = MaxNum;
printf("please input numbers into the array\n");
for(int i = 1;i< n;i++){
int num = 0;
scanf("%d",&num);
A[i] = num;
printf("ok,this array remain space : %d\n",n-i-1);
}
printf("the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
printf("\nStart Sorting\n");
InsertSort(A,n);//进入直接插入排序
printf("Now Sort end!,the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
}
折半插入代码实现
#include <stdio.h>
#define MaxNum 10
void Binary_Sort(int *A,int n){
int i,j,mid,low,high;
for(i=2;i<=n;i++){ //比较的过程
if(A[i]<A[i-1]){
//出现了待插入元素
A[0]=A[i];
low = 1;high = i-1;
while(low<=high){//注意low是可以小于等于high,最后high-1会跑到low的前面,循环结束
mid = (low+high)/2;
if(A[0]<A[mid]){
//小于mid走左边
high = mid-1;
}else{
//大于mid走右边
low = mid+1;
}
}
//交换的过程
for(j=i-1;j>=high+1;--j){//注意j是大于等于high+1
A[j+1]=A[j];
}
A[high+1] = A[0];
}
}
}
int main(){
int A[MaxNum];
A[0] = 0;//guard point
int n = MaxNum;
printf("please input numbers into the array\n");
for(int i = 1;i< n;i++){
int num = 0;
scanf("%d",&num);
A[i] = num;
printf("ok,this array remain space : %d\n",n-i-1);
}
printf("the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
printf("\nStart Sorting\n");
Binary_Sort(A,n);
printf("Now Sort end!,the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
}
希尔排序代码实现
#include <stdio.h>
#define MaxNum 10
void ShellSort(int *A,int n){
int i,j;
int dk = n/2;
for(dk;dk>=1;dk=dk/2){//dk为步长,最初为数组长度的一半,每次循环折半
//比较过程
for(i=dk+1;i<=n;++i){//向左遍历,分块切换
//注意这里是++i,先加法操作后赋值
if(A[i]<A[i-dk]){
A[0] = A[i];
//移动过程
for(j = i-dk;j>0&&A[0]<A[j];j=j-dk){
A[j+dk]=A[j];//以dk为步长在分块中使用直接插入排序向后移动元素
}
A[j+dk] = A[0];
}
}
}
}
int main(){
int A[MaxNum];
A[0] = 0;//guard point
int n = MaxNum;
printf("please input numbers into the array\n");
for(int i = 1;i< n;i++){
int num = 0;
scanf("%d",&num);
A[i] = num;
printf("ok,this array remain space : %d\n",n-i-1);
}
printf("the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
printf("\nStart Sorting\n");
ShellSort(A,n);
printf("Now Sort end!,the array's elements include :\n");
for(int i = 0;i< n;i++){
printf("%d ",A[i]);
}
}
实现结构:
1.直接插入排序实现结果
2.折半插入排序代码运行结果
3.希尔排序代码运行结果