数据结构第四次实验-常用的内部排序算法

这篇具有很好参考价值的文章主要介绍了数据结构第四次实验-常用的内部排序算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验目的

1.掌握常见的内部排序算法的思想及其适用条件;
2.掌握常见的内部排序算法的程序实现;

二、实验内容及要求

1、任务描述
设计一个内部排序算法模拟系统,利用该系统实现常用的 7 种排序算法,并测试
各种排序算法的性能。
实验内容:通过一个简单的菜单,分别实现下列排序要求,采用几组不同数据测试各排
序算法的性能(比较次数和移动次数)及稳定性。
◆ 实现简单选择排序、直接插入排序和冒泡排序;
◆ 实现折半插入排序;
◆ 实现希尔排序算法;
◆ 实现快速排序算法(递归和非递归);
◆ 实现堆排序算法
输入和输出:
(1)输入形式:根据菜单提示选择排序算法,输入一组带排序数据。
(2)输出形式:输出排序结果(体现排序过程),及排序过程中数据的比较次数和移动次数,判断排序算法的稳定性。
实验要求:
实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。
◆ 要输出每一趟排序的结果。
◆ 能够上机编辑、调试出完整的程序。
2、主要数据类型与变量

typedef struct
{
	int r[MAXSIZE + 1];	/* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
	int length;			/* 用于记录顺序表的长度 */
}SqList;
#define MAXSIZE 10000  /* 用于要排序数组个数最大值,可根据需要修改 */

3、算法或程序模块

1. void SelectSort(SqList* L)

通过n-1次关键词间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录进行交换。

2.void InsertSort(SqList* L)

将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数增1的有序表。

3.void BubbleSort(SqList* L)

两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

4.void BinarySort(SqList* L)

不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,因此不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。

5. void ShellSort(SqList* L)

将相距某个增量的记录组成一个子序列,保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。

6. void QSort(SqList* L, int low, int high)

通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到对整个序列有序的目的。

7. void QSort(SqList* L, int low, int high)

将待排序的序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根结点。将它移走,然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。

三、测试

1、方案
数据结构第四次实验-常用的内部排序算法

2.结果
数据结构第四次实验-常用的内部排序算法

1选择排序:
数据结构第四次实验-常用的内部排序算法

2.直接插入排序:
数据结构第四次实验-常用的内部排序算法

3.冒泡排序:
数据结构第四次实验-常用的内部排序算法

4.折半插入排序:
数据结构第四次实验-常用的内部排序算法

5.希尔排序:
数据结构第四次实验-常用的内部排序算法

6.快速排序:
数据结构第四次实验-常用的内部排序算法

7.堆排序:
数据结构第四次实验-常用的内部排序算法

测试结果都正确,程序设计无误。

四、总结与讨论

此实验主要应用于对六种内部排序算法移动和比较次数的比较。通过对冒泡排序、直接插入插排序、简单选择排序、折半插入排序、快速排序、希尔排序、堆排序这几种内部排序算法进行比较,加深了我对这些排序的基本思想及排序算法的掌握和理解。同时通过该题目的设计过程,我也加深理解各种数据结构的逻辑结构、存储结构及相应上运算的实现,进一步理解和熟练掌握课本中所学的各种数据结构,进一步提升了自身的动手能力。
在之前的编程应用中我经常用的是选择法排序,第一个for循环用来控制选择的轮数,第二个for循环用来不断地选择最小或最大的值来放入指定的位置,实现也很方便。同时也掌握了冒泡法排序的思想和具体的代码实现过程,因为平常编写的程序排序的数据都比较少,因此也不太能明显地感受到时间复杂度的不同对于程序的影响,但经过本章排序算法的学习后,我了解到虽然冒泡法排序和选择法排序的时间复杂度都是O(n²),但是选择法排序的性能要稍微优于冒泡法排序。
同时我也了解了三种时间复杂度更为优越的算法,分别是希尔排序、堆排序和快速排序,它们都将时间复杂度提升到了O(nlogn),对于前两个我大致了解了其排序的思路,认识到希尔排序相当于直接插入排序的升级,堆排序相当于简单选择排序的升级,但对于快速排序我了解到它被列为20世纪十大算法之一,因此我仔细熟悉了其算法的具体实现过程,尤其是利用Partition函数去获得枢轴所在的位置的思想确实让我收获很大,感受到了这种算法的便利。因此今后在面对较多数据的排序时,我会再进一步熟悉并利用这种排序算法,以实现程序更加高效的执行。

