数据结构C++——插入排序(直接插入排序、折半插入排序和希尔排序)
一、待排序记录的数据类型定义
待排序记录的数据类型定义
/*------------待排序记录的数据结构类型定义----------*/
#define MAXSIZE 1001//顺序表的最大长度
typedef int KeyType;//定义关键字类型为整型
typedef int InfoType;
typedef struct {
KeyType key;//关键字项
InfoType otherinfo;//其他数据项
}RedType;//记录类型
typedef struct {
RedType r[MAXSIZE + 1];//r[0]闲置或用做哨兵单元
int length;//顺序表长度
}SqList;//顺序表类型
二、直接插入排序
直接插入排序
直接插入排序的算法思路:
1:顺序表0号单元用做哨兵单元
2:从2号单元开始,和前一个单元比较,若此号单元值比前一个单元值小,说明此单元位置需要移动
3:将此单元值放入0号单元作为哨兵值,并将前一个单元值后移覆盖此单元
4:从前两个单元值开始寻找插入位置,直至找到比哨兵值小的单元值,在此区间内,记录逐个后移
5:将插入位置的单元值置为哨兵值
/*----------直接插入排序---------*/
void InsertSort(SqList& L) {
//对顺序表L做直接插入排序
int j = 0;
for(int i=2;i<=L.length;i++)
if (L.r[i].key < L.r[i - 1].key) {//"<",需将r[i]插入有序子表
L.r[0] = L.r[i];//将待插入的记录暂存到监视哨中
L.r[i] = L.r[i - 1];//r[i-1]后移
for ( j = i - 2; L.r[0].key<L.r[j].key ; j--)//从后向前寻找插入位置
L.r[j + 1] = L.r[j];//记录逐个后移,直到找到插入位置
L.r[j + 1] = L.r[0];//将r[0]即原r[i],插入到正确位置
}
}
三、折半插入排序
折半插入排序
折半插入排序的算法思路:
1:将待插入的记录暂存在监视哨中
2:置查找区间初值,不断折半缩小查找区间,找到插入位置
3:将此位置开始到i-1位置的单元均后移覆盖当前值
4:将哨兵值赋给插入位置单元值
折半插入排序与直接插入排序的最大不同是:寻找插入位置。
从时间上比较,折半查找比顺序查找快,所以就平均性能来说,折半插入排序优于直接插入排序。
在平均情况下,折半插入排序仅减少了关键字间的比较次数,而记录的移动次数不变,因此,折半插入排序的时间复杂度仍为O(n2)
/*--------折半插入排序----------*/
void BInsertSort(SqList& L) {
//对顺序表L做折半插入排序
for (int i = 2; i <= L.length; i++) {
L.r[0] = L.r[i];//将待插入的记录暂存到监视哨中
int low = 1;int high = i - 1;//置查找区间初值
while (low <= high) {
int m = (low + high) / 2;//折半
if (L.r[0].key < L.r[m].key) high = m - 1;//插入点在前一子表
else low = m + 1;//插入点在后一子表
}
for (int 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],插入到正确位置
}
}
四、希尔排序
希尔排序
希尔排序的算法思路:
1:对顺序表L做一趟增量是dk的希尔插入排序
2:不断缩小增量并做希尔排序
/*------------希尔排序--------------*/
void ShellInsert(SqList& L, int dk) {
//对顺序表L做一趟增量是dk的希尔插入排序
int j = 0;
for(int 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],插入到正确位置
}
}
void ShellSort(SqList& L, int dt[], int t) {
//按增量序列dt[0...t-1]对顺序表L作t趟希尔排序
for (int k = 0; k < t; k++)
ShellInsert(L, dt[k]);//一趟增量为dt[t]的希尔插入排序
}
五、测试的完整代码
测试的完整代码
#include<iostream>
using namespace std;
/*------------待排序记录的数据结构类型定义----------*/
#define MAXSIZE 1001//顺序表的最大长度
typedef int KeyType;//定义关键字类型为整型
typedef int InfoType;
typedef struct {
KeyType key;//关键字项
InfoType otherinfo;//其他数据项
}RedType;//记录类型
typedef struct {
RedType r[MAXSIZE + 1];//r[0]闲置或用做哨兵单元
int length;//顺序表长度
}SqList;//顺序表类型
/*----------创建顺序表---------*/
void CreateList(SqList& L) {
//cout << "请输入待排序数的个数:" << endl;
int n = 0;
cin >> n;
for (int i = 1; i < n+1; i++)
cin >> L.r[i].key;
L.length = n;
}
/*----------直接插入排序---------*/
void InsertSort(SqList& L) {
//对顺序表L做直接插入排序
int j = 0;
for(int i=2;i<=L.length;i++)
if (L.r[i].key < L.r[i - 1].key) {//"<",需将r[i]插入有序子表
L.r[0] = L.r[i];//将待插入的记录暂存到监视哨中
L.r[i] = L.r[i - 1];//r[i-1]后移
for ( j = i - 2; L.r[0].key<L.r[j].key ; j--)//从后向前寻找插入位置
L.r[j + 1] = L.r[j];//记录逐个后移,直到找到插入位置
L.r[j + 1] = L.r[0];//将r[0]即原r[i],插入到正确位置
}
}
/*--------折半插入排序----------*/
void BInsertSort(SqList& L) {
//对顺序表L做折半插入排序
for (int i = 2; i <= L.length; i++) {
L.r[0] = L.r[i];//将待插入的记录暂存到监视哨中
int low = 1;int high = i - 1;//置查找区间初值
while (low <= high) {
int m = (low + high) / 2;//折半
if (L.r[0].key < L.r[m].key) high = m - 1;//插入点在前一子表
else low = m + 1;//插入点在后一子表
}
for (int 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],插入到正确位置
}
}
/*------------希尔排序--------------*/
void ShellInsert(SqList& L, int dk) {
//对顺序表L做一趟增量是dk的希尔插入排序
int j = 0;
for(int 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],插入到正确位置
}
}
void ShellSort(SqList& L, int dt[], int t) {
//按增量序列dt[0...t-1]对顺序表L作t趟希尔排序
for (int k = 0; k < t; k++)
ShellInsert(L, dt[k]);//一趟增量为dt[t]的希尔插入排序
}
/*-----------输出排序结果----------*/
void PrintResut(SqList& L) {
for (int i = 1; i < L.length+1; i++)
cout << L.r[i].key << " ";
}
int main() {
SqList L;
CreateList(L);
BInsertSort(L);
PrintResut(L);
return 0;
}
输入:
10
2 8 4 6 1 10 7 3 5 9
1 2 3 4 5 6 7 8 9 10
六、总结
以上为笔者对于插入排序的一些见解,希望初学者都能有所收获,有技术不到位的地方,还望各位大佬指正。
同时,笔者的个人主页还有数据结构其他部分的一些见解与分析,后续数据结构的相关知识还将陆续更新,欢迎大家访问且共同学习!