常见的七大排序

目录

前言

冒泡排序

选择排序

插入排序

堆排序

希尔排序

快排

归并排序


前言

本文介绍七种常见的排序方式:冒泡排序,选择排序,插入排序,堆排序,希尔排序,快排,归并排序

冒泡排序

将每2个相邻的数依次进行前后对比,如果前大于后则还位,一轮后最大的将排到最后面

再将长度减1重复进行就可以得到有序的数据了

时间复杂度:O(n^2)

空间复杂度:O(1)

代码展示

void maopao(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz-1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j+1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;
			}
		}
	}
}

选择排序

从数组中选择最小元素,将它与数组的第一个元素交换位置。再从数组剩下的元素中选择出最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。

时间复杂度:O(n^2)

空间复杂度:O(1)

代码展示

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end)
	{
		int mini = begin, maxi = begin;
		for (int i = begin + 1; i <= end; ++i)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}

			if (a[i] < a[mini])
			{
				mini = i;
			}
		}

		Swap(&a[begin], &a[mini]);
		Swap(&a[end], &a[maxi]);
		++begin;
		--end;
	}
}

插入排序

将第一个数记录后与前一个数比较如果小于前面的数则将前面的数后移,再将从第二个数开始重复直到最后的数比完即可

时间复杂度:O(n^2)

空间复杂度:O(1)

代码展示