附:程序的源代码文章来源地址https://www.toymoban.com/news/detail-469763.html

#include <stdio.h>    
#include <string.h> 
#include <stdlib.h>   

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAX_LENGTH_INSERT_SORT 7 /* 用于快速排序时判断是否选用插入排序阙值 */

typedef int Status;


#define MAXSIZE 10000  /* 用于要排序数组个数最大值,可根据需要修改 */
typedef struct
{
	int r[MAXSIZE + 1];	/* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
	int length;			/* 用于记录顺序表的长度 */
}SqList;

/* 交换L中数组r的下标为i和j的值 */
void swap(SqList* L, int i, int j)
{
	int temp = L->r[i];
	L->r[i] = L->r[j];
	L->r[j] = temp;
}

void print(SqList L)
{
	int i;
	for (i = 1; i < L.length; i++)
		printf("%d,", L.r[i]);
	printf("%d", L.r[i]);
	printf("\n");
}



/* 对顺序表L作冒泡排序 */
void BubbleSort(SqList* L)
{
	int i, j,k=0;
	for (i = 1; i < L->length; i++)
	{
		for (j = L->length - 1; j >= i; j--)  /* 注意j是从后往前循环 */
		{
			if (L->r[j] > L->r[j + 1]) /* 若前者大于后者(注意这里与上一算法的差异)*/
			{
				swap(L, j, j + 1);/* 交换L->r[j]与L->r[j+1]的值 */
				printf("	第%d趟排序结果: ", ++k);
				print(*L);
			}
		}
	}
}


/* 对顺序表L作简单选择排序 */
void SelectSort(SqList* L)
{
	int i, j,k=0;
	for (i = 1; i < L->length; i++)
	{	
		for (j = i + 1; j <= L->length; j++)/* 循环之后的数据 */
		{
			if (L->r[i] > L->r[j])
			{
				swap(L, i, j);/* 交换L->r[i]与L->r[j]的值 */
				printf("	第%d趟排序结果: ", ++k);
				print(*L);
			}					
		}
					              							
	}
}

/* 对顺序表L作直接插入排序 */
void InsertSort(SqList* L)
{
	int i, j,k=0;
	for (i = 2; i <= L->length; i++)
	{
		if (L->r[i] < L->r[i - 1]) /* 需将L->r[i]插入有序子表 */
		{
			L->r[0] = L->r[i]; /* 设置哨兵 */
			for (j = i - 1; L->r[j] > L->r[0]; j--)
				L->r[j + 1] = L->r[j]; /* 记录后移 */
			L->r[j + 1] = L->r[0]; /* 插入到正确位置 */
			printf("	第%d趟排序结果: ", ++k);
			print(*L);
		}
	}
}
//折半插入排序
void BinarySort(SqList* L)
{
	int i, j, low = 0, high = 0, mid,k=0;
	int temp = 0;
	for (i = 2; i < L->length+1; i++) {
		low = 1;
		high = i-1;
		temp = L->r[i];
		//采用折半查找法判断插入位置,最终变量 low 表示插入位置
		while (low <= high) {
			mid = (low + high) / 2;
			if (L->r[mid] > temp) {
				high = mid - 1;
			}
			else {
				low = mid + 1;
			}
		}
		//有序表中插入位置后的元素统一后移
		for (j = i; j > low; j--) {
			L->r[j] = L->r[j - 1];
			printf("	第%d趟排序结果: ", ++k);
			print(*L);
		}
		L->r[low] = temp;//插入元素

	}
}

/* 对顺序表L作希尔排序 */
void ShellSort(SqList* L)
{
	int i, j, k = 0;
	int increment = L->length;
	do
	{
		increment = increment / 3 + 1;/* 增量序列 */
		for (i = increment + 1; i <= L->length; i++)
		{
			if (L->r[i] < L->r[i - increment])/*  需将L->r[i]插入有序增量子表 */
			{
				L->r[0] = L->r[i]; /*  暂存在L->r[0] */
				for (j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment)
					L->r[j + increment] = L->r[j]; /*  记录后移,查找插入位置 */
				L->r[j + increment] = L->r[0]; /*  插入 */
			}
		}
		printf("	第%d趟排序结果: ", ++k);
		print(*L);
	} while (increment > 1);

}


/* 堆排序********************************** */

