前言:
让我们开始排序的学习吧,首先我们先理解一下插入排序的基本思想:每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,知道所有待排序记录全部插入为止。(这个可能会和选择排相似,但是那个是设置最大或最小,然后依次找到最大或最小插入到特定位置,而选择依次比较后移或前移,不要混淆哦)。
一、直接插入排序
这个大家都应该很清楚,之前的我们在写这个操作的时候是查找到位置之后把元素放到这个位置,然后其后的元素向后移动。而这里我们给出的算法是边查找边移动。(和查找一样也设置岗哨避免越界,自i-1起往前查找)。
【算法描述】
void InsertSort(SqList &L)
{//对顺序表L做直接插入排序
for(i=2;i<L.length;++i)
if(L.r[i].key<L.r[r-1].key)//“<”,需将r[i]插入有序子表
{
L.r[0]=L.r[i];//将待插入的记录暂存到监视哨中
L.r[i]=L.r[r-1];//r[i-1]后移
for(j=i-2;L.r[0].key<L.r[j].key;--j)//从后向前查找插入位置
L.r[j+1]=L.r[j];//将r[0]即原r[i],插入到正确位置
L.r[j+1]=L.r[0];//if
}
}
二、折半插入排序
我们发现上述的直接插入排序在查找的时候是顺序查找,所以我们在进行查找操作的时候利用“折半查找”来实现,是不是查找的时间复杂度就更好了呢!(之前查找的时候我们只关注查找的时间复杂度,现在排序之后我们就需要关注查找、移动的时间复杂度)。
【算法描述】
void BInsertSort(SqList &L){
//对顺序表L做折半插入排序
int i,j,low,high,m;
for(i=2;i<=L.length;++i)
{
L.r[0]=L.r[i]; //将待插入的记录暂存到监视哨中
low=1; high=i-1; //置查找区间初值
while(low<=high)
{ //在r[low..high]中折半查找插入的位置
m=(low+high)/2; //折半
if(L.r[0].key<L.r[m].key) high=m-1; //插入点在前一子表
else low=m+1; //插入点在后一子表
}//while
for(j=i-1;j>=high+1;--j) L.r[j+1]=L.r[j]; //记录后移
L.r[high+1]=L.r[0]; //将r[0]即原r[i],插入到正确位置
} //for
} //BInsertSort
三、希尔排序
但是聪明的你会想,会不会有更好的方法,从“减少记录个数”和“序列基本有序”两个方面对直接插入排序再进行改进呢?——答案就是希尔排序啦。(核心就是增量)
【算法步骤】
[1]第一趟取增量d1(d1<n)把全部记录分成d1个组,所有间隔为d1的记录分在同一组,在各个组中进行直接插入排序。
[2]第二趟去增量d2(d2<d1),重复上述的分组和排序。
[3]依次类推,知道所取的增量d1=1,所有记录在同一组中进行直接排序为止
(这里我们通常会取5,3,1这几个数字作为增量)。
来,看看图理解一下。
你看这个图中的例子,第一次增量是5,然后就找到交换位置,第二次也是如此。
这里给出希尔排序的演示程序:
// 希尔排序
#include <iostream>
using namespace std;
#define MAXSIZE 20 //顺序表的最大长度
typedef struct
{
int key;
char *otherinfo;
}ElemType;
//顺序表的存储结构
typedef struct
{
ElemType *r; //存储空间的基地址
int length; //顺序表长度
}SqList; //顺序表类型
void ShellInsert(SqList &L,int dk)
{
//对顺序表L做一趟增量是dk的希尔插入排序
int i,j;
for(i=dk+1;i<=L.length;++i)
if(L.r[i].key<L.r[i-dk].key)
{ //需将L.r[i]插入有序增量子表
L.r[0]=L.r[i]; //暂存在L.r[0]
for(j=i-dk;j>0&& L.r[0].key<L.r[j].key;j-=dk)
L.r[j+dk]=L.r[j]; //记录后移,直到找到插入位置
L.r[j+dk]=L.r[0]; //将r[0]即原r[i],插入到正确位置
} //for
}
//ShellInsert
void ShellSort(SqList &L,int dt[ ],int t){
//按增量序列dt[0..t-1]对顺序表L作t趟希尔排序
int k;
for(k=0;k<t;++k)
ShellInsert(L,dt[k]); //一趟增量为dt[t]的希尔插入排序
} //ShellSort
void Create_Sq(SqList &L)
{
int i,n;
cout<<"请输入数据个数,不超过"<<MAXSIZE<<"个。"<<endl;
cin>>n; //输入个数
cout<<"请输入待排序的数据:\n";
while(n>MAXSIZE)
{
cout<<"个数超过上限,不能超过"<<MAXSIZE<<",请重新输入"<<endl;
cin>>n;
}
for(i=1;i<=n;i++)
{
cin>>L.r[i].key;
L.length++;
}
}
void show(SqList L)
{
int i;
for(i=1;i<=L.length;i++)
cout<<L.r[i].key<<endl;
}
void main()
{
SqList L;
L.r=new ElemType[MAXSIZE+1];
L.length=0;
Create_Sq(L);
int i,t;//增量数组的长度
int *dt=new int[MAXSIZE];//增量数组
cout<<"请输入增量个数:\n";
cin>>t;
for(i=0;i<t;i++)
{
cout<<"第"<<i+1<<"个增量:\n";
cin>>dt[i];
}
ShellSort(L,dt,t);
cout<<"排序后的结果为:"<<endl;
show(L);
}
后记:
排序冲冲冲!如果有误可以评论指出哦,谢谢。