插入排序(直接插入排序、折半插入排序和希尔排序)

所谓插入排序就是将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中,直到全部记录插入完成。

1.直接插入排序
假设在排序过程中,待排序表L[1…n]在某次排序过程中的某一时刻状态如下:
在这里插入图片描述

为了实现将元素L[i]插入到已有序列的子序列L[1…i-1]中,需要执行以下操作:
(1)查找L(i)在L[1…i-1]中的插入位置。注意是从1到n !!!
(2) 将L[k…i-1]中所有元素全部后移一个位置。
(3)将L(i)复制到L(k)。
为了实现对L[1…n]的排序,可以将L(2)~L(n)依次插入到前面已排好序的子序列中,初始假定L[1]是一个已排好序的子序列。执行n-1次插入排序,就能得到一个有序的表。代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
void InsertSort(int a[], int n);

int main(){
 int n;
 int maxn=110;
 
 printf("请输入元素的个数:\n"); 
 scanf("%d",&n);
 int a[maxn];
 printf("请输入数组中的元素:\n");
 for(int i=1; i<=n; i++){
  scanf("%d", &a[i]);
 } 
 a[0] = 1110;
 InsertSort(a, n);
  printf("请输出排序好的数组:\n");
 for(int i=1; i<=n; i++){
  printf("%d ",a[i]);
 } 
  
  return 0;
}

void InsertSort(int a[], int n){
 int i, j;
 for (i= 2; i<=n; i++){  //进行n-1趟排序 
  if(a[i]<a[i-1]){
   a[0] = a[i];  //a[0]为哨兵,不存放元素 
   for(j =i-1; a[0]<a[j]; j--){
    a[j+1] = a[j];   //往后挪位 
   }
   a[j+1] = a[0];   //复制到插入位置 
  }
 }
}

/*
void InsertSort(int a[], int n){
 
 for(int i= 2; i<= n; i++)
 {
  int temp = a[i], j= i;
  while(j >1  && temp < a[j-1]){
   a[j] = a[j-1];
   j--;
  } 
  a[j] = temp;
 }
} 

编译运行的结果如图所示:
在这里插入图片描述

2.折半插入排序
从前面的直接插入排序算法中,不难看出每趟插入的过程中,都进行了两项工作:1 从前面的字表中查找出待插入元素应该被插入的位置; 2 给插入位置腾出空间,将待插入元素复制到表中的插入位置。直接插入排序算法总是边比较边移动元素,下面将比较和移动操作分离出来,即先折半查找出元素的待插入位置,然后再统一地移动待插入位置之后的所有元素。当排序表为顺序存储的线性表时,可以对直接插入排序算法作如下改进:
由于是顺序存储的线性表,所以查找有序子表时可以用折半查找来实现,在确定出待插入位置后,就可以统一地向后移动元素了。代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
void BinaryInsertSort(int a[], int n);

int main(){
 int n;
 int maxn=110;
 
 printf("请输入元素的个数:\n"); 
 scanf("%d",&n);
 int a[maxn];
 printf("请输入数组中的元素:\n");
 for(int i=1; i<=n; i++){
  scanf("%d", &a[i]);
 } 
 a[0] = 1110;
 BinaryInsertSort(a, n);
 printf("请输出排序好的数组:\n");
 for(int i=1; i<=n; i++){
  printf("%d ",a[i]);
 } 
  return 0;
} 

void BinaryInsertSort(int a[], int n){
 int i, j ,low,high,mid;
 for(i =2; i<=n; i++){
 int low = 1, high = i-1;
  a[0] = a[i];
  while(low <=high){
  mid = (low + high)/2;
   if(a[mid] > a[0])    high = mid-1;
   else  low = mid +1;
  }
  for(j = i-1; j >= high+1; j--){
   a[j +1] = a[j];
  }
    a[high +1] = a[0];
 }
}
    

3.希尔排序
直接插入排序算法适用于基本有序的排序表和数据量不大的排序表。基于这两点,D.L.Shell提出了希尔排序,又称为缩小增量排序。
希尔排序的基本思想:先将待排序表分割成若干个形如L[i, i+d, i+2d,…i+kd]的“特殊”字表,分别进行直接插入排序,希尔排序的排序过程如下:
先取一个小于n的步长d1(d1 = n/2),把表中全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组,在各组中进行排序;然后取d2(d2 = d1/2),重复上述过程,直到所取到的dn = 1,即所有记录已放在同一组中,再进行直接排序,由于此时已经具有较好的局部有序性,故很快得到最终结果,代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
void ShellSort(int a[], int n);
int main(){
 int n;
 int maxn=110;
 printf("请输入元素的个数:\n"); 
 scanf("%d",&n);
 int a[maxn];
 printf("请输入数组中的元素:\n");
 for(int i=1; i<=n; i++){
  scanf("%d", &a[i]);
 } 
 a[0] = 1110;
 
 ShellSort(a, n);
 printf("请输出排序好的数组:\n");
 for(int i=1; i<=n; i++){
  printf("%d ",a[i]);
 } 
   return 0;
} 

void ShellSort(int a[], int n){
 
 for(int dk = n/2; dk>=1; dk = dk/2){
  for(int i = dk+1; i <= n; i++){
   if(a[i] < a[i -dk]){
   a[0] = a[i];
    int j;
    for( j = i-dk; j>0&&a[0] <a[j]; j= j-dk){
     a[j+dk] = a[j]}
    a[j +dk]= a[0];
   }
  }
 }
}
    

猜你喜欢

转载自blog.csdn.net/xiaoyong5854/article/details/106283155