/* 已知L->r[s..m]中记录的关键字除L->r[s]之外均满足堆的定义, */
/* 本函数调整L->r[s]的关键字,使L->r[s..m]成为一个大顶堆 */
void HeapAdjust(SqList* L, int s, int m)
{
	int temp, j;
	temp = L->r[s];
	for (j = 2 * s; j <= m; j *= 2) /* 沿关键字较大的孩子结点向下筛选 */
	{
		if (j < m&& L->r[j] < L->r[j + 1])
			++j; /* j为关键字中较大的记录的下标 */
		if (temp >= L->r[j])
			break; /* rc应插入在位置s上 */
		L->r[s] = L->r[j];
		s = j;
	}
	L->r[s] = temp; /* 插入 */
}

/*  对顺序表L进行堆排序 */
void HeapSort(SqList* L)
{
	int i,k=0;
	for (i = L->length / 2; i > 0; i--) /*  把L中的r构建成一个大顶堆 */
		HeapAdjust(L, i, L->length);

	for (i = L->length; i > 1; i--)
	{
		swap(L, 1, i); /* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */
		HeapAdjust(L, 1, i - 1); /*  将L->r[1..i-1]重新调整为大顶堆 */
		printf("	第%d趟排序结果: ", ++k);
		print(*L);
	}
}



/* 快速排序******************************** */

/* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */
/* 此时在它之前(后)的记录均不大(小)于它。 */
int Partition(SqList* L, int low, int high)
{
	int pivotkey;

	pivotkey = L->r[low]; /* 用子表的第一个记录作枢轴记录 */
	while (low < high) /*  从表的两端交替地向中间扫描 */
	{
		while (low < high && L->r[high] >= pivotkey)
			high--;
		swap(L, low, high);/* 将比枢轴记录小的记录交换到低端 */
		while (low < high && L->r[low] <= pivotkey)
			low++;
		swap(L, low, high);/* 将比枢轴记录大的记录交换到高端 */
	}
	return low; /* 返回枢轴所在位置 */
}

/* 对顺序表L中的子序列L->r[low..high]作快速排序 */
int t = 0;
void QSort(SqList* L, int low, int high)
{
	int pivot;
	if (low < high)
	{
		pivot = Partition(L, low, high); /*  将L->r[low..high]一分为二,算出枢轴值pivot */
		QSort(L, low, pivot - 1);		/*  对低子表递归排序 */
		QSort(L, pivot + 1, high);		/*  对高子表递归排序 */
	}
	printf("	第%d趟排序结果: ", ++t);
	print(*L);
}

/* 对顺序表L作快速排序 */
void QuickSort(SqList* L)
{
	QSort(L, 1, L->length);
	t = 0;
}

/* **************************************** */
#define N 9
int main()
{
	int i, n;

	//int d[N] = { 50,10,90,30,70,40,80,60,20 };
	int d[MAXSIZE];
	printf("请输入待排序元素的个数:\n");
	scanf("%d", &n);
	printf("请依次输入元素:\n");

	SqList sq1,sq2,sq3,sq4,sq5,sq6,sq7,sq8;

	for (i = 0; i < n; i++)
	{
		scanf("%d", &sq1.r[i + 1]);
	}
	sq1.length = n;
	sq2=sq3=sq4=sq5=sq6=sq7=sq8 = sq1;
	printf("排序前:\n");
	print(sq1);
	while (1)
	{
		int flag;
		printf("---------------操作命令集---------------\n");
		printf("****************************************\n");
		printf("*            1.选择排序                *\n");
		printf("*            2.直接插入排序            *\n");
		printf("*            3.冒泡排序                *\n");
		printf("*            4.折半插入排序            *\n");
		printf("*            5.希尔排序                *\n");
		printf("*            6.快速排序                *\n");
		printf("*            7.堆排序                  *\n");
		printf("*            0.Return                  *\n");
		printf("****************************************\n");
		scanf("%d", &flag);
		switch (flag)
		{
		case 1:
			printf("选择排序:\n");
			SelectSort(&sq2);
			print(sq2);
			break;
		case 2:
			printf("直接插入排序:\n");
			InsertSort(&sq3);
			print(sq3);
			break;
		case 3:
			printf("冒泡排序:\n");
			BubbleSort(&sq4);
			print(sq4);
			break;
		case 4:
			printf("折半插入排序:\n");
			BinarySort(&sq5);
			print(sq5);
			break;
		case 5:
			printf("希尔排序:\n");
			ShellSort(&sq6);
			print(sq6);
			break;
		case 6:
			printf("快速排序:\n");
			QuickSort(&sq7);
			print(sq7);
			break;
		case 7:
			printf("堆排序:\n");
			HeapSort(&sq8);
			print(sq8);
			break;
		default:
			break;
		}
	}
	return 0;
}

