数据结构实训项目---比较一些排序

文章背景

我以前一直以为各种排序都差不多,只要越快写出来越好,浪费时间在这上面干嘛,直到我写了才发现这些排序各有千秋,如图:

当数据规模为100

当数据规模为20000时

当数据规模为20w时(再多就不测试了,我的int类型的数据装不下比较次数了,复述的比较次数就是超出范围了,而且等待时间太久了)

程序崩了,我就不放了,运行时间太久了

在进行排序之间需要准备一些处理

1,我采用宏定义的方法定义需要排序的一维数组的大小

#define MAX_SIZE 200000 //进行排序的规模
#define MAX_TRAVEL 100 //在需要遍历数组的个数超过这个时,则不会遍历

每次要修改规模时,都需要去修改,很麻烦,但是我知道聪明的你肯定会知道使用变量来解决这个问题

2,需要用到的头文件

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

3,这是产生随机数的方法

int* createRandomIntList() {
	int* intList = (int*)malloc(sizeof(int)*MAX_SIZE); // 开辟空间
	printf("产生的随机数如下:\n");
	for (int i = 0; i < MAX_SIZE; i++) {
		intList[i] = rand() % 100; // 产生[0-100)的随机数
	}
	travelList(intList);
	return intList;
}

4,遍历数组

void travelList(int* list) {
	if (MAX_SIZE > MAX_TRAVEL) {
		printf("随机数组的大小超过了最大遍历数,则不会遍历输出!\n");
		return;
	}
	printf("==============开始遍历=================\n");
	for (int i = 0; i < MAX_SIZE; i++) {
		if (!(i % 5)) {
			printf("\n");
		}
		printf("%d\t", list[i]);
	}
	printf("\n==============遍历结束=================\n");
}

5,需要比较各个算法的各种属性,如运算时间,移动次数等,用一个结构体来对这些属性进行抽象,方便书写和阅读代码

typedef struct Tool{
	char name[20] = ""; // 记录算法名字
	int compareTime = 0; // 记录比较次数
	int moveTime = 0; //记录移动次数
	long begainTime = 0; // 记录开始时间
	long endTime = 0;// 记录结束时间
};

6,格式化输出这些信息的函数

void printTool(Tool tool) {
	printf("=====================%s============================\n",tool.name);
	printf("排序规模(个):%d\n",MAX_SIZE);
	printf("程序运行时间:%ld个时钟周期\n",tool.endTime - tool.begainTime);
	printf("移动次数:%d\n比较次数:%d\n",tool.moveTime,tool.compareTime);
	printf("=================================================\n");
}

一切准备就绪,现在步入正题,在这里我将实现5个算法:

1,直接选择排序:通过n-I次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录交换之。

Tool zhiJie_sort(int* _list) {
	int* list = copyList(_list);
	Tool tool;
	strcpy_s(tool.name, "直接排序");
	tool.begainTime = clock();
	for (int i = 0; i < MAX_SIZE; i++) {
		int min = list[i];
		int k = i;
		for (int j = i + 1; j < MAX_SIZE; j++) {
			tool.compareTime++;
			if (min > list[j]) {
				min = list[j];
				k = j;
			}
		}
		if (k != i) {
			int a = list[i];
			list[i] = list[k];
			list[k] = a;
			tool.moveTime++;
		}
	}
	tool.endTime = clock();
	printf("\n直接排序成功!\n");
	travelList(list);
	printTool(tool);
	return tool;
}

2,冒泡排序:如果有n个数,则要进行n-1趟比较。在第1趟比较中要进行n-1次两两比较,在第j趟比较中要进行n-j次两两比较

Tool qiPao_sort(int* _list) {
	int* list = copyList(_list);
	Tool tool;
	strcpy_s(tool.name, "冒泡排序");
	tool.begainTime = clock();
	for (int i = 0; i < MAX_SIZE; i++) {
		for (int j = 0; j < MAX_SIZE-1-i; j++) {
			tool.compareTime++;
			if (list[j] > list[j + 1]) {
				int a = list[j];
				list[j] = list[j+1];
				list[j+1] = a;
				tool.moveTime++;
			}
		}
	}
	tool.endTime = clock();
	travelList(list);
	printTool(tool);
	return tool;
}

3,希尔排序:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。


