【算法】--- 几分钟了解直接选择排序(排序中最简单的排序)+快排(解决一切的优质算法)(中)

news2024/11/24 8:05:38

文章目录

  • 前言
  • 🌟一、常见的排序算法:
  • 🌟二、选择排序---直接选择排序:
    • 🌏2.1.1 基本思想:
    • 🌏2.1.2 直接选择排序:
    • 🌏2.1.3 直接选择排序的特性总结:
    • 🌏2.1.4 思路:
    • 🌏2.1.5 代码:
    • 🌏2.1.6 注意易错点:
  • 🌟三、交换排序---快速排序(上):
    • 🌏3.1.1 基本思想:
    • 🌏3.1.2 快速排序
      • 💫3.1.2.1 第一种---挖坑填补法:
        • 📒思路:
        • 📒代码:
        • 📒流程图:
        • 📒时间复杂度:
          • 🔑最好的情况:接近二分
          • 🔑最坏的情况:有序
        • 📒解决方法:三数取中---解决了快排中最坏的情况
          • 🔑代码:
        • 📒补充知识点:>>1与/2的关系
        • 📒小区间优化:
          • 🔑代码:
  • 😽总结


前言

👧个人主页:@小沈熬夜秃头中୧⍤⃝❅
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:算法
🔑本章内容:选择排序中的直接选择排序和交换排序中的快速排序
送给各位💌:你被黑暗敲打恰恰说明你是光明本身
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


提示:以下是本篇文章正文内容,下面案例可供参考

🌟一、常见的排序算法:

前面的插入排序可以回顾【算法】— 几分钟带你走进排序算法大门(上)
选择排序中的堆排序可以回顾【数据结构】—堆排序+TOP-K问题(了解游戏排行底层原理)
交换排序中的冒泡排序可以回顾C-指针的进阶(下)+qsort库函数
所以本章讲解选择排序中的直接选择排序和交换排序中的快速排序请添加图片描述

🌟二、选择排序—直接选择排序:

🌏2.1.1 基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

🌏2.1.2 直接选择排序:

  • 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

🌏2.1.3 直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

🌏2.1.4 思路:

遍历比较选取一个最大的数,一个最小的数,将最小的数和开始位置值交换,最大的数和末尾位置值交换。

🌏2.1.5 代码:

