Lesson6--排序(初级数据结构完结篇)

news2024/11/17 16:27:32
【本节目标】
1. 排序的概念及其运用
2. 常见排序算法的实现
3. 排序算法复杂度及稳定性分析

1.排序的概念及其运用

1.1排序的概念  

排序 :所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次
序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排
序算法是稳定的;否则称为不稳定的
稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次
序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排
序算法是稳定的;否则称为不稳定的

1.2排序运用

 1.3 常见的排序算法

// 排序实现的接口
// 插入排序
void InsertSort(int* a, int n);
// 希尔排序
、void ShellSort(int* a, int n);
// 选择排序
void SelectSort(int* a, int n);
// 堆排序
void AdjustDwon(int* a, int n, int root);
void HeapSort(int* a, int n);
// 冒泡排序
void BubbleSort(int* a, int n)
// 快速排序递归实现
// 快速排序hoare版本
int PartSort1(int* a, int left, int right);
// 快速排序挖坑法
int PartSort2(int* a, int left, int right);
// 快速排序前后指针法
int PartSort3(int* a, int left, int right);
void QuickSort(int* a, int left, int right);
// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
// 归并排序递归实现
void MergeSort(int* a, int n)
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
// 计数排序
void CountSort(int* a, int n)
// 测试排序的性能对比
void TestOP()
{
 srand(time(0));
 const int N = 100000;
 int* a1 = (int*)malloc(sizeof(int)*N);
 int* a2 = (int*)malloc(sizeof(int)*N);
 int* a3 = (int*)malloc(sizeof(int)*N);
 int* a4 = (int*)malloc(sizeof(int)*N);
 int* a5 = (int*)malloc(sizeof(int)*N);
 int* a6 = (int*)malloc(sizeof(int)*N);
 for (int i = 0; i < N; ++i)
 {
 a1[i] = rand();
 a2[i] = a1[i];
 a3[i] = a1[i];
 a4[i] = a1[i];
 a5[i] = a1[i];
 a6[i] = a1[i];
}
 int begin1 = clock();
 InsertSort(a1, N);
 int end1 = clock();
 int begin2 = clock();
 ShellSort(a2, N);
 int end2 = clock();
 int begin3 = clock();
 SelectSort(a3, N);
 int end3 = clock();
 int begin4 = clock();
 HeapSort(a4, N);
 int end4 = clock();
 int begin5 = clock();
 QuickSort(a5, 0, N-1);
 int end5 = clock();
 int begin6 = clock();
 MergeSort(a6, N);
 int end6 = clock();

printf("InsertSort:%d\n", end1 - begin1);
 printf("ShellSort:%d\n", end2 - begin2);
 printf("SelectSort:%d\n", end3 - begin3);
 printf("HeapSort:%d\n", end4 - begin4);
 printf("QuickSort:%d\n", end5 - begin5);
 printf("MergeSort:%d\n", end6 - begin6);
 free(a1);
 free(a2);
 free(a3);
 free(a4);
 free(a5);
 free(a6);
}

 排序OJ(可使用各种排序跑这个OJ)912. 排序数组 - 力扣(LeetCode)

2.常见排序算法的实现 

2.1 插入排序

2.1.1基本思想:

直接插入排序是一种简单的插入排序法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为
止,得到一个新的有序序列
实际中我们玩扑克牌时,就用了插入排序的思想

 

2.1.2直接插入排序: 

当插入第 i(i>=1) 个元素时,前面的 array[0],array[1],…,array[i-1] 已经排好序,此时用 array[i] 的排序码与
array[i-1],array[i-2],… 的排序码顺序进行比较,找到插入位置即将 array[i] 插入,原来位置上的元素顺序后移
直接插入排序的特性总结:
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度: O(N^2)
3. 空间复杂度: O(N) ,它是一种稳定的排序算法
4. 稳定性:稳定

 

