草庐IT

【从零到蓝桥杯省一】 算法详解之排序算法

cloud、泡泡 2023-06-20 原文

引言

大家好,我是泡泡,一个在算法和其他领域反复横跳的博主(虽然还没去其他领域写文)

如果你是零基础的小白 那么欢迎你来订阅我的算法详解专栏 会给你不一样的学习体验!

如果你是有基础的高手 欢迎你来对自己学过的知识进行复习 和我一起探讨算法!

如果你是大牛 允许我膜拜你三分钟

对各位有帮助的话还请三连支持一下小弟,你们的关注三连是我更新的动力!

目录

引言

算法简述

快速排序

归并排序

写在最后


算法简述

想必各位小伙伴都听说过八大排序,如果你没有学习过算法估计也会在c语言课上听老师讲过,这八个排序算法是冒泡排序,选择排序,插入排序,希尔排序,快速排序,归并排序,桶排序, 堆排序。

但是我们平时用得到的多的排序只有快排和归并,所以这里展开去讲这两个排序算法。

快速排序

快速排序是对冒泡排序的一种改进, 它是不稳定的。采用的是分治策略,以减少排序过程中的比较次数,它的最好情况为O(nlogn),最坏情况为O(n^2),平均时间复杂度为O(nlogn)。

快速排序的基本思想是

1、先从数列中取出一个数作为分界点

这个分界点有三种方法 第一种是取左端点 第二种是取l+r/2 也就是中间点 第三种是右端点 我们平时就用中点 因为他更快一些

2、划分成两个分区 不一定相等 让左边的分区都小于等于这个点 右边的都大于等于这个点

3、递归的给左右两端排序

光看文字不直观,我们上动态图先了解一下!

然后我们就可以基于这个思想实现一下代码

首先是定义端点

int i = l - 1,j = r + 1,x = a[l+r>>1];

这是左端点和右端点,有同学要问为什么不是l和r是l-1 r+1

因为我们这两个端点每次交换完都会向中间移动一格 所以我们选择先移动再判断 为了防止边界问题 就先设置成l-1 r+1

然后就是我们的判断代码

while(i<j)
	{
		while(a[++i]<x);
		while(a[--j]>x);
		if(i<j)
		{
			swap(a[i],a[j]);
		}
	}

首先就是判断 左端点小于右端点 然后我们循环判断 如果当前数组左端点小于x 那么i就++ 也就是指针继续往下走 比如我们数组里的值为

3 1 2 3 5 8 7 9 6 

此时 我们的中点在5 左端点在3左边 右端点在6右边 我们先进行++ 此时左端点在3

3 1 2 3 5 8 7 9 6

然后开始判断 如果当前的值小于5 那么i继续++

一直到中点5

3 1 2 3 5 8 7 9 6

此时左端点指针停了,然后i的值为4

开始j 一直判断大于5 也是最后会到5这里 j的值也为4

注意!因为我的数组在主函数读入是从0开始 所以我传入的左端点和右端点是0和n-1(在上面这个数据也就是8)

如果 i和j两个指针没相遇 那么让他们交换一下值。

然后我们就开始递归处理左右两边

quick_sort(l,j),quick_sort(j+1,r);

一个快速排序就写好了,我们把全部代码放上来

#include<bits/stdc++.h>
using namespace std;
int a[100001];
void quick_sort(int l,int r)
{
	if(l>=r)
	{
		return;
	}
	int i = l - 1,j = r + 1,x = a[l+r>>1];
	while(i<j)
	{
		while(a[++i]<x);
		while(a[--j]>x);
		if(i<j)
		{
			swap(a[i],a[j]);
		}
	}
	quick_sort(l,j),quick_sort(j+1,r);
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	quick_sort(0,n-1);
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	return 0;
}

这边建议各位记一下这个模板(不记也行 反正有库函数),然后给大家放道简单题锻炼一下这个模板哦!

快速排序模板题点这里

归并排序

如果说快速排序用的是分治的思想,那么归并排序就是分治的体现了,他会先把所有的值分开,直到不能分为止,再去进行排序,这个过程需要一个额外的数组给我们打辅助!

比如:3 1 2 3 8 7 9 6 分治之后就是 3123  8796 然后再分 31   23   87   96,这里就不能再分了,然后我们开始排序 13   23   78   69,然后开始并起来, 1233  6789最后就是排序完成 12336789 

1、确定分界点 (l+r)/2

2、递归排序左右两边

3、合二为一(难点)

然后就是我们熟悉的gif,比较直观地看一下!

我们基于上面的思想来实现代码

先去递归左右两边

int mid = l + r >> 1;
mergesort(l,mid);
mergesort(mid+1,r);

然后我们定义一个左端点 右端点和一个k(记录第二个数组放了几个值)

int k = 0,i = l,j = mid + 1;

然后就可以开始判断了,如果左边小 那么先把左边放进第二个数组,否则把右边的放入第二个数组