void shell_sort(int* list,int begPosition,int endPosition,Tool* tool,int* times) {
	(*times)++;
	int keyValue = list[begPosition]; // 枢轴值
	int key = begPosition; // 记录空位置
	for (int i = begPosition, j = endPosition; i <j&&j!=key; j--) {
		tool->compareTime++;
		if (keyValue>list[j]) { // 从右边开始比较
			list[key] = list[j];// 将右边小于枢值移到左边
			key = j;// 记录空值位置
			tool->moveTime++;
			while (keyValue >= list[i] && i!=key) {//从左边开始比较
				tool->compareTime++;
				i++;
			}
			if (i == key) {
				break;
			}
			list[key] = list[i];			// i 为空位置
			key = i;
			tool->moveTime++;
		}
	}
	list[key] = keyValue;
	if (MAX_TRAVEL > MAX_SIZE) {
		printf("第%d躺移动结果:\n", *times);
		travelList(list);
	}
	tool->moveTime++;
	if (begPosition != key) {
		shell_sort(list, begPosition, key, tool,times);
	}
	if (key + 1 < endPosition) {
		shell_sort(list, key + 1, endPosition, tool,times);
	}
}

4,直接插入排序:将一个记录插入到已排序好的有序表中,从而得到一个新的、记录数增1的有序表。设整个排序有n个数,则进行n-1趟插入,即:先将序列中的第1个记录

Tool insert_sort(int* _list) {
	int* newList = (int*)malloc(sizeof(int)*MAX_SIZE);
	Tool tool;
	strcpy_s(tool.name, "直接插入排序");
	tool.begainTime = clock();
	newList[0] = _list[0];
	for (int i = 1; i < MAX_SIZE; i++) { // i 表示开始插入i个元素
		int insertValue = _list[i]; // 插入的值
		int isInsert = false;
		for (int j = 0; j <i; j++) {// 找到插入位置
			tool.compareTime++;
			if (newList[j] > insertValue) { // 找到插入位置
				for (int k = i; k > j; k--) {
					newList[k] = newList[k - 1];
					tool.moveTime++;
				}
				newList[j] = insertValue;
				isInsert = true;
				break;
			}
		}
		if (!isInsert) {
			newList[i] = insertValue;
		}
	}
	tool.endTime = clock();
	travelList(newList);
	printTool(tool);
	return tool;
}

5,堆排序


void heapAdjust(int* list, int s, int m,Tool* tool)//一次筛选的过程
{
	int min = list[s]; // 假设节点处的值最小
	for (int j = 2 * s; j <= m; j = j * 2)//通过循环沿较大的孩子结点向下筛选
	{
		if (j < m && list[j] < list[j + 1]) {
			j++;//j为较大的记录的下标
			tool->compareTime++;
		} 
		if (min > list[j]) break; // 找到比根大的位置,跳出调整循环,插入节点处
		list[s] = list[j];
		tool->moveTime++;
		s = j;
	}
	list[s] = min;//插入
	tool->moveTime++;
}

/*
des: 堆排序
*/
void heap_sort(int* _list, int n,Tool* tool)
{
	// 将数组里的元素向后移预留出0的位置,方便逻辑实现
	int* list =(int*) malloc(sizeof(int)*(MAX_SIZE+1));
	// 因此排序长度加一
	n += 1;
	// 元素后移
	for (int i = MAX_SIZE; i > 0; i--) {
		list[i] = _list[i - 1];
	}
	for (int i = n / 2; i > 0; i--)//初始化堆
	{
		heapAdjust(list, i, n,tool);
	}
	for (int i = n; i >0; i--)
	{
		int temp = list[1];
		list[1] = list[i];
		list[i] = temp;//将堆顶记录与未排序的最后一个记录交换
		tool->moveTime++;
		heapAdjust(list, 1, i - 1,tool);//重新调整为顶堆
	}
	// 输出排序结果
	if (MAX_SIZE > MAX_TRAVEL) {
		return;
	}
	for (int i = 1; i <= MAX_SIZE; i++) {
		printf("%d\t",list[i]);
		if (!(i % 5)) {
			printf("\n");
		}
	}
}

其他还有很多排序,都各有各的好处

开始测试

#include"App6.h"
bool toolIsEmpty(Tool tool) {
	if (!strcmp(tool.name, "")) {
		return true;
	}
	return false;
}
void copyTool(Tool* newT, Tool* oldT) {
	newT->begainTime = oldT->begainTime;
	newT->compareTime = oldT->compareTime;
	newT->endTime = oldT->endTime;
	newT->moveTime = oldT->moveTime;
	strcpy_s(newT->name,oldT->name);
}

bool addTool(Tool tools[], Tool tool) {
	int i = 0;
	while (!toolIsEmpty(tools[i])) {
		i++;
	}
	copyTool(&tools[i], &tool);
	return true;
}