代码实现:
void InsertSort(int* arr, int length)
{
	for (int i = 0; i < length-1; i++)
	{
		int end=i;
		int temp = arr[end + 1];
		while (end >= 0)
		{
			if (temp < arr[end])
			{
				arr[end+1] = arr[end];
			}
			else
			{
				break;
			}
			end--;
		}
		arr[end + 1] = temp;
	}
	
}

2.1.3希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个 组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工 作。当到达gap=1时,所有记录在统一组内排好序

希尔排序的特性总结:
1. 希尔排序是对直接插入排序的优化。
2. gap > 1 时都是预排序,目的是让数组更接近于有序。当 gap == 1 时,数组已经接近有序的了,这样就
会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为 gap 的取值方法很多,导致很难去计算,因此在好些树中给出的
希尔排序的时间复杂度都不固定

 

时间复杂度可以即一个结论大概是:N^1.3 

 

代码实现:

 

void SellSort(int* arr, int length)
{
	int gap = length;
	while (gap>1)
	{
		gap = gap / 3 + 1;
		for (int  i = 0; i < length-gap; i++)
		{
			int end = i;
			int temp = arr[end + gap];
			while (end>=0)
			{
				if (temp < arr[end])
				{
					arr[end + gap] = arr[end];
					end = end - gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = temp;
		}
	}
}

2.2冒泡排序

基本思路:
左边大于右边交换一趟排下来最大的在右边

 

冒泡排序的特点包括:
1. 冒泡排序适合处理元素集合越接近有序的情况,时间效率会更高。
2. 冒泡排序的时间复杂度为O(N^2),性能较差,不适用于处理大规模数据的排序。
3. 冒泡排序是一种稳定的排序算法,相同元素的相对位置不会发生改变。
4. 冒泡排序的空间复杂度为O(N),是一种原地排序算法。
5. 冒泡排序是一种交换排序算法,通过不断比较相邻的元素并交换位置来达到排序的目的。
 

代码实现:

void BubbleSort(int* arr, int length)
{
	for (int i = 0; i < length-1; i++)
	{
		int flag = 0;
		for (int j = 0; j < length-i-1; j++)
		{
			if (arr[j] > arr[j + 1]) 
			{
				
				Swap(&arr[j], &arr[j + 1]);
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}

2.3堆排序

堆排序是一种基于二叉堆数据结构的排序算法,其基本思路如下:

  1. 构建最大堆或最小堆:将待排序的数组视作一个完全二叉树,并且通过调整父节点与子节点的关系,使得每个父节点的值都大于或小于其子节点的值,即构建最大堆或最小堆。

  2. 将堆顶元素与最后一个元素交换:将根节点(最大值或最小值)与最后一个元素交换位置。

  3. 调整堆结构:交换元素后,调整堆结构,使其重新满足最大堆或最小堆的性质。

  4. 重复步骤2和3:重复进行上述步骤,直到所有元素都被交换到对应的位置,即完成排序。

堆排序的时间复杂度为O(nlogn),其中n为待排序数组的长度。堆排序是一种原地排序算法,不需要额外的空间,但性能较差且不稳定。

 

代码实现: 

void AdjustDown(int* arr,int length, int parent)
{
	int child = parent * 2 + 1;
	while (child<length)
	{
		if (child+1<length && arr[child + 1] > arr[child])
		{
			child++;
		}

		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break; 
		}
	}
}
void HeapSort(int* arr, int length)
{
	for (int i = (length-1-1)/2; i >= 0; i--)
	{
		AdjustDown(arr, length, i);
	}
	int end = length - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
		end--;
	}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1721439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GPT LoRA 大模型微调,生成猫耳娘

往期热门专栏回顾 专栏描述Java项目实战介绍Java组件安装、使用&#xff1b;手写框架等Aws服务器实战Aws Linux服务器上操作nginx、git、JDK、VueJava微服务实战Java 微服务实战&#xff0c;Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc…

MACOS安装 vue 抱错解决方法npm ERR! code EACCESnpm ERR! syscall mkdirnpm ERR!

问题 在使用脚手架 vue-cli 创建 vue 工程的时候存在权限不足的情况下&#xff0c;报错&#xff1b; npm error code EACCES npm error syscall open npm error path /Users/ npm ERR! code EACCESnpm ERR! syscall mkdirnpm ERR! 解决方案&#xff1a; sudo npm cache cl…

什么是最好的手机数据恢复软件?6 款手机数据恢复软件 [2024 年更新]

什么是最好的手机数据恢复软件&#xff1f;在这篇文章中&#xff0c;您将了解 6 款最好的免费手机数据恢复软件&#xff0c;并学习如何恢复数据的完整指南。 最好的手机数据恢复软件是什么&#xff1f; 手机数据恢复软件是恢复智能手机中丢失或删除的文件、消息、照片和其他宝…

反射获取成员变量

目录 利用反射获取成员变量 ​编辑 代码实现 获取class对象 获取成员变量 获取单个成员变量 获取成员变量的名字 获取权限修饰符 获取成员变量的数据类型 获取成员变量记录的值 修改对象里面记录的值 利用反射获取成员变量 代码实现 Student类&#xff1a; 获取clas…

【 0 基础 Docker 极速入门】镜像、容器、常用命令总结

Docker Images&#xff08;镜像&#xff09;生命周期 Docker 是一个用于创建、部署和运行应用容器的平台。为了更好地理解 Docker 的生命周期&#xff0c;以下是相关概念的介绍&#xff0c;并说明它们如何相互关联&#xff1a; Docker&#xff1a; Docker 是一个开源平台&#…

生成ssh密钥,使用ssh连接linux系统

这里写目录标题 ssh密钥大概介绍1、密钥在哪里生成&#xff08;客户端/服务器&#xff09;&#xff1f;2、密钥生成是什么样子的&#xff1f; ssh &#xff08;生成密钥、密钥传输、配置连接、连接服务&#xff09;过程1、生成密钥提示一&#xff1a;输入保存密钥的文件&#x…

Nginx实战:nginx支持带下划线的header

nginx对header 的名字字符做了限制&#xff0c;默认 underscores_in_headers 为off&#xff0c;表示如果header name中包含下划线&#xff0c;则忽略掉&#xff0c;后端服务就获取不到该请求头。 为了支持header带下划线的参数&#xff0c;可以在http内或者server内设置如下参数…

ip地址告诉别人安全吗?ip地址告诉别人会有什么风险

IP地址告诉别人安全吗&#xff1f;在数字化时代&#xff0c;IP地址作为网络连接的关键标识符&#xff0c;承载着重要的安全意义。然而&#xff0c;很多人可能并不清楚&#xff0c;轻易地将自己的IP地址告诉他人可能带来一系列安全风险。那么&#xff0c;IP地址告诉别人会有什么…

7-11 验证宏(verify)---PTA实验C++

一、题目描述 无需惊慌&#xff0c;C缔造者Bjarne Stroustrup这句话说的CPP是C PreProcessor&#xff0c;即“C代码预处理器”。CPP根据#include #define #if #pragma等指令对文件进行处理。这种处理发生在编译之前&#xff0c;所以CPP叫“预处理器”。CPP完全是文本层面的处理…

少样本学习与零样本学习:理解与应用

少样本学习与零样本学习&#xff1a;理解与应用 在现代机器学习领域中&#xff0c;少样本学习&#xff08;Few-Shot Learning&#xff09;和零样本学习&#xff08;Zero-Shot Learning&#xff09;正变得越来越重要。这些技术能够在数据稀缺的情况下有效地进行学习和推理&…

禁止Windows Defender任务计划程序

开始键->搜索“任务计划程序”->“任务计划程序库”->“Microsoft”->"Windows"->"Windows Defender"->右边四项

Prometheus + Grafana + Alertmanager 系统监控

PrometheusGrafana 系统监控 1. 简介1.1 Prometheus 普罗 米修斯1.2 Grafana 2. 快速试用2.1 Prometheus 普罗 米修斯2.2 Prometheus 配置文件2.3 Grafana 2. 使用 Docker-Compose脚本部署监控服务3. Grafana 配置3.1 配置数据源 Prometheus3.2 使用模板ID 配置监控模板3.3 使用…

【SpringBoot】怎么在一个大的SpringBoot项目中创建多个小的SpringBoot项目,从而形成子父依赖

父子项目工程创建 步骤 先创建父项目 具体操作步骤请看本文章&#xff1a;使用maven工程创建spring boot项目 创建子项目 file- project structure module–new module 剩下步骤请看创建父工程时的操作使用maven工程创建spring boot项目 应用 确认即可 之后创建启动类…

Kafka篇:Kafka搭建、使用、及Flink整合Kafka文档

一、Kafka搭建 1、上传并解压改名 tar -xvf kafka_2.11-1.0.0.tgz mv kafka_2.11-1.0.0 kafka-1.0.0 2、配置环境变量 vim /etc/profile export KAFKA_HOME/usr/local/soft/kafka-1.0.0 export PATH$PATH:$KAFKA_HOME/bin source /etc/profile &#xff08;使环境变量生效…

SPHINX的输出文档格式

SPHINX的输出文档格式 SPHINX的输出文档格式更多信息 SPHINX的输出文档格式 用rst编写&#xff0c;然后用sphinx-build进行编译&#xff0c;还是效果相当不错地&#xff0c;只要掌握了格式&#xff0c;可以一次编译&#xff0c;多种格式输出&#xff0c;主要是用的可能是html和…

Java对象的比较——equals方法,Comparable接口,Comparator接口

Java对象的比较——equals方法&#xff0c;Comparable接口&#xff0c;Comparator接口 1. equals方法2. Comparable接口3. Comparator接口 1. equals方法 在判断两个整数是否相同时&#xff0c;我们可以使用以下方式&#xff1a; System.out.println(1 2); System.out.printl…

多普云DPGo摄影测量航线规划软件

1.航线代规划。支持GSR航线&#xff08;大疆精灵4RTKSDK遥控器&#xff09;、DJI Pilot航线&#xff08;大疆精灵4RTK、M300&#xff09;、DJI Pilot2航线&#xff08;大疆精灵4RTK、M300、Mavic3E&#xff09;。 2.DPGO三维模型满足毫米级精度要求&#xff1a;已知被摄范围&am…

基于java的CRM客户关系管理系统(二)

目录 第二章 相关技术介绍 2.1 后台介绍 2.1.1 B/S平台模式 2.1.2 MVC 2.1.3 Spring 2.1.4 Hibernate 2.1.5 Struts 2.2 前端介绍 2.2.1 JSP网页技术 2.3 开发工具 2.4 本章小结 前面内容请移步 基于java的CRM客户关系管理系统&#xff08;二&#xff09; 资源…

vscode编辑器创建分支注意事项?!

最近在公司开发项目时&#xff0c;不小心将自己分支的东西提交到公司的master的分支&#xff0c;大家看看是什么情况&#xff1f; 先上图&#xff1a; 从图上看&#xff0c;我这边用了GITLENS这个插件&#xff0c;在创建分支时&#xff0c;有个create branch from&#xff0c;有…

如何选择软件开发服务商

在当今数字化快速发展的时代&#xff0c;软件已经成为企业运营不可或缺的一部分。然而&#xff0c;对于许多非技术背景的企业来说&#xff0c;如何选择一个合适的软件开发服务商却是一个不小的挑战。本文将从需求分析、服务商评估、合同条款以及后期维护等方面&#xff0c;详细…