数据结构 基本排序(选择 插入 冒泡)

在很多情况下,有序表比无序表的效率要高得多。对于排序,不仅是对于普通的数字编号进行排序,对于抽象的文章,图片,视频等等信息都可进行排序。(这里的排序不是说给它们编号在对编号排序,而是真正对其所包含的关键字排序,这种规律是可以联系到其本身的含义的!)由于编者水平有限,以下介绍的均为对数据的排序。

对于一个表想让其转化成有序表,则需要表中每个数据项都有可以相互比较的元素。为此引入关键字,通过关键字的比较排列,使整个表呈非递增和非递减的规律;这种加了关键字的数据元素被定义为“记录”。

typedef int KeyType;         //为简单起见,定义关键字类型为整型
typedef struct {
	KeyType key;             //关键字项
	InfoType otherinfo;      //其他数据项
}RcdType;                    //记录类型

此为定义记录时的内容

排序根据过程中涉及的存储器不同可分为 (1),内部排序:排序过程不使用计算机外部存储器.(2),外部排序:排序过程中需要调用外存。

const MAXSIZE = 20;             //一个用作示例的小顺序表的最大长度
typedef struct {
	RcdType r[MAXSIZE + 1];     //r[0]闲置或作为判别标志的“哨兵”单元
	int length;                 //顺序表排序的记录空间为r[1..length]
}SqList;                        //顺序表类型

此为顺序表,其中的每个元素都是RcdType定义的记录

选择排序

对于选择排序,思想很简单,关键是如何建立一个存储数据为记录的顺序表。步骤如下:一,对于记录和顺序表进行定义,(定义顺序表存储数组时还是先定义指向记录的指针。)二,建表,即为顺序表分配内存空间,同时初始化表长为零。三,对于表中数据的赋值,可以在主函数中进行,赋值时千万不要忘记增加表长。最后对其进行排序就完成了。

同时需要注意的一点是,顺序表中 L.r[0] 作为哨兵单元,不存储数据,所以在排序循环中要注意循环变量的起始值和范围的确定。

#include<stdio.h>

/******************************************************************************
							 对记录这个数据类型的定义
******************************************************************************/
typedef int KeyType;
typedef struct {
	KeyType key;
	char data;
}RcdType;

/*******************************************************************************
					  对每一个元素都是记录的顺序表的定义
********************************************************************************/
const int MAXSIZE = 10;
typedef struct {
	RcdType *r;     //r[0]是哨兵单元,不记录数值    r[i]表示记录
	int length;             //表示顺序表的实时长度
}SqList;

/*********************************************************************************
                                      建表
**********************************************************************************/
void InitList_L(SqList &L)
{                                     //定义过数据类型后引用时要先给它分配内存空间
	L.r = new RcdType[MAXSIZE + 1];      
	L.length = 0;                     //初始化表长为0
}
/********************************************************************************
								 排序
*********************************************************************************/
void SelectSort(SqList &L)
{
	//对顺序表L进行选择排序
	int i, j, k; 
	RcdType w; //用于交换的辅助变量
	for (i = 1; i < L.length; i++)
	{
		j = i;
		for (k = i + 1; k <= L.length; k++)
			if (L.r[k].key < L.r[j].key)
				j = k;
		if (i != j)
		{
			w = L.r[j];
			L.r[j] = L.r[i];
			L.r[i] = w;
		}
	}
}

