【数据结构】插入排序

数据结构 专栏收录该内容
17 篇文章 1 订阅

数据结构中的插入排序

参考代码如下:


/*
	名称:插入排序 
	语言:数据结构C语言版 
	编译环境:VC++ 6.0
	日期: 2014-3-26 
*/
#include <stdio.h>
#include <malloc.h>
#include <windows.h>


typedef int KeyType;	// 定义关键字类型为整型
typedef int InfoType;	// 定义其它数据项的类型

// 记录类型
typedef struct
{
	KeyType key;		// 关键字项
	InfoType otherinfo;	// 其它数据项
}RedType;

#define MAXSIZE 20	// 一个用作示例的小顺序表的最大长度

// 顺序表类型
typedef struct
{
	RedType r[MAXSIZE+1];	// r[0]闲置或用作哨兵单元
	int length;				// 顺序表长度
}SqList;


// 打印顺序表 
void print(SqList L)
{
	int i;
	
	for(i = 1; i <= L.length; i++)
		printf("(%d, %d) ", L.r[i].key, L.r[i].otherinfo);
	
	printf("\n\n");
}

/*	
	对顺序表L作直接插入排序。
*/
void InsertSort(SqList *L)
{
	int i, j;
	
	// 升序排序 
	for( i = 2; i <= (*L).length; ++i)
		if((*L).r[i].key < (*L).r[i-1].key)
		{
			(*L).r[0] = (*L).r[i]; // 复制为哨兵
			
			for(j = i-1; (*L).r[0].key < (*L).r[j].key; --j)
				(*L).r[j+1]=(*L).r[j];	// 记录后移
			
			(*L).r[j+1] = (*L).r[0];	// 插入到正确位置
			
			print(*L);	// 打印线性表 
		}
}

/*
	对顺序表L作折半插入排序。 
*/
void BInsertSort(SqList *L)
{
	int i,j,m,low,high;
	
	for(i = 2; i <= (*L).length; ++i)
	{
		(*L).r[0] = (*L).r[i]; // 将L.r[i]暂存到L.r[0]
		low = 1;
		high = i-1;
		
		// 在r[low..high]中折半查找有序插入的位置
		while(low <= high)
		{
			m = (low + high) / 2;	// 折半
			if((*L).r[0].key < (*L).r[m].key)
				high = m-1;	// 小于插入点在低半区
			else
				low = m + 1; 	// 其他插入点在高半区
		
		}
		for(j = i-1;j >= high+1; --j)
			(*L).r[j+1] = (*L).r[j];	// 记录后移
		
		(*L).r[high+1] = (*L).r[0];		// 插入
		
		print(*L); 
	}
}

void P2_InsertSort(SqList *L)
{
	int i,j,first,final;
	RedType *d;

	// 生成L.length个记录的临时空间
	d = (RedType*)malloc((*L).length*sizeof(RedType));

	// 设L的第1个记录为d中排好序的记录(在位置[0])
	d[0] = (*L).r[1];

	// first、final分别指示d中排好序的记录的第1个和最后1个记录的位置
	first = final = 0;

	for(i = 2; i <= (*L).length; ++i)
	{
		// 依次将L的第2个~最后1个记录插入d中 
		if((*L).r[i].key < d[first].key)
		{
			/* 
				待插记录小于d中最小值,插到d[first]之前(不需移动d数
				组的元素)
			*/
			first = (first - 1 + (*L).length) % (*L).length;
			// 设d为循环向量
			d[first] = (*L).r[i];
		}
		else if((*L).r[i].key > d[final].key)
		{
			/*
				待插记录大于d中最大值,插到d[final]之后(不需移动d数
				组的元素) 
			*/
			final=final+1;
			d[final]=(*L).r[i];
		}
		else
		{
			/*
				待插记录大于d中最小值,小于d中最大值,插到d的中
				间(需要移动d数组的元素) 
			*/
			j = final++;	// 移动d的尾部元素以便按序插入记录
			while((*L).r[i].key < d[j].key)
			{
				d[(j+1)%(*L).length] = d[j];
				j = (j-1+(*L).length) % (*L).length;
			}
			d[j+1] = (*L).r[i];
		}
	}
	// 把d赋给L.r, 线性关系
	for(i = 1;i <= (*L).length; i++)
		(*L).r[i] = d[(i+first-1)%(*L).length];
}

// 对顺序表L作一趟希尔插入排序。本算法是和一趟直接插入排序相比, 
// 作了以下修改: 
// 1.前后记录位置的增量是dk,而不是1; 
// 2.r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到。 
void ShellInsert(SqList *L,int 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]; // 插入 
			}
}

// 按增量序列dlta[0..t-1]对顺序表L作希尔排序。
void ShellSort(SqList *L,int dlta[],int t)
{
	int k;
	for(k=0;k<t;++k)
	{
		ShellInsert(L,dlta[k]); // 一趟增量为dlta[k]的插入排序 
		printf("第%d趟排序结果: ",k+1);
		print(*L);
	}
}



#define N 8
#define T 3

int main()
{
	RedType d[N] = {
		{ 49, 1}, { 38, 2}, { 65, 3}, { 97, 4},
		{ 76, 5}, { 13, 6}, { 27, 7}, { 49, 8}
	};
	SqList L;
	int i;
	int dt[T] = { 5, 3, 1}; // 增量序列数组

	// 给L.r赋值
	for(i = 0; i < N; i++)
		L.r[i+1]=d[i];
	L.length = N;

	printf("排序前:\n");
	print(L);


/*************测试直接插入排序*******************/
#if 0
	printf("\n直接插入排序的过程\n");
	InsertSort(&L);
	
	printf("\n直接插入排序后:\n");
	print(L);
#endif


/*************测试折半插入排序*******************/
#if 0
	printf("\n折半插入排序的过程\n");
	BInsertSort(&L);
	
	printf("\n折半插入排序后:\n");
	print(L);
#endif

/*************测试2路插入排序*******************/
#if 0
	P2_InsertSort(&L);

	printf("\n2路插入排序后:\n");
	print(L);
#endif

/*************测试希尔排序*******************/
#if 0
	ShellSort(&L,dt,T);

	printf("\n希尔排序后:\n");
	print(L);
#endif

	system("pause");
	return 0;
}


/*
输出效果:

*************测试直接插入排序*******************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)


直接插入排序的过程
(38, 2) (49, 1) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

(38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (13, 6) (27, 7) (49, 8)

(13, 6) (38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (27, 7) (49, 8)

(13, 6) (27, 7) (38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (49, 8)

(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)


直接插入排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*************测试折半插入排序*******************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)


折半插入排序的过程
(38, 2) (49, 1) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

(38, 2) (49, 1) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

(38, 2) (49, 1) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

(38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (13, 6) (27, 7) (49, 8)

(13, 6) (38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (27, 7) (49, 8)

(13, 6) (27, 7) (38, 2) (49, 1) (65, 3) (76, 5) (97, 4) (49, 8)

(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)


折半插入排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*************测试2路插入排序*******************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)


2路插入排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*************测试希尔排序*******************


排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

第1趟排序结果: (13, 6) (27, 7) (49, 8) (97, 4) (76, 5) (49, 1) (38, 2) (65, 3)

第2趟排序结果: (13, 6) (27, 7) (49, 8) (38, 2) (65, 3) (49, 1) (97, 4) (76, 5)

第3趟排序结果: (13, 6) (27, 7) (38, 2) (49, 8) (49, 1) (65, 3) (76, 5) (97, 4)


希尔排序后:
(13, 6) (27, 7) (38, 2) (49, 8) (49, 1) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*/


  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页

打赏

徐刘根

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值