到了这里,关于数据结构第四次实验-常用的内部排序算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis内部数据结构Dict结构详解

    dict的数据结构定义 dict的创建(dictCreate) dict的查找(dictFind) dict的插入(dictAdd和dictReplace) dict的删除(dictDelete) 如果你使用过Redis,一定会像我一样对它的内部实现产生兴趣。《Redis内部数据结构详解》是我准备写的一个系列,也是我个人对于之前研究Redis的一个阶段性

    2024年01月21日
    浏览(38)
  • 数据结构之内部排序

    目录 7-1 直接插入排序 输入格式: 输出格式: 输入样例: 输出样例: 7-2 寻找大富翁 输入格式: 输出格式: 输入样例: 输出样例: 7-3 PAT排名汇总 输入格式: 输出格式: 输入样例: 输出样例: 7-4 点赞狂魔 输入格式: 输出格式: 输入样例: 输出样例: 7-5 链式基数排序 输入样例: 输出

    2024年02月04日
    浏览(55)
  • 408数据结构第四章

    小题形式考,比较简单,拿两个题来练手就会了 字符串简称串 由零个或多个字符组成的有限序列 S是串名n称为串的长度,n=0称为空串 串中多个连续的字符组成的子序列称为该串的子串 串的逻辑结构和线性表极为相似,区别仅在于串的数据结构对象限定为字符集 线性表的基

    2024年02月11日
    浏览(34)
  • 数据结构 第四章:串

    所谓串其实就是字符串,该小节我们会先学习串的定义和相关基本操作。也就是要探讨它的逻辑结构和基本运算(数据结构三要素:逻辑结构、存储结构、数据的运算) 1.1.1串的定义 串 ,即字符串(String)是由零个或多个 字符 组成的有序序列。 一般记为S=‘a1a2…an’(n=0)

    2024年02月06日
    浏览(40)
  • 数据结构 第四章 栈

    🚀 写在最前 :这篇文章将学习栈这种结构,以及该结构的一些基本操作的实现,包括顺序存储栈和链式存储栈的基本操作的实现。 🚀:点求个关注,让我们一起探索计算机的奥秘! 所谓的 栈就是一种特殊的线性表 ,对于栈这种逻辑结构来说他和线性表最大的区别就是 栈

    2024年04月15日
    浏览(40)
  • Redis 的数据结构和内部编码

    Redis 底层在实现上述数据结构的时候,会在源码层面,针对上述实现进行 特定的优化 ,来达到节省时间/节省空间效果 特定的优化 :内部的具体实现的数据结构,在特定场景下,不是其对应的标准数据结构,而是使用别的数据结构实现,不过仍然保证时间复杂度符合要求 编

    2024年04月25日
    浏览(28)
  • 数据结构复盘——第四章:数组和矩阵

    矩阵在线性代数中已经有过详细了解,在考研中矩阵部分常常考察 数组下标 k 与 矩阵行 i 和列 j 的关系。 需要注意的是矩阵下标 i、j 通常是: 1 到 n 1到n 1 到 n ,而数组下标 k 通常是: 0 到 n 2 − 1 0到n^2-1 0 到 n 2 − 1 。 k 与 i、j 的关系就是: k = n ∗ ( i − 1 ) + j − 1 k=n*

    2024年02月07日
    浏览(39)
  • 【数据结构初阶】第四节.链表详讲

    前言 一、单链表的概念 二、链表的创建 2.1链表的初始化 2.2 打印链表 2.3 获取链表的长度 2.4 判断链表是否为空 三、新增结点 3.1头插 3.2 指定下标插入 四、删除结点 4.1 头删 4.2 指定下标的删除 4.3 删除链表中的指定元素 五、单链表查找 六、附录 总代码 测试代码 总结 前

    2023年04月15日
    浏览(69)
  • 数据结构与算法·第10章【内部排序】

    排序问题可以分为内部排序和外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。 在内部排序中,若对于两个相等的元素 K i 和

    2024年02月09日
    浏览(41)
  • 数据结构基础内容-----第四章 栈与队列

    栈(Stack)是计算机科学中的一种抽象数据类型,它是一个只能在一端进行插入和删除操作的线性数据结构。栈按照后进先出(LIFO)的原则存储数据,即最后放入的元素最先被取出。类比物理世界中的堆叠物品,每次加入的物品都被放在上面,取出时也只能从上面取出,最后

    2024年02月07日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包