1. 插入排序
插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。
本节介绍两种插入排序方法:直接插入排序和希尔排序。直接插入排序基本思想1.直接插入排序的基本思想 直接插入排序(Straight Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
把a[i]插入到a[0],a[1],...,a[i-1]之中的具体实施过程为:先把a[i]赋值给变量t,然后将t依次与a[i-1],a[i-2],...进行比较,将比t大的元素右移一个位置,直到发现某个j(0<=j<=i-1),使得a[j]<=t或j为(-1),把t赋值给a[j+1].2、第i-1趟直接插入排序: 通常将一个记录R[i](i=2,3,…,n-1)插入到当前的有序区,使得插入后仍保证该区间里的记录是按关键字有序的操作称第i-1趟直接插入排序。 排序过程的某一中间时刻,R被划分成两个子区间R[1..i-1](已排好序的有序区)和R[i..n](当前未排序的部分,可称无序区)。 直接插入排序的基本操作是将当前无序区的第1个记录R[i]插人到有序区R[1..i-1]中适当的位置上,使R[1..i]变为新的有序区。因为这种方法每次使有序区增加1个记录,通常称增量法。 插入排序与打扑克时整理手上的牌非常类似。摸来的第1张牌无须整理,此后每次从桌上的牌(无序区)中摸最上面的1张并插入左手的牌(有序区)中正确的位置上。为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。一趟直接插入排序方法 1.简单方法 首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。 注意: 若R[i]的关键字大于等于R[1..i-1]中所有记录的关键字,则R[i]就是插入原位置。2.改进的方法 一种查找比较操作和记录移动操作交替地进行的方法。 具体做法: 将待插入记录R[i]的关键字从右向左依次与有序区中记录R[j](j=i-1,i-2,…,1)的关键字进行比较: ① 若R[j]的关键字大于R[i]的关键字,则将R[j]后移一个位置; ②若R[j]的关键字小于或等于R[i]的关键字,则查找过程结束,j+1即为R[i]的插入位置。 关键字比R[i]的关键字大的记录均已后移,所以j+1的位置已经腾空,只要将R[i]直接插入此位置即可完成一趟直接插入排序。2. 希尔排序思想
希尔排序(Shell Sort)是插入排序的一种。因D.L.Shell于1959年提出而得名。
希尔排序基本思想
基本思想
希尔排序(Shell Sort)又称为“缩小增量排序”。是1959年由D.L.Shell提出来的。该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
具体做法:首先确定一组增量d0,d1,d2,d3,...,dt-1()其中n>d0>d1>...>dt-1=1),对于i=0,1,2,...,t-1,依次进行下面的各趟处理:根据当前增量di将n个元素分成di个组,每组中元素的下标相隔为di;再对各组中元素进行直接插入排序.
2、下面给出希尔排序算法的执行过程。
(1)采用希尔排序法排序的各趟的结果如下:
初始:503,17,512,908,170,897,275,653,426,154,509,612,677,765,703,94
第1趟{d1=8}:426,17,509,612,170,765,275,94,503,154,512,908,677,897,703,653
第2趟(d2=4):170,17,275,94,426,154,509,612,503,765,512,653,677,897,703,908
第3趟(d3=2):170,17,275,94,426,154,503,612,509,653,512,765,677,897,703,908
第4趟(d1=1):17,94,154,170,275,426,503,509,512,612,653,677,703,765,897,908
(2)例如,n=8,数组a的八个元素分别为:17,3,30,25,14,17,20,9。
给定实例的shell排序的排序过程
假设待排序文件有10个记录,其关键字分别是:
49,38,65,97,76,13,27,49,55,04。
增量序列的取值依次为:
5,3,1
排序过程如【】。
Shell排序的算法实现 1. 不设监视哨的算法描述
void ShellPass(SeqList R,int d)
{//希尔排序中的一趟排序,d为当前增量
for(i=d+1;i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区
if(R[i].key<R[i-d].key){
R[0]=R[i];j=i-d; //R[0]只是暂存单元,不是哨兵
do {//查找R[i]的插入位置
R[j+d];=R[j]; //后移记录
j=j-d; //查找前一记录
}while(j>0&&R[0].key<R[j].key);
R[j+d]=R[0]; //插入R[i]到正确的位置上
} //endif
} //ShellPass
void ShellSort(SeqList R)
{
int increment=n; //增量初值,不妨设n>0
do {
increment=increment/3+1; //求下一增量
ShellPass(R,increment); //一趟增量为increment的Shell插入排序
}while(increment>1)
} //ShellSort
注意:
当增量d=1时,ShellPass和InsertSort基本一致,只是由于没有哨兵而在内循环中增加了一个循环判定条件"j>0",以防下标越界。
3.代码
#include运行结果:#include using namespace std;void ShellSort(int* a,int left,int right){ int len=right-left+1; int d=len; while(d>1) { d=(d+1)/2; //设置一个增量 for(int i = d;i < len;i ++) { int t = a[i]; int j = i-d; while(j>=0 && a[j]>t) { a[j+d]=a[j]; j = j -d; } a[j+d]=t; } }}void InsertSort(int *a, int len){ for(int i = 1;i < len;i ++) { int t = a[i]; int j = i-1; while(j>=0 && a[j]>t) { a[j+1]=a[j]; j--; } a[j+1]=t; }}void ShellSort2(int* a,int len){ int k = len /2; while(k>0) { for(int i = k;i <= len;i ++) { int t= a[i]; int j= i - k; while(j>=0 && t < a[j]) { a[j+k]=a[j]; j=j-k; } a[j+k]=t; } k/=2; }}int main (){ int size = 4; int list[size]; int i; printf("Enter 4 number: "); for(i=0;i
注意到:
希尔排序在分完组之后,用到了插入排序。
通过对比程序,明显可以发现,只是将程序中的凡是与j相关的均加减d,其他与插入排序一样。
版权声明:本文为博主原创文章,未经博主允许不得转载。