c++ 插入排序(直接插入排序、折半插入排序、希尔排序)

直接插入排序:

  很简单,给定序列:23 44 12 13 54 25 41 由小到的排序。对数字所在位置分别编号 1,2,3,4,5,6,7

  • 2和1比较,44>23,位置不变   :23 44 12 13 54 25 41 
  • 3和2比较,12<44,继续3和1比较,12<23,到头了,然后把12插到最前面   :12 23 44 13 54 25 41    于是,1,2两个位置上的数字为有序队列
  • 4和3比较,13<44。继续4和2比较,13<23。继续4和1比较,13>12。把13插到12前面   :13 12 23 44 54 25 41    于是,1,2,3三个位置上的数字为有序队列,剩下的为无序队列。
  • ········

总之:从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列。


typedef struct {
	ReadType r[MAXSIZE];  //一般r[0]闲置用作哨兵单元
	int length;           //用一个整型变量来记录顺序表的长度
}SqList;                  //这个表的类型名


//直接插入排序(从小到大排序)
void InsertSort(SqList &L)
{
	int j;
	for (int i = 2; i <= L.length; i++)
		if (L.r[i].key < L.r[i - 1].key)  //r[i].key和已经排好的有序部分的最后一个元素的key,也就是和前面的数字中最大的数做比较
		{
			L.r[0] = L.r[i];              //满足条件(比前面的第一个数字小),放入哨兵单元
			L.r[i] = L.r[i - 1];          //先把第[r-1]个后移,覆盖r的位置
			for (j = i - 2; L.r[0].key < L.r[j].key; j--) //再把剩下[r-1]前面的&&比r[0]大的全部后移
				L.r[j + 1] = L.r[j];
			L.r[j + 1] = L.r[0];          //最后的位置用哨兵单元补齐
		}//简而言之:if里面做的操作就是 从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列
}

折半插入排序:

  和直接插入相比,查找插入位置由顺序查找变为折半查找,不过插入方式还是相同的

void BInsertSort(SqList &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)            //用二分法查找在排好的有序的部分中查找找第i个元素插入的位置(找到一个位置m,一个比当前r[i]大和r[i]小的数之间)
		{
			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--)//找到之后,位置是r[high+1],把r[i](即此时所要插入有序部分的元素) 之前的元素后移,从i-2开始后移
			L.r[j + 1] = L.r[j];     //后移即赋值,最后r[high+1]和它后一个元素赋值后相等
		L.r[high + 1] = L.r[0];   //最后将要插入的元素r[i]或者r[0](两者相等)插入到二分查找找到的位置r[high+1]
	}
}

希尔排序:

  直接插入其实是增量为1的一趟直接插入排序 而希尔排序是增量由大变小的好几趟直接插入排序
  思路;(简单一点取增量 3,1)

 

  1. 分组 把 第1,4,7,10...各元素分成一组 ,把第2,5,8,11...个元素分成一组,依次以3为增量,分完所有元素
  2. 排序 在以上分好的组中分别进行直接插入排序,使得每一组都有序
  3. 分组 以增量为1,分组,只能分成一组了
  4. 排序 在这一组中进行直接插入排序
//待排序记录的存储方式
#define MAXSIZE 50

typedef struct {
	int key;               //关键字类型默认简化设置为整型
	char otherinfo;        //其他数据项默认简化设置为char型
}ReadType;

typedef struct {
	ReadType r[MAXSIZE];  //一般r[0]闲置用作哨兵单元
	int length;           //用一个整型变量来记录顺序表的长度
}SqList;                  //这个表的类型名


//对序列表做一趟增量为dk的希尔插入排序
void ShellInsert(SqList &L, int dk)
{
	for (int i = dk + 1; i <= L.length; i++)
		if (L.r[i].key < L.r[i - dk].key)
		{
			L.r[0] = L.r[i];
			int j;
			//增量为dk组成的一组序列进行直接插入排序
			for (j = i - dk; j > 0 && L.r[0].key < L.r[j].key; j -= dk)//把这一组中 已经排好序的有序部分中 大于r[0].key的元素全部后移
				L.r[j + dk] = L.r[j];
			L.r[j + dk] = L.r[0]; //把r[0]放到有序部分中所有大于r[0].key的元素之后
		}

}
//给ShellInsert()不同的增量
void Shellsort(SqList &L, int dt[], int t)
{
	for (int k = 0; k < t; k++)
	{
		ShellInsert(L, dt[k]);  // (dt[0] = 5,dt[1] = 3,.....)
	}
}