while(i<=mid&&j<=r)
{
	if(a[i]<=a[j])
	{
		b[k++] = a[i++];
	}
	else
	{
		b[k++] = a[j++];
	}
}

此时我们还需要判断一下,如果左右两边没有循环完毕的情况

	while(i<=mid)
	{
		b[k++] = a[i++];
	}
	while(j<=r)
	{
		b[k++] = a[j++];
	}

最后我们把数组复原一下!

	for(int i=l,j=0;i<=r;i++,j++)
	{
		a[i] = b[j];
	}

这就是我们的归并排序核心代码了,我把全部代码放上来

#include<bits/stdc++.h>
using namespace std;
int a[100010],b[1000010];
void mergesort(int l,int r)
{
	if(l>=r)
	{
		return;
	}
	int mid = l + r >> 1;
	mergesort(l,mid);
	mergesort(mid+1,r);
	int k = 0,i = l,j = mid + 1;
	while(i<=mid&&j<=r)
	{
		if(a[i]<=a[j])
		{
			b[k++] = a[i++];
		}
		else
		{
			b[k++] = a[j++];
		}
	}
	while(i<=mid)
	{
		b[k++] = a[i++];
	}
	while(j<=r)
	{
		b[k++] = a[j++];
	}
	for(int i=l,j=0;i<=r;i++,j++)
	{
		a[i] = b[j];
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	mergesort(0,n-1);
	for(int i=0;i<n;i++)
	{
		cout<<a[i];
	}
	return 0;
}

这个模板是需要大家去记得,先理解了代码的思想和原理再去记代码 不然的话记不住的 也不会用

归并排序平时都是用在了逆序对上,这里出一个逆序对的简单题,大家可以思考一下!

逆序对简单题点这里

写在最后

学习算法是为了让自己变得更好,更优秀,路上的这些比赛都是检验你的学习成果的,如果成绩不理想也不要灰心,毕竟你不是为了比赛去学习的,学习算法需要持之以恒的练习,我希望各位都能在算法这条路上坚持下去

如果你觉得这篇文章对你有帮助或者觉得写得不错的可以订阅我的算法详解专栏并且给我一个三连关注支持一下我,你们的支持是我更新的动力,感谢各位的观看,祝你们天天开心!

 

 

有关【从零到蓝桥杯省一】 算法详解之排序算法的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  3. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  4. ruby-on-rails - 在具有 ActiveRecord 条件的相关模型中按字段排序 - 2

    我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我

  5. ruby - 按数字(从大到大)然后按字母(字母顺序)对对象集合进行排序 - 2

    我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby​​做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排

  6. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  7. ruby-on-rails - 如何对对象数组进行排序? - 2

    我有一个对象如下:[{:id=>2,:fname=>"Ron",:lname=>"XXXXX",:photo=>"XXX"},{:id=>3,:fname=>"Dain",:lname=>"XXXX",:photo=>"XXXXXXX"},{:id=>1,:fname=>"Bob",:lname=>"XXXXXX",:photo=>"XXXX"}]我想按fname排序,不区分大小写,所以它会导致编号:1,3,2我该如何排序?我正在尝试:@people.sort!{|x,y|y[:fname]x[:fname]}但这没有任何效果。 最佳答案

  8. ruby - 使用自定义排序首选项对数组进行排序? - 2

    有人可以告诉我如何根据自定义字符串对嵌套数组进行排序吗?比如有没有办法排序:[['Red','Blue'],['Green','Orange'],['Purple','Yellow']]“橙色”、“黄色”,然后是“蓝色”?最终结果如下所示:[['Green','Orange'],['Purple','Yellow'],['Red','Blue']]它不是按字母顺序排序的。我很想知道我是否可以定义要排序的值以实现上述目标。 最佳答案 sort_by对于这种排序总是非常方便:a=[['Red','Blue'],['Green','Ora

  9. Ruby 将对象插入现有的已排序对象数组 - 2

    我有以下现有的Dog对象数组,它们按age属性排序:classDogattr_accessor:agedefinitialize(age)@age=ageendenddogs=[Dog.new(1),Dog.new(4),Dog.new(10)]我现在想插入一条新的狗记录,并将它放在数组中的正确位置。假设我想插入这个对象:another_dog=Dog.new(8)我想把它插入到数组中,让它成为数组中的第三项。这是一个人为的示例,旨在演示我特别想如何将一个项目插入到现有的有序数组中。我意识到我可以创建一个全新的数组并重新对所有对象进行排序,但这不是我的目标。谢谢!

  10. ruby - 如何排序不是简单的哈希(哈希的哈希) - 2

    我有一个这样的哈希{55=>{:value=>61,:rating=>-147},89=>{:value=>72,:rating=>-175},78=>{:value=>64,:rating=>-155},84=>{:value=>90,:rating=>-220},95=>{:value=>39,:rating=>-92},46=>{:value=>97,:rating=>-237},52=>{:value=>73,:rating=>-177},64=>{:value=>69,:rating=>-167},86=>{:value=>68,:rating=>-165},53=>{:va

随机推荐