void travelTools(Tool tools[]) {
	for (int i = 0; !toolIsEmpty(tools[i]); i++) {
		printTool(tools[i]);
	}
}

void sortTools(Tool tools[],int key=1) {
	switch (key) {
	case 1: // 运行时间
		for (int i = 0; !toolIsEmpty(tools[i]); i++) {
			long min = tools[i].endTime - tools[i].begainTime;
			for (int j = i; !toolIsEmpty(tools[j]); j++) {
				long big = tools[j].endTime - tools[j].begainTime;
				if (min > big) {
					Tool tool = tools[i];
					tools[i] = tools[j];
					tools[j] = tool;
				}
			}
		}
	}
	travelTools(tools);
}

void menue() {
	Tool tools[6];
	int* list = createRandomIntList();
	int ope = 1; 
	while (ope){
		Tool tool;
		printf("\n\t\t欢迎来到排序综合系统!\n\t\t菜单\n\
		(1)-- - 直接插入排序\n\
		(2)-- - 直接选择排序\n\
		(3)-- - 冒泡排序\n\
		(4)-- - 快速排序\n\
		(5)-- - 堆排序\n\
		(6)-- - 时间效率比较\n\
		(7)-- - 显示随机数\n\
		(0)-- - 退出系统\n");
		scanf_s("%d", &ope);
		switch (ope)
		{
		case 0:
			printf("正在退出系统\n");
			break;
		case 1:
			// 直接插入排序
			tool = insert_sort(list);
			addTool(tools, tool);
			break;
		case 2: //直接选择排序
			tool = zhiJie_sort(list);
			addTool(tools, tool);
			break;
		case 3: // 冒泡排序
			tool = qiPao_sort(list);
			addTool(tools, tool);
			break;
		case 4:// 快速排序
		{
			tool.begainTime = clock();
			int times = 0;
			strcpy_s(tool.name, "shell排序");
			int* _list = copyList(list);
			shell_sort(_list, 0, MAX_SIZE - 1, &tool, &times);
			tool.endTime = clock();
			addTool(tools, tool);
			travelList(_list);
			printf("shell排序成功!\n");
			printTool(tool);
		}
			break;
		case 5:// 堆排序
			tool.begainTime = clock();
			strcpy_s(tool.name, "堆排序");
			heap_sort(list, MAX_SIZE - 1,&tool);
			tool.endTime = clock();
			addTool(tools,tool);
			printTool(tool);
			break;
		case 6: //时间效率比较
			sortTools(tools);
			break;
		case 7: //显示随机数
			travelList(list);
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}
}

int main() {
	menue();
	return 0;
}

运行效果 

注:规模较小时会输出排序结果,规模较大时结果就没算法的一些属性那么重要,则不输出结果

 1,直接插入排序运行效果

 2,直接选择排序运行效果

 3,冒泡排序运行效果

4,快速排序运行效果

 

 5,堆排序

 6,时间比较

规模较小时

数据规模较大时

 

 全部代码


#define MAX_SIZE 20
#define MAX_TRAVEL 100
#include<time.h>
#include <stdlib.h>
#include<stdio.h>
#include<string.h>
typedef struct Tool{
	char name[20] = ""; // 记录算法名字
	int compareTime = 0; // 记录比较次数
	int moveTime = 0; //记录移动次数
	long begainTime = 0; // 记录开始时间
	long endTime = 0;// 记录结束时间
};

void travelList(int* list) {
	if (MAX_SIZE > MAX_TRAVEL) {
		printf("随机数组的大小超过了最大遍历数,则不会遍历输出!\n");
		return;
	}
	printf("==============开始遍历=================\n");
	for (int i = 0; i < MAX_SIZE; i++) {
		if (!(i % 5)) {
			printf("\n");
		}
		printf("%d\t", list[i]);
	}
	printf("\n==============遍历结束=================\n");
}

int* createRandomIntList() {
	int* intList = (int*)malloc(sizeof(int)*MAX_SIZE); // 开辟空间
	printf("产生的随机数如下:\n");
	for (int i = 0; i < MAX_SIZE; i++) {
		intList[i] = rand() % 100; // 产生[0-100)的随机数
	}
	travelList(intList);
	return intList;
}
int* copyList(int* list) {
	int* newList = (int*)malloc(sizeof(int) * MAX_SIZE);
	for (int i = 0; i < MAX_SIZE; i++) {
		newList[i] = list[i];
	}
	return newList;
}

void printTool(Tool tool) {
	printf("=====================%s============================\n",tool.name);
	printf("排序规模(个):%d\n",MAX_SIZE);
	printf("程序运行时间:%ld个时钟周期\n",tool.endTime - tool.begainTime);
	printf("移动次数:%d\n比较次数:%d\n",tool.moveTime,tool.compareTime);
	printf("=================================================\n");
}


Tool zhiJie_sort(int* _list) {
	int* list = copyList(_list);
	Tool tool;
	strcpy_s(tool.name, "直接排序");
	tool.begainTime = clock();
	for (int i = 0; i < MAX_SIZE; i++) {
		int min = list[i];
		int k = i;
		for (int j = i + 1; j < MAX_SIZE; j++) {
			tool.compareTime++;
			if (min > list[j]) {
				min = list[j];
				k = j;
			}
		}
		if (k != i) {
			int a = list[i];
			list[i] = list[k];
			list[k] = a;
			tool.moveTime++;
		}
	}
	tool.endTime = clock();
	printf("\n直接排序成功!\n");
	travelList(list);
	printTool(tool);
	return tool;
}

Tool qiPao_sort(int* _list) {
	int* list = copyList(_list);
	Tool tool;
	strcpy_s(tool.name, "气泡排序");
	tool.begainTime = clock();
	for (int i = 0; i < MAX_SIZE; i++) {
		for (int j = 0; j < MAX_SIZE-1-i; j++) {
			tool.compareTime++;
			if (list[j] > list[j + 1]) {
				int a = list[j];
				list[j] = list[j+1];
				list[j+1] = a;
				tool.moveTime++;
			}
		}
	}
	tool.endTime = clock();
	travelList(list);
	printTool(tool);
	return tool;
}

Tool insert_sort(int* _list) {
	int* newList = (int*)malloc(sizeof(int)*MAX_SIZE);
	Tool tool;
	strcpy_s(tool.name, "直接插入排序");
	tool.begainTime = clock();
	newList[0] = _list[0];
	for (int i = 1; i < MAX_SIZE; i++) { // i 表示开始插入i个元素
		int insertValue = _list[i]; // 插入的值
		int isInsert = false;
		for (int j = 0; j <i; j++) {// 找到插入位置
			tool.compareTime++;
			if (newList[j] > insertValue) { // 找到插入位置
				for (int k = i; k > j; k--) {
					newList[k] = newList[k - 1];
					tool.moveTime++;
				}
				newList[j] = insertValue;
				isInsert = true;
				break;
			}
		}
		if (!isInsert) {
			newList[i] = insertValue;
		}
	}
	tool.endTime = clock();
	travelList(newList);
	printTool(tool);
	return tool;
}


void shell_sort(int* list,int begPosition,int endPosition,Tool* tool,int* times) {
	(*times)++;
	int keyValue = list[begPosition]; // 枢轴值
	int key = begPosition; // 记录空位置
	for (int i = begPosition, j = endPosition; i <j&&j!=key; j--) {
		tool->compareTime++;
		if (keyValue>list[j]) { // 从右边开始比较
			list[key] = list[j];// 将右边小于枢值移到左边
			key = j;// 记录空值位置
			tool->moveTime++;
			while (keyValue >= list[i] && i!=key) {//从左边开始比较
				tool->compareTime++;
				i++;
			}
			if (i == key) {
				break;
			}
			list[key] = list[i];			// i 为空位置
			key = i;
			tool->moveTime++;
		}
	}
	list[key] = keyValue;
	if (MAX_TRAVEL > MAX_SIZE) {
		printf("第%d躺移动结果:\n", *times);
		travelList(list);
	}
	tool->moveTime++;
	if (begPosition != key) {
		shell_sort(list, begPosition, key, tool,times);
	}
	if (key + 1 < endPosition) {
		shell_sort(list, key + 1, endPosition, tool,times);
	}
}


void heapAdjust(int* list, int s, int m,Tool* tool)//一次筛选的过程
{
	int min = list[s]; // 假设节点处的值最小
	for (int j = 2 * s; j <= m; j = j * 2)//通过循环沿较大的孩子结点向下筛选
	{
		if (j < m && list[j] < list[j + 1]) {
			j++;//j为较大的记录的下标
			tool->compareTime++;
		} 
		if (min > list[j]) break; // 找到比根大的位置,跳出调整循环,插入节点处
		list[s] = list[j];
		tool->moveTime++;
		s = j;
	}
	list[s] = min;//插入
	tool->moveTime++;
}

/*
des: 堆排序
*/
void heap_sort(int* _list, int n,Tool* tool)
{
	// 将数组里的元素向后移预留出0的位置,方便逻辑实现
	int* list =(int*) malloc(sizeof(int)*(MAX_SIZE+1));
	// 因此排序长度加一
	n += 1;
	// 元素后移
	for (int i = MAX_SIZE; i > 0; i--) {
		list[i] = _list[i - 1];
	}
	for (int i = n / 2; i > 0; i--)//初始化堆
	{
		heapAdjust(list, i, n,tool);
	}
	for (int i = n; i >0; i--)
	{
		int temp = list[1];
		list[1] = list[i];
		list[i] = temp;//将堆顶记录与未排序的最后一个记录交换
		tool->moveTime++;
		heapAdjust(list, 1, i - 1,tool);//重新调整为顶堆
	}
	// 输出排序结果
	if (MAX_SIZE > MAX_TRAVEL) {
		return;
	}
	for (int i = 1; i <= MAX_SIZE; i++) {
		printf("%d\t",list[i]);
		if (!(i % 5)) {
			printf("\n");
		}
	}
}
bool toolIsEmpty(Tool tool) {
	if (!strcmp(tool.name, "")) {
		return true;
	}
	return false;
}
void copyTool(Tool* newT, Tool* oldT) {
	newT->begainTime = oldT->begainTime;
	newT->compareTime = oldT->compareTime;
	newT->endTime = oldT->endTime;
	newT->moveTime = oldT->moveTime;
	strcpy_s(newT->name,oldT->name);
}

bool addTool(Tool tools[], Tool tool) {
	int i = 0;
	while (!toolIsEmpty(tools[i])) {
		i++;
	}
	copyTool(&tools[i], &tool);
	return true;
}

void travelTools(Tool tools[]) {
	for (int i = 0; !toolIsEmpty(tools[i]); i++) {
		printTool(tools[i]);
	}
}

void sortTools(Tool tools[],int key=1) {
	switch (key) {
	case 1: // 运行时间
		for (int i = 0; !toolIsEmpty(tools[i]); i++) {
			long min = tools[i].endTime - tools[i].begainTime;
			for (int j = i; !toolIsEmpty(tools[j]); j++) {
				long big = tools[j].endTime - tools[j].begainTime;
				if (min > big) {
					Tool tool = tools[i];
					tools[i] = tools[j];
					tools[j] = tool;
				}
			}
		}
	}
	travelTools(tools);
}

void menue() {
	Tool tools[6];
	int* list = createRandomIntList();
	int ope = 1; 
	while (ope){
		Tool tool;
		printf("\n\t\t欢迎来到排序综合系统!\n\t\t菜单\n\
		(1)-- - 直接插入排序\n\
		(2)-- - 直接选择排序\n\
		(3)-- - 冒泡排序\n\
		(4)-- - 快速排序\n\
		(5)-- - 堆排序\n\
		(6)-- - 时间效率比较\n\
		(7)-- - 显示随机数\n\
		(0)-- - 退出系统\n");
		scanf_s("%d", &ope);
		switch (ope)
		{
		case 0:
			printf("正在退出系统\n");
			break;
		case 1:
			// 直接插入排序
			tool = insert_sort(list);
			addTool(tools, tool);
			break;
		case 2: //直接选择排序
			tool = zhiJie_sort(list);
			addTool(tools, tool);
			break;
		case 3: // 冒泡排序
			tool = qiPao_sort(list);
			addTool(tools, tool);
			break;
		case 4:// 快速排序
		{
			tool.begainTime = clock();
			int times = 0;
			strcpy_s(tool.name, "shell排序");
			int* _list = copyList(list);
			shell_sort(_list, 0, MAX_SIZE - 1, &tool, &times);
			tool.endTime = clock();
			addTool(tools, tool);
			travelList(_list);
			printf("shell排序成功!\n");
			printTool(tool);
		}
			break;
		case 5:// 堆排序
			tool.begainTime = clock();
			strcpy_s(tool.name, "堆排序");
			heap_sort(list, MAX_SIZE - 1,&tool);
			tool.endTime = clock();
			addTool(tools,tool);
			printTool(tool);
			break;
		case 6: //时间效率比较
			sortTools(tools);
			break;
		case 7: //显示随机数
			travelList(list);
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}
}

int main() {
	menue();
	return 0;
}

代码写得很赶,当数据规模大的时候还是有很多bug,可能是算法的不稳定性,也很大可能是我考虑不周,很多算法上的细节没处理好,欢迎大家评论,我将认真阅读大家的意见!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小周努力变优秀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值