void main()
{
	int i;
	SqList L;
	InitList_L(L);
	char a[MAXSIZE] = { 'Y','L','V','X','O','L','!','I','U','E' };
	int key[MAXSIZE] = { 3,5,7,2,6,1,10,4,9,8 };
	for (i = 1; i <= MAXSIZE; i++)
	{
		L.r[i].data = a[i - 1];
		L.r[i].key = key[i - 1];
		L.length++;                 //千万不要忘记每输入一个记录,表长要加一
	}
	printf("排序前顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
	{
		printf("%c ", L.r[i].data);
	}
	printf("\n");
	SelectSort(L);
	printf("排序后顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
		printf("%c ", L.r[i].data);

}

插入排序

插入排序的思路就是,定义循环变量 i 和 j ,最初让 i 从第二个数据开始,与前一个数据进行比较,如果 i 较小,则将 i 放到哨兵单元待定。然后令 j 从 i 前面一个数据开始,循环将前面的数据后移,然后 j 减一,后移循环的条件是哨兵单元处的数据小于 j 此时的数据。当跳出此循环时说明哨兵单元的数据比 j 此时所指的数据和前面的数据都大,是时候将哨兵单元的数据插回到表中。由于判断循环条件前 j 减了一,所以将哨兵单元数据插回到 j 的后一位,即 L.r[j + 1] = L.r[0]; 此处 j + 1 就很细节。

#include<stdio.h>

/******************************************************************************
							 对记录这个数据类型的定义
******************************************************************************/
typedef int KeyType;
typedef struct {
	KeyType key;
	char data;
}RcdType;

/*******************************************************************************
					  对每一个元素都是记录的顺序表的定义
********************************************************************************/
const int MAXSIZE = 10;
typedef struct {
	RcdType *r;     //r[0]是哨兵单元,不记录数值    r[i]表示记录
	int length;             //表示顺序表的实时长度
}SqList;

/*********************************************************************************
                                      建表
**********************************************************************************/
void InitList_L(SqList &L)
{                                     //定义过数据类型后引用时要先给它分配内存空间
	L.r = new RcdType[MAXSIZE + 1];      
	L.length = 0;                     //初始化表长为0
}
/********************************************************************************
								 排序
*********************************************************************************/
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];     //将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];       
		}
}