#include<stdio.h>
void Swap(int*  p1, int* p2)
{
	int* tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin, maxi = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] < a[mini])
			{
				mini = i;
			}
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin],& a[mini]);
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[maxi],& a[end]);
		begin++;
		end--;
	}
}
int main()
{
	int a[] = { 9,5,1,7,4,2,6,8![请添加图片描述](https://img-blog.csdnimg.cn/98bf39b9ed01460b83de60cbbe6f3a74.png)
,0,8 };
	int n = sizeof(a)/sizeof(a[0]);
	SelectSort(a, n);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

🌏2.1.6 注意易错点:

这一部分是必须要加上的,不然会出现一个bug,当交换开始位置值与最小值之后,要想一下若最大值就是开始位置值,再交换最大值和末尾值那最大值已经和最小值位置交换了不懂可以看下图:

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

请添加图片描述

🌟三、交换排序—快速排序(上):

🌏3.1.1 基本思想:

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

🌏3.1.2 快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

💫3.1.2.1 第一种—挖坑填补法:

📒思路:

快速排序算法是基于分治策略的另一个排序算法。

该方法的基本思想是
1.先从数列中取出一个数作为基准数,记为key。
2.分区过程,将小于key的数全放到它的左边大于key的数全放到它的右边

📒代码:

#include<stdio.h>
void QuickSort(int* a,int left ,int  right)
{
	//剩下一个数或者没有数就达到了排序就不用排了
	if (left >= right)
	{
		return;
	}
	int begin = left, end = right;
	int pivot = begin;
	int key = a[begin];
	while (begin < end)
	{
		//右边找小,放到左边
		while (begin < end && a[end]>=key)
		{
			end--;
		}
		//找到放在左边的坑里
		a[pivot] = a[end];
		pivot = end;
		//左边找小,放到右边
		while (begin < end && a[begin] <= key)
		{
			begin++;
		}
		a[pivot] = a[begin];
		//找到放在右边的坑里
		pivot = begin;
	}
	//相遇了
	pivot = begin;
	a[pivot] = key;
	//分治策略,分区间将key左边和右边分别再次找关键key然后再次左小右大
	//直到剩下一个数或者没有数就达到了排序的目的
	QuickSort(a, left, pivot - 1);//注意传递的区间
	QuickSort(a, pivot +1,right);//注意传递的区间
}
int main()
{
	int a[] = { 9,5,1,7,4,2,6,3,0,8 };
	int n = sizeof(a) / sizeof(a[0]);
	QuickSort(a, 0,n-1);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

📒流程图:

然后再分为左区间,右区间然后再从左区间中找关键数字再次进行下图这种流程,右区间同理就类似二叉树在这里插入图片描述
在这里插入图片描述

📒时间复杂度:

🔑最好的情况:接近二分

快排最好的情况就是二分(选取的key值正确位置刚好接近中间位置):每一次将一个数排到正确位置,分治算法就相当于一个完全二叉树高度为logN,且每一次时间复杂度O(N),所以总共时间复杂度是O(NlogN)*

请添加图片描述

🔑最坏的情况:有序

快排最坏情况就是有序:当有序时选取最左边(最右边)的数那么都小于(大于)其他数,就会出现左边(右边)没有要排的数,这样每一次都只排一个不像上面的情况类似一个二叉树

请添加图片描述

📒解决方法:三数取中—解决了快排中最坏的情况

🔑代码:
#include<stdio.h>

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

int GetMidIndex(int* a, int left, int right)
{
	int mid = (left + right) >> 1;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else//a[left]>a[mid]
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}
void QuickSort(int* a,int left ,int  right)
{
	//剩下一个数或者没有数就达到了排序就不用排了
	if (left >= right)
	{
		return;
	}
	int index = GetMidIndex(a, left, right);
	Swap(&a[left], &a[index]);
	int begin = left, end = right;
	int pivot = begin;
	int key = a[begin];
	while (begin < end)
	{
		//右边找小,放到左边
		while (begin < end && a[end]>=key)
		{
			end--;
		}
		//找到放在左边的坑里
		a[pivot] = a[end];
		pivot = end;
		//左边找小,放到右边
		while (begin < end && a[begin] <= key)
		{
			begin++;
		}
		a[pivot] = a[begin];
		//找到放在右边的坑里
		pivot = begin;
	}
	//相遇了
	pivot = begin;
	a[pivot] = key;
	//分治策略,分区间将key左边和右边分别再次找关键key然后再次左小右大
	//直到剩下一个数或者没有数就达到了排序的目的
	QuickSort(a, left, pivot - 1);
	QuickSort(a, pivot +1,right);
}
int main()
{
	//int a[] = { 0.1,2,3,4,5,6,7,8,9 };
	int a[] = { 9,5,1,7,4,2,6,3,0,8 };
	int n = sizeof(a) / sizeof(a[0]);
	QuickSort(a, 0,n-1);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

📒补充知识点:>>1与/2的关系

  • n为非负数时,>> 1和/ 2的结果是一样的
  • n为负数且还是偶数时,>> 1和/ 2的结果是一样的
  • n为负数且还是奇数时,>> 1和/ 2的结果是不一样的

📒小区间优化:

🔑代码:

当每次调用越到最后递归调用越多,所以可以将最后几层递归调用消除掉,越到最后所排序的区间越小所以采用直接插入排序接可以了
对于直接插入排序可以回顾【算法】— 几分钟带你走进排序算法大门(上)

if (pivot - 1 - left > 10)
	{
		QuickSort(a, left, pivot - 1);
	}
	else
	{
		InsertSort(a + left, pivot - 1 - left + 1);
	}
	if (right-(pivot+1) > 10)
	{
		QuickSort(a, pivot + 1, right);
	}
	else
	{
		InsertSort(a + pivot+1, right-(pivot+1) + 1);
	}

😽总结

请添加图片描述
😽Ending,今天的直接选择排序+快排(中)的内容就到此结束啦~,如果后续想了解更多,就请关注我吧,一键三连哦 ~

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

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

相关文章

Vue3 Vite4 ElementPlus TS模板(含Vue-Router4+Pinia4)

引言 手动安装配置Vue3 ElementPlus模板比较繁琐&#xff0c;网上寻找一些模板不太符合自己预期&#xff0c;因此花点精力搭建一个符合自己需求的架子 采用最新的组件&#xff0c;版本如下&#xff1a; vite 4.3.9vite-plugin-mock 2.9.8vue 3.3.4pinia 2.1.3vue-router 4.2.2…

总结6种服务限流的实现方式

服务限流&#xff0c;是指通过控制请求的速率或次数来达到保护服务的目的&#xff0c;在微服务中&#xff0c;我们通常会将它和熔断、降级搭配在一起使用&#xff0c;来避免瞬时的大量请求对系统造成负荷&#xff0c;来达到保护服务平稳运行的目的。下面就来看一看常见的6种限流…

推荐常用的排序学习算法——BPR(贝叶斯个性化排序)

文章目录 1. 排序学习1.1 优势1.2 排序学习在推荐领域的作用1.3 排序学习设计思路1.3.1 单点法&#xff08;Pointwise&#xff09;1.3.2 配对法&#xff08;Pairwise&#xff09;1.3.3 列表法&#xff08;Listwise&#xff09; 2. BPR&#xff08;贝叶斯个性化推荐&#xff09;…

投票评选活动小程序的分享功能和背景音乐功能实现

投票评选活动小程序的分享功能和背景音乐功能实现 投票评选活动过程中&#xff0c;需要转发分享出去&#xff0c;实现投票的效果&#xff0c;那么就需要分享功能&#xff0c;不然怎么实现投票呢&#xff0c;其实这个是最具价值的功能之一。 而背景音乐播放功能&#xff0c;只…

路径规划算法:基于静电放电优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于静电放电优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于静电放电优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

Qt/GUI/布局/实现窗口折叠效果/且在操作时父窗口尺寸跟随变动

文章目录 概述无法resize到小尺寸可行方案其他方案 概述 本文旨在&#xff0c;实现如下所示的显示或隐藏 ‘附加选项’ 的效果&#xff0c;以折的不常用信息和操作项&#xff0c;减少普通用户负担&#xff0c;提升用户体验。在某些软件中此类窗口折叠效果&#xff0c;常用 “……

SpringCloud断路器

SpringCloud断路器 Hystrix 简介 hystrix对应的中文名字是“豪猪”&#xff0c;豪猪周身长满了刺&#xff0c;能保护自己不受天敌的伤害&#xff0c;代表了一种防御机制。 这与hystrix本身的功能不谋而合&#xff0c;因此Netflix团队将该框架命名为Hystrix&#xff0c;并使用…

2023最详细的接口测试用例设计教程,详细文档等你来拿

目录 一、接口测试流程 二、分析接口文档元素 三、如何设计接口测试用例 四、常用的接口测试用例覆盖方法 五、接口测试接口优先级 六、接口测试的设计思路分析 七、接口测试返回结果的比较 一、接口测试流程 1、需求讨论 2、需求评审 3、场景设计 4、数据准备 5、测试执…

sdf与timingCheck和后仿真

目录 1.Distributed delays 2.specify--endspecify 1.1 specify内部语法 2.sdf 2.1 sdf的格式 3.timingCheck和网表后仿真 4.关于负值delay sdf和 module 里面的specify--endspecify都可以对路径延时进行赋值和检查&#xff1b;HDL语言中的‘#()’也可以描述延时【叫做D…

没事千万别动生产服数据库 - 来自小菜鸟的忠告

阿里云官方参考文档 目录 背景一、环境部署二、目录规划三、操作步骤FAQ 背景 今天把一张 5500 多万条记录的表进行按年度拆分&#xff0c;本来打算将表数据拆分为 2020 年、2021 年、2022 年三张新表&#xff0c;提升原表查询效率&#xff0c;仅保留 2023 年数据。表拆分完毕…

【SpinalHDL快速入门】4.1、基本类型之Bool

Tips1&#xff1a; 由于SpinalHDL是基于Scala构建的&#xff0c;Scala本身自带类似变量Boolean&#xff0c;故在此要认准SpinalHDL中采用的是Bool而非Boolean&#xff1a; Bool&#xff08;大写的True和False&#xff09;&#xff1a;True表示1&#xff0c;False表示0Boolean&…

Vue3搭建

Vue3项目搭建全过程 vue create 项目名 选择手动吗&#xff0c;自定义安装 选择vue3 是否选择class风格组件 选择ts处理工具和css预处理器 Y 是否使用router的history模式 Y 选择css预处理语言 ;less 9.选择lint的检查规范 只使用EsLint官网推荐规范 使用EsLint官网推荐规…

MyBatis-plus(1)

基本概念: 一)开发效率也就是我们使用这款框架开发的速度快不快&#xff0c;是否简单好用易上手。从这个角度思考&#xff0c;每当我们需要编写一个SQL需求的时候&#xff0c;我们需要做几步 1)Mapper接口提供一个抽象方法 2)Mapper接口对应的映射配置文件提供对应的标签和SQL语…

论文笔记--LLaMA: Open and Efficient Foundation Language Models

论文笔记--LLaMA: Open and Efficient Foundation Language Models 1. 文章简介2. 文章概括3 文章重点技术3.1 数据集3.2 模型训练 4. 数值实验5. 文章亮点6. 原文传送门7. References 1. 文章简介 标题&#xff1a;LLaMA: Open and Efficient Foundation Language Models作者…

【自动化测试】--JUnit5

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启软件测试的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 前言 Junit5简介 什么是Junit5 JU…

tomcat和undertow、jetty、netty的区别

记录一下&#xff0c;最近发现的几个容器的区别 tomcat简介 Tomcat&#xff1a;免费开源&#xff0c;轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP 程序的首选。实际上Tomcat 部分是Apache 服务器的扩展&am…

十年历程:下定决心转向自动化测试/开发

目录 前言&#xff1a; 十年测试心路历程&#xff1a; 放弃了年薪二十万的offer&#xff0c;挑战自动化测试&#xff1a; 自动化测试心得&#xff1a; 自动化测试没用的误解&#xff1f; 关于测试开发 测试行业的现状 那么如何来全面的学习自动化测试呢&#xff1f; 前言&…

4.2 synchronized 解决方案

4.2 synchronized 解决方案 1、应用之互斥2、synchronized3、思考4、面向对象改进 1、应用之互斥 为了避免临界区的竞态条件发生&#xff0c;有多种手段可以达到目的。 阻塞式的解决方案&#xff1a;synchronized&#xff0c;Lock非阻塞式的解决方案&#xff1a;原子变量 本…

Linux网络基础 — 应用层

目录 应用层 再谈 "协议" 网络版计算器 HTTP协议 认识URL urlencode和urldecode HTTP协议格式 HTTP请求 HTTP响应 HTTP的方法 HTTP的状态码 HTTP常见Header 拓展知识&#xff08;了解&#xff09; 长链接 http周边会话保持 基本工具(http) 应用层 程序…

MOS管电源开关电路的缓启动功能是怎么实现的

先看一个电路&#xff1a; 其主要设计思路是使用MOS管来做一个开关&#xff0c;控制电源输出&#xff1b; 为什么选用MOS管&#xff1f; 这就涉及到MOS管的两个重要特性&#xff1a; 1.MOS管的导通电流大&#xff1b; 2.MOS管导通时内阻小&#xff0c;内部功耗低&#xff1b…