所谓插入排序就是将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中,直到全部记录插入完成。
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];
}
}
}
}