数据结构C++——插入排序(直接插入排序、折半插入排序和希尔排序)

数据结构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

六、总结

以上为笔者对于插入排序的一些见解,希望初学者都能有所收获,有技术不到位的地方,还望各位大佬指正。
同时,笔者的个人主页还有数据结构其他部分的一些见解与分析,后续数据结构的相关知识还将陆续更新,欢迎大家访问且共同学习!

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

近景_

打赏拉满,动力满满

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值