main方法运行:

#include<iostream>
#include <ctime>
using namespace std;


//待排序记录的存储方式
#define MAXSIZE 50

typedef struct {
	int key;               //关键字类型默认简化设置为整型
	char otherinfo;        //其他数据项默认简化设置为char型
}ReadType;

typedef struct {
	ReadType r[MAXSIZE];  //一般r[0]闲置用作哨兵单元
	int length;           //用一个整型变量来记录顺序表的长度
}SqList;                  //这个表的类型名


//插入排序


//产生长度为length的0~100的随机序列
void Make_random(SqList &L, int length)
{
	time_t now = time(NULL);
	srand(unsigned(now));
	L.length = 0;
	for (int i = 1; i <= length; i++)
	{
		L.r[i].key = rand() % 100;        //生成0~100的随机数
		L.r[i].otherinfo = rand() % 100;
		L.length++;
	}
}

//公用输出函数
void Cout_SqList(SqList &L)
{

	for (int i = 1; i <= L.length; i++)
	{
		cout << L.r[i].key << " ";
		//cout << L.r[i].otherinfo << " ";
	}
	cout << endl;
}



//直接插入排序(从小到大排序)
void InsertSort(SqList &L)
{
	int j;
	for (int i = 2; i <= L.length; i++)
		if (L.r[i].key < L.r[i - 1].key)  //r[i].key和已经排好的有序部分的最后一个元素的key,也就是和前面的数字中最大的数做比较
		{
			L.r[0] = L.r[i];              //满足条件(比前面的第一个数字小),放入哨兵单元
			L.r[i] = L.r[i - 1];          //先把第[r-1]个后移,覆盖r的位置
			for (j = i - 2; L.r[0].key < L.r[j].key; j--) //再把剩下[r-1]前面的&&比r[0]大的全部后移
				L.r[j + 1] = L.r[j];
			L.r[j + 1] = L.r[0];          //最后的位置用哨兵单元补齐
		}//简而言之:if里面做的操作就是 从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列
}
//折半插入排序:和直接插入相比,查找插入位置由依次查找变为折半查找,插入方式相同
void BInsertSort(SqList &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)            //用二分法查找在排好的有序的部分中查找找第i个元素插入的位置(找到一个位置m,一个比当前r[i]大和r[i]小的数之间)
		{
			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--)//找到之后,位置是r[high+1],把r[i](即此时所要插入有序部分的元素) 之前的元素后移,从i-2开始后移
			L.r[j + 1] = L.r[j];     //后移即赋值,最后r[high+1]和它后一个元素赋值后相等
		L.r[high + 1] = L.r[0];   //最后将要插入的元素r[i]或者r[0](两者相等)插入到二分查找找到的位置r[high+1]
	}
}


//对序列表做一趟增量为dk的希尔插入排序
void ShellInsert(SqList &L, int dk)
{
	for (int i = dk + 1; i <= L.length; i++)
		if (L.r[i].key < L.r[i - dk].key)
		{
			L.r[0] = L.r[i];
			int j;
			//增量为dk组成的一组序列进行直接插入排序
			for (j = i - dk; j > 0 && L.r[0].key < L.r[j].key; j -= dk)//把这一组中 已经排好序的有序部分中 大于r[0].key的元素全部后移
				L.r[j + dk] = L.r[j];
			L.r[j + dk] = L.r[0]; //把r[0]放到有序部分中所有大于r[0].key的元素之后
		}

}
//给ShellInsert()不同的增量
void Shellsort(SqList &L, int dt[], int t)
{
	for (int k = 0; k < t; k++)
	{
		ShellInsert(L, dt[k]);  // (dt[0] = 5,dt[1] = 3,.....)
	}
}




int main()
{
	SqList L1;
	Make_random(L1, 10);
	Cout_SqList(L1);
	cout << "直接插入排序:" << endl;
	InsertSort(L1);
	Cout_SqList(L1);
	cout << endl << endl;

	SqList L2;
	Make_random(L2, 10);
	Cout_SqList(L2);
	cout << "折半插入排序:" << endl;
	BInsertSort(L2);
	Cout_SqList(L2);
	cout << endl << endl;

	SqList L3;
	int dt[3] = { 5,3,1 }; //设置增量序列为5,3,1  条件:递减&&最后增量为1
	Make_random(L3, 10);
	Cout_SqList(L3);
	cout << "希尔排序:" << endl;
	Shellsort(L3, dt, 3);
	Cout_SqList(L3);
	cout << endl << endl;

	return 0;
}



运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值