void insertsort(int* a, int n)
{
	  //[0, n-1]
	for (int i = 0; i < n - 1; i++)
	{
		 //[0,end]有序 end+1位置的值插入[0,end],保持有序
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

 

希尔排序

又称“分组插入排序”

先将整个待排元素序列分割成若干个子序列(一般为数组长度/3+1,+1保证最后一个gap一定是1)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小,即gap==1)时,再对全体元素进行一次直接插入排序

时间复杂度:大约O(N ^ 1.3)

空间复杂度:O(1)

代码展示

void Shellsort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		// +1保证最后一个gap一定是1
		// gap > 1时是预排序
		// gap == 1时是插入排序
		gap = gap / 3 + 1;

		for (size_t i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

堆排序

将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

向上排序的时间复杂度为N*logN

而向下排序的时间复杂度为N

所以最好使用向下拍序

向下排序整理好数据为堆后

再将头尾互换数组大小-1后

再使用向下排序

这样得出来的数组就有序了

总共时间复杂度为N*logN

升序建大堆降序建小堆

时间复杂度:O(n*logn)

空间复杂度:O(1)

代码展示

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)
{
	// 初始条件
	// 中间过程
	// 结束条件
	int parent = (child - 1) / 2;
	//while (parent >= 0)
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown(HPDataType* a, int n, int parent)
{
	// 先假设左孩子小
	int child = parent * 2 + 1;

	while (child < n)  // child >= n说明孩子不存在,调整到叶子了
	{
		// 找出小的那个孩子
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

int main()
{
	int a[10] = { 8,7,5,3,6,4,2,9,4,89 };
	int n = sizeof(a) / sizeof(a[0]);
	// 降序,建小堆
	// 升序,建大堆
	// 向上调整建堆 O(N*logN)
	/*for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}*/

	// 向下调整建堆 O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
	return 0;
}

快排

右数找小于key的数停下,左数找大于key的数停下来,左右数互换后继续走,如果碰头与key换

再将0~key-1的数快排,key+1~n的数快排

为提升效率

使用三数取中

小区间优化

时间复杂度:O(n*logn)

空间复杂度:On*logn)

代码展示

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int GetMidi(int* a, int left, int right)
{
	int midi = (left + right) / 2;
	// left midi right
	if (a[left] < a[midi])
	{
		if (a[midi] < a[right])
		{
			return midi;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	else // a[left] > a[midi]
	{
		if (a[midi] > a[right])
		{
			return midi;
		}
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}
void InsertSort(int* a, int n)
{
	//  [0, n-1]
	for (int i = 0; i < n - 1; i++)
	{
		// [0, n-2]是最后一组
		// [0,end]有序 end+1位置的值插入[0,end],保持有序
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}
void Quicksort(int* a, int left, int right)
{
	if (left >= right)
		return;

	// 小区间优化,不再递归分割排序,减少递归的次数
	if ((right - left + 1) < 10)
	{
		InsertSort(a + left, right - left + 1);
	}
	else
	{
		// 三数取中
		int midi = GetMidi(a, left, right);
		Swap(&a[left], &a[midi]);

		int keyi = left;
		int begin = left, end = right;
		while (begin < end)
		{
			// 右边找小
			while (begin < end && a[end] >= a[keyi])
			{
				--end;
			}

			// 左边找大
			while (begin < end && a[begin] <= a[keyi])
			{
				++begin;
			}

			Swap(&a[begin], &a[end]);
		}

		Swap(&a[keyi], &a[begin]);
		keyi = begin;
		// [left, keyi-1] keyi [keyi+1, right]
		Quicksort(a, left, keyi - 1);
		Quicksort(a, keyi + 1, right);
	}
}

归并排序

将该数组依次分割成两个数组,直到每个数组只有一个元素,再将相邻的2个数组比较有序后合并再将2个元素的数组之间合并,依次完成实现最终数组有序

时间复杂度:O(n*logn)

空间复杂度:On)

代码展示

void _MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 2;
	// 如果[begin, mid][mid+1, end]有序就可以进行归并了
	_MergeSort(a, tmp, begin, mid);
	_MergeSort(a, tmp, mid + 1, end);

	// 归并
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}

	_MergeSort(a, tmp, 0, n - 1);

	free(tmp);
	tmp = NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rsync未授权访问-vulfocus

1.原理 Rsync是linux上文件传输的协议&#xff0c;如果有返回直接可以看到&#xff0c;部分主机使用协议的时候不会加密码&#xff0c;就容易造成未授权访问漏洞 2.复现 打开vulfocus.io,搜索rsync关键字&#xff0c;打开环境 在自己的主机上去连接远程服务器&#xff1a; r…

linux高级编程(1)

linux操作系统编程: 实现一个 用户程序 (1).库函数 --来实现 (2).系统调用 也就是说&#xff0c;程序要进行系统调用的话&#xff0c;有直接和间接&#xff08;通过库函数&#xff09;两种方式 linux里面对文件的处理: 思想: 一切皆文件 everything is file&…

轻松上手MYSQL:MYSQL事务隔离级别的奇幻之旅

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索MYSQL索引数据结构之旅✨ &#x1f44b; 大家好&#xff01;文本学习…

国产AI算力训练大模型技术实践

ChatGPT引领AI大模型热潮&#xff0c;国内外模型如雨后春笋&#xff0c;掀起新一轮科技浪潮。然而&#xff0c;国内大模型研发推广亦面临不小挑战。面对机遇与挑战&#xff0c;我们需保持清醒&#xff0c;持续推进技术创新与应用落地。 为应对挑战&#xff0c;我们需从战略高度…

【Linux详解】冯诺依曼架构 | 操作系统设计 | 斯坦福经典项目Pintos

目录 一. 冯诺依曼体系结构 (Von Neumann Architecture) 注意事项 存储器的意义&#xff1a;缓冲 数据流动示例 二. 操作系统 (Operating System) 操作系统的概念 操作系统的定位与目的 操作系统的管理 系统调用和库函数 操作系统的管理&#xff1a; sum 三. 系统调…

matplotlib之常见图像种类

Matplotlib 是一个用于绘制图表和数据可视化的 Python 库。它支持多种不同类型的图形&#xff0c;以满足各种数据可视化需求。以下是一些 Matplotlib 支持的主要图形种类&#xff1a; 折线图&#xff08;Line Plot&#xff09;&#xff1a; 用于显示数据随时间或其他连续变量的…

【web2】jquary,bootstrap,vue

文章目录 1.jquary&#xff1a;选择器1.1 jquery框架引入&#xff1a;$("mydiv") 当成id选择器1.2 jquery版本/对象&#xff1a;$(js对象) -> jquery对象1.3 jquery的页面加载事件&#xff1a;$ 想象成 window.onload 1.4 jquery的基本选择器&#xff1a;$()里内容…

大模型参数高效微调学习笔记

大模型参数高效微调学习笔记 github地址 billbill链接 1.分类 图中有五个大类&#xff1a; selective&#xff08;选择性微调&#xff09;&#xff1a;BitFit&#xff0c;Attention Tuningsoft prompts&#xff08;提示微调&#xff09;&#xff1a;Prompt-tuning&#xff0c…

Android 自定义软键盘实现 数字九宫格

最近项目在对接美团外卖功能 实现外面小哥凭取货码取货 对接完功能后 用户反馈 弹出的软键盘 很难输入 数字太小了 大概是下面这种显示方式 需求 组长说 要不搞一个自定义软键盘吧 数字搞大点 方便外卖员输入数字 我设置了输入EditText的输入格式为Number 还是不行 那就开…

文件夹或文件已在另一程序中打开,找句柄发现是explorer.exe如何解决

1.找到句柄&#xff1a;ctrl alt del打开任务资源管理器 2.注意是选择CPU -> 关联的句柄&#xff0c;而不是概述 如果发现只有explorer.exe&#xff0c;那肯定是不对的&#xff0c;我们先shfit一个一个删除&#xff0c;发现哪个删不掉&#xff0c;再在这里找句柄&#xff0c…

使用MyBatis Generator自动代码生成器简化Java持久层开发

在Web开发中&#xff0c;数据访问层&#xff08;DAO层&#xff09;的编码工作往往重复且繁琐&#xff0c;尤其是在处理数据库表与Java对象之间的映射时。MyBatis Generator是一款强大的代码生成工具&#xff0c;它能自动生成DAO接口、Mapper XML文件和实体类&#xff0c;极大地…

pytorch国内镜像源安装及测试

一、安装命令&#xff1a; pip install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple 二、测试&#xff1a; import torch x torch.rand(5, 3) print(x)

微信小程序入门2

微信开发者工具的安装方法 1.打开微信开发者工具下载页面 在微信小程序管理后台的左侧边栏中选择“开发工具”&#xff0c;然后选择“开发者工具”&#xff0c;即可找到微信开发者工具的下载页面。 2.打开微信开发者工具的下载链接页面 单击“下载” 按钮下载&#xff0c;即…

【软件测试】认识测试

文章目录 1.什么是测试2.软件测试和开发的区别3.优秀的测试人员需要具备的素质 1.什么是测试 软件测试就是验证软件产品特性是否满足用户的需求 产品特性&#xff1a; 功能性能界面易用性 2.软件测试和开发的区别 工作内容 开发以编码为主&#xff0c;而测试以测试为主&…

高考填报志愿不容易,压线考生怎么救?

每年的高考季 就是高考生们水深火热的一大月份&#xff0c;很多考生都会纠结要报考哪些学校&#xff0c;哪些专业好&#xff0c;并非每个学生从小就有明确的目标&#xff0c;很多人到6月份才深思这个问题&#xff0c;此时难免手慌脚乱&#xff0c;更别说一些考生的分数处于一本…

ping命令返回结果实例分析

测试在各相关情况下ping命令回复信息。 网络环境搭建如下图所示&#xff1a; 【1】R1、R2、PC1和PC2没有配置&#xff0c;测试ping命令回复 在路由器没有配置端口IP地址和路由&#xff0c;PC没有配置IP地址、子网掩码和网关的情况下&#xff0c;PC2 ping 192.168.1.1。 在PC没…

代码随想录-Day37

56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;in…

Program-of-Thoughts(PoT):结合Python工具和CoT提升大语言模型数学推理能力

Program of Thoughts Prompting:Disentangling Computation from Reasoning for Numerical Reasoning Tasks github&#xff1a;https://github.com/wenhuchen/Program-of-Thoughts 一、动机 数学运算和金融方面都涉及算术推理。先前方法采用监督训练的形式&#xff0c;但这…

Qt: QPushButton 按钮实现 上图标下文字

效果如下&#xff1a; 实现有如下几种方式&#xff1a; 1. 使用 QPushButton 设置 setStyleSheet 例&#xff1a; ui->recorder->setStyleSheet("QPushButton{"\"border: 1px solid #00d2ff; "\"min-height: 60px; "\"col…

ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs

ToolLLM: Facilitating Large Language Models to Master 16000 Real-world APIs 一、动机 虽然现如今大模型展现出无与伦比的表现&#xff0c;但是其在工具理解和使用方面依然存在不足&#xff0c;即根据用户的指令和意图来使用外部API。这是因为现有的指令微调任务大多数是…