void main()
{
	int i;
	SqList L;
	InitList_L(L);
	char a[MAXSIZE] = { 'Y','L','V','X','O','L','!','I','U','E' };
	int key[MAXSIZE] = { 3,5,7,2,6,1,10,4,9,8 };
	for (i = 1; i <= MAXSIZE; i++)
	{
		L.r[i].data = a[i - 1];
		L.r[i].key = key[i - 1];
		L.length++;                 //千万不要忘记每输入一个记录,表长要加一
	}
	printf("排序前顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
	{
		printf("%c ", L.r[i].data);
	}
	printf("\n");
	InsertSort(L);
	printf("排序后顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
		printf("%c ", L.r[i].data);

}

冒泡排序

冒泡排序即相邻的两个数据进行比较,较大的那个数排在两者中的后者,然后下标加一继续排列,这样一趟下来,整个序列中最大的数就会被交换到最后的位置,该过程小的数向前移动,抽象为冒泡。为了提高算法的效率,设置lastExchangeIndex记录最后一次交换发生时的下标,此时该下标的后续数据不经历交换意味着已经排序完成。

#include<stdio.h>

/******************************************************************************
							 对记录这个数据类型的定义
******************************************************************************/
typedef int KeyType;
typedef struct {
	KeyType key;
	char data;
}RcdType;

/*******************************************************************************
					  对每一个元素都是记录的顺序表的定义
********************************************************************************/
const int MAXSIZE = 10;
typedef struct {
	RcdType *r;     //r[0]是哨兵单元,不记录数值    r[i]表示记录
	int length;             //表示顺序表的实时长度
}SqList;

/*********************************************************************************
                                      建表
**********************************************************************************/
void InitList_L(SqList &L)
{                                     //定义过数据类型后引用时要先给它分配内存空间
	L.r = new RcdType[MAXSIZE + 1];      
	L.length = 0;                     //初始化表长为0
}
/********************************************************************************
								 排序
*********************************************************************************/
void BubbleSort(SqList &L)
{
	//对顺序表L作起泡排序
	RcdType W;
	int i, j;
	int lastExchangeIndex;     //用于记录相邻两个数据比较大小时最后一次交换位置时的下标
	i = L.length;
	while (i > 1)          //i>1 表明上一趟曾进行过记录的交换
	{
		lastExchangeIndex = 1;
		for (j = 1; j < i; j++)
		{
			if (L.r[j + 1].key < L.r[j].key)
			{
				W = L.r[j];
				L.r[j] = L.r[j + 1];
				L.r[j + 1] = W;
				lastExchangeIndex = j;
			}
		}
		i = lastExchangeIndex;    //一趟排列中无序序列中最后一个记录的位置
	}
}

void main()
{
	int i;
	SqList L;
	InitList_L(L);
	char a[MAXSIZE] = { 'Y','L','V','X','O','L','!','I','U','E' };
	int key[MAXSIZE] = { 3,5,7,2,6,1,10,4,9,8 };
	for (i = 1; i <= MAXSIZE; i++)
	{
		L.r[i].data = a[i - 1];
		L.r[i].key = key[i - 1];
		L.length++;                 //千万不要忘记每输入一个记录,表长要加一
	}
	printf("排序前顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
	{
		printf("%c ", L.r[i].data);
	}
	printf("\n");
	BubbleSort(L);
	printf("排序后顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
		printf("%c ", L.r[i].data);

}

但是形象地来说,本算法应该叫下沉排序,因为每一趟最大的数都落在了最后,若要变成真正的冒泡排序,应该从序列的末尾数据进行比较。此时 j 由末尾数据开始向上遍历,初始 j = L.length; 然后初始 lastExchangeIndex = L.length; 而 i 初始值为 1,当 while(i < L.length) 时进入大循环。其中 i 用于记录由下向上排列时上方有序序列的最大末尾下标 当i的值为L.length时,表示已经排列好整个序列。

#include<stdio.h>

/******************************************************************************
							 对记录这个数据类型的定义
******************************************************************************/
typedef int KeyType;
typedef struct {
	KeyType key;
	char data;
}RcdType;

/*******************************************************************************
					  对每一个元素都是记录的顺序表的定义
********************************************************************************/
const int MAXSIZE = 10;
typedef struct {
	RcdType *r;     //r[0]是哨兵单元,不记录数值    r[i]表示记录
	int length;             //表示顺序表的实时长度
}SqList;

/*********************************************************************************
                                      建表
**********************************************************************************/
void InitList_L(SqList &L)
{                                     //定义过数据类型后引用时要先给它分配内存空间
	L.r = new RcdType[MAXSIZE + 1];      
	L.length = 0;                     //初始化表长为0
}
/********************************************************************************
								 排序
*********************************************************************************/
void BubbleSort(SqList &L)
{
	//对顺序表L作起泡排序
	RcdType W;
	int i, j;
	int lastExchangeIndex;     //用于记录相邻两个数据比较大小时最后一次交换位置时的下标
	i = 1;
	while (i < L.length)     //i用于记录由下向上排列时上方有序序列的最大末尾下标 当i的值为L.length时,表示已经排列好整个序列
	{
		lastExchangeIndex = L.length;
		for (j = L.length; j > i; j--)
		{
			if (L.r[j].key < L.r[j-1].key)
			{
				W = L.r[j];
				L.r[j] = L.r[j-1];
				L.r[j-1] = W;
				lastExchangeIndex = j;
			}
		}
		i = lastExchangeIndex;    //i用于记录由下向上排列时上方有序序列的最大末尾下标
	}
}

void main()
{
	int i;
	SqList L;
	InitList_L(L);
	char a[MAXSIZE] = { 'Y','L','V','X','O','L','!','I','U','E' };
	int key[MAXSIZE] = { 3,5,7,2,6,1,10,4,9,8 };
	for (i = 1; i <= MAXSIZE; i++)
	{
		L.r[i].data = a[i - 1];
		L.r[i].key = key[i - 1];
		L.length++;                 //千万不要忘记每输入一个记录,表长要加一
	}
	printf("排序前顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
	{
		printf("%c ", L.r[i].data);
	}
	printf("\n");
	BubbleSort(L);
	printf("排序后顺序表中数据为:");
	for (i = 1; i <= MAXSIZE; i++)
		printf("%c ", L.r[i].data);

}

本笔记所依据的教材为严薇敏版的《数据结构及应用算法教程》

所有代码在Visual Studio 2017上均可正常运行

如有错误欢迎指出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值