详解排序几大算法

一、插入排序

基本思想:

  • 直接插入排序是一种简单的插入排序算法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

步骤:

当插入第n个元素的时候前面的arr[0]到arr[n-1]都已经排序好了,此时我们将arr[n]与前面的相比较,假设我们需要一个升序的数组,那当arr[n]小于所比较的这个数的时候,就跟其交换位置,原来位置上的元素顺序后移。

动图演示:
在这里插入图片描述
代码实现:

void InsertSort(int* a, int n)
{
   for (int i = 0; i < n-1; i++)
   {
      //记录最后一个元素的下标
      int end = i ;
      //待排序的数据
      int tmp = a[end + 1];
      while (end >= 0)
      {
         //比插入的数大就往后
         if (a[end] > tmp)
         {
            a[end + 1] = a[end];
            end--;
         }
         //比插入的数小就跳出循环
         else
         {
            break;
         }
        }
      a[end + 1] = tmp;
    }
}

直接插入排序的特性:

  • 元素集合越接近有序,直接插入排序算法的时间效率就越高
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)

二、希尔排序

基本思想:

  • 先选定一个整数(通常是gap = n/3+1),把待排序文件所有记录成各组,所有的距离相等的记录在同一组内,并对每一组内的记录进行排序,然后gap = gap/3+1得到下一个整数,再将数组分成各组,进行插入排序,当gap = 1时,将相当于直接插入排序。
  • 所有我们会发现希尔排序是直接插入算法的基础上进行改进而来,但是它的效率要高于直接插入排序。
    在这里插入图片描述

动图演示:
在这里插入图片描述

希尔排序的特性:

  • 希尔排序是对直接排序的优化
  • 当gap > 1时都时预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了。

代码实现:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap>1)
	{
		gap = gap / 3 + 1;
		//单趟排序
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

希尔排序的时间复杂度:O(n^3/2)
希尔排序的空间复杂度:O(1)

三、选择排序

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

直接选择排序步骤:

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

动图演示:
在这里插入图片描述
代码实现:

void SelectSort(int* a, int n)
{
   int begin = 0, end = n - 1;
   while (begin < end)
   {
      int mini = begin, maxi = begin;
      for (int i = begin; i <= end; i++)
      {
         if (a[i] > a[maxi])
         {
             maxi = i;
         }
         if (a[i] < a[mini])
         {
             mini = i;
         }
      }
      if (begin == maxi)
      {
          maxi = mini;
      }
      swap(&a[mini], &a[begin]);
      swap(&a[maxi], &a[end]);
      ++begin;
      --end;
   }
}

直接选择排序的时间复杂度:O(N^2)
直接选择排序的空间复杂度:O(1)

四、堆排序

堆排序是指利用堆积树这种数据结构所设计的一种排序算法,它是选择排序的一种。
我们需要注意的是排升序要建大堆,排降序建小堆。
点这里在二叉树里面实现了堆排序

五、冒泡排序

动图演示:
在这里插入图片描述
代码实现:

//冒泡排序
void BubbleSort(int* arr, int n)
{
	int end = n;
	while (end)
	{
		int flag = 0;
		for (int i = 1; i < end; ++i)
		{
			if (arr[i - 1] > arr[i])
			{
				int tmp = arr[i];
				arr[i] = arr[i - 1];
				arr[i - 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
		--end;
	}
}

冒泡排序的时间复杂度:O(N^2)
冒泡排序的空间复杂度:O(1)

六、快速排序

基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

hoare版本

算法思想:
1.创建左右指针,确定基准值
2.从右向左找出比基准值小的数据,从左往右找出比基准值大的数据,左右指针数据交换,进入下一次循环

步骤:

我们选定一个key(一般是最右边的数,或者最左边的数)接着我们需要定义一个begin和一个end,begin是从左往右走,end是右往左走。在它们走的过程中,当begin遇到比key大的数据的时候停下来,end继续走,指导遇到一个小于key的数时,两者交换数据,最后直到它们相遇,相遇点的数据和key的数据交换。

动图演示:
在这里插入图片描述

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int left = begin;
	int right = end;
	//选左边为key
	int keyi = begin;
	while (begin < end)
	{
		while (a[end] >= a[keyi] && begin < end)
		{
			--end;
		}
		//左边选大
		while (a[begin] <= a[keyi] && begin < end)
		{
			++begin;
		}
		//小的换到右边,大的换到左边
		swap(&a[begin], &a[end]);
	}
	swap(&a[keyi], &a[end]);
	keyi = end;
	QuickSort(a, left, keyi - 1);
	QuickSort(a,keyi + 1,right);
}

挖坑法

基本思路:
创建左右指针,首先从右往左找出比基准值小的数据,后将其放在左边坑中,当前的位置就变为新的坑,然后在从左往右找出比基准值大的数据,找到后将其放进右边坑中,当前位置变为新的坑,当结束循环的时候将最开始储存的分界值放进当前的坑中,返回当前坑的下标。

步骤:

选出一个数据(可以是最左也可以是最右,一般情况下)存放在key变量中,在这个数据位置形成一个坑,紧接着我们定义一个Left和一个Right,Left从左往右走,Right从右往左走。
需要注意的是如果最左边挖坑,则需要Right先走;反之,则Left先走。

动图演示:
在这里插入图片描述
代码实现:

void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
	   return;
	}
	int left = begin,right = end;
	int key = a[begin];
	while (begin < end)
	{
		//找小
		while (a[end] >= key && begin < end)
		{
			--end;
		}
		//小的放到左边的坑里
		a[begin] = a[end];
		//找大
		while (a[begin] <= key && begin < end)
		{
			++begin;
		}
		//大的放到右边的坑里
		a[end] = a[begin];
	}
	a[begin] = key;
	int keyi = begin;
	QuickSort1(a, left, keyi - 1);
	QuickSort1(a, keyi + 1, right);
}

lomuto前后指针

基本思路:
创建前后指针从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。

步骤:

选出一个key,起始时prev指针指向序列开头,cur指针指向prev+1的位置。若cur指向的数据小于key,则prev先向后移动一位,然后将prev和cur指针指向的数据交换,cur++;若cur指向的数据大于key,则cur指向直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的数据交换即可。

在这里插入图片描述
代码实现:

void QuickSort2(int* arr, int begin, int end)
{
	if (begin >= end)
	{
	   return;
	}
	int cur = begin, prev = begin - 1;
	int keyi = end;
	while (cur != keyi)
	{
		if (arr[cur] < arr[keyi] && ++prev != cur)
		{
			swap(&arr[cur], &arr[prev]);
		}
		++cur;
	}
	swap(&arr[++prev],&arr[keyi]);
	keyi = prev;
	QuickSort2(arr, begin, keyi - 1);
	QuickSort2(arr, keyi + 1, end);

}

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

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

相关文章

ARMS 用户体验监控正式发布原生鸿蒙应用 SDK

作者&#xff1a;杨兰馨&#xff08;楠瑆&#xff09; 背景 2024 年 10 月 22 日&#xff0c;华为正式发布了原生鸿蒙操作系统&#xff08;HarmonyOS NEXT&#xff09;。原生鸿蒙实现了系统底座全部自研&#xff0c;系统的流畅度、性能、安全特性等方面显著提升&#xff0c;也…

嵌入式驱动开发详解17(CAN驱动开发)

文章目录 前言CAN简介CAN收发器CAN协议讲解电气特性传输协议数据帧遥控帧错误帧过载帧帧间隔 同步矫正 CAN控制器CAN控制器模式CAN接收器CAN波特率 CAN设备树分析CAN测试后续参考文献 前言 该专栏主要是讲解嵌入式相关的驱动开发&#xff0c;但是由于部分模块的驱动框架过于复…

计算机游戏运行时常见问题解析:d3dx9_43.dll丢失的真相与修复指南

游戏运行时d3dx9_43.dll缺失问题全解析 在计算机游戏的探险之旅中&#xff0c;d3dx9_43.dll文件缺失常成为玩家的绊脚石。此DLL文件是DirectX 9的关键组件&#xff0c;对图形渲染至关重要。以下&#xff0c;我们将深入剖析其丢失原因&#xff0c;并提供精简有效的修复策略。 …

CSS(13):2D

一.2D转换之移动translate 2D移动是2D转换里面的一种功能&#xff0c;可以改变元素在页面中的位置&#xff0c;类似定位。 transform:translate(x,y);&#xff08;里面可以用到参数%&#xff0c;是相对于自身宽度和高度来计算的&#xff09; transform:translateX(n); tran…

AI 赋能:医学科研审稿邀请的优化之道

在医学科研这座宏伟的知识殿堂中&#xff0c;审稿邀请是保障学术成果质量的关键环节&#xff0c;审稿邀请犹如一扇关键之门&#xff0c;连接着科研成果与专业评审&#xff0c;决定着学术智慧的传承与升华。如今&#xff0c;AI 技术恰似一把神奇的钥匙&#xff0c;悄然插入这扇门…

如何搭建Hexo博客,并发布到github上

1、安装好git 2、安装好npm、node 3、切换npm的源&#xff0c;现在阿里的cnpm不行了&#xff0c;要切换成新的&#xff1a; npm config set registry https://registry.npmmirror.com npm config get registry4、安装hexo-cli npm install -g hexo-cli查看是否安装成功&#…

React,Antd实现文本输入框话题添加及删除的完整功能解决方案

最终效果就是实现该输入框: 添加话题时,话题自动插入到输入框前面多文本输入框左侧间距为话题的宽度多行文本时,第二行紧接开头渲染删除文本时,如果删除到话题,再次删除,话题被删除首先构造div结构const [hashtag, setHashtag] = useState(""); // 话题内容con…

Apache服务器配置:从小白到高手的飞跃

本节目录&#xff1a; Web服务器概述 Apache服务器及安装 配置 作业 Web服务:互联网的心脏 想象一下&#xff0c;如果没有Web服务器&#xff0c;我们就不能浏览网页&#xff0c;不能在线购物&#xff0c;不能看视频&#xff0c;不能做很多事情。Web服务器就是互联网的心脏&…

基于SpringBoot的滑雪场管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

bean创建源码

去字节面试&#xff0c;直接让人出门左拐&#xff1a;Bean 生命周期都不知道&#xff01; spring启动创建bean流程 下面就接上了 bean生命周期 doGetBean Object sharedInstance this.getSingleton(beanName); sharedInstance this.getSingleton(beanName, new ObjectF…

【HarmonyOS】鸿蒙获取appIdentifier,Identifier

【HarmonyOS】鸿蒙获取appIdentifier&#xff0c;Identifier 一、前言 三方后台需要填写的所谓appIdentifier&#xff0c;Identifier信息&#xff0c;其实对应鸿蒙应用的appID。 二、解决方案&#xff1a; 注意&#xff0c;模拟器获取data.signatureInfo.appIndentifer为空…

在Linux的嵌入式开发中,如何确定要操作的帧缓冲设备是第几个实例?即是fb0还是fb1还是fb2...

方法汇总 在实际编写程序时&#xff0c;要确定操作的帧缓冲设备&#xff08;如 /dev/fb0、/dev/fb1 等&#xff09;&#xff0c;通常需要结合系统环境和硬件配置。以下是一些常见的方法&#xff0c;帮助你确定需要打开的帧缓冲设备实例&#xff1a; 1. 检查系统设备文件 查看…

The Past, Present and Future of Apache Flink

摘要&#xff1a;本文整理自阿里云开源大数据负责人王峰&#xff08;莫问&#xff09;在 Flink Forward Asia 2024上海站主论坛开场的分享&#xff0c;今年正值Flink开源项目诞生的第10周年&#xff0c;借此时机&#xff0c;王峰回顾了Flink在过去10年的发展历程以及 Flink社区…

自动驾驶控制与规划——Project 2: 车辆横向控制

目录 零、任务介绍一、环境配置二、算法三、代码实现四、效果展示 零、任务介绍 补全src/ros-bridge/carla_shenlan_projects/carla_shenlan_stanley_pid_controller/src/stanley_controller.cpp中的TODO部分。 一、环境配置 上一次作业中没有配置docker使用gpu&#xff0c;…

FFmpeg库之ffplay

文章目录 FFmpeg环境搭建ffplay使用通用选项视频选项音频选项快捷键使用滤镜直播拉流 FFmpeg环境搭建 FFmpeg官网 FFmpeg环境搭建 我这里用的是cmake配置&#xff0c;mingw编译&#xff0c;不用移动文件夹 CMakeLists.txt cmake_minimum_required ( VERSION 3.16 )project…

jenkins pipeline打包流程

Jenkins Pipeline 是 Jenkins 提供的一种用于持续集成和持续交付&#xff08;CI/CD&#xff09;的脚本化流程工具。它允许你通过编写一个 Jenkinsfile 文件来定义整个构建、测试和部署的流程。本文介绍打包springcloud项目&#xff0c;react项目为docker镜像 文章目录 1.项目结…

【LC】876. 链表的中间结点

题目描述&#xff1a; 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中间结点…

WEB开发: Node.js路由之由浅入深- 即拿即用完整版

前面我们一起学习了Node.js路由之由浅入深&#xff0c;基本了解并熟悉了Node.js的路由实现。 现在我们来一个综合完整版&#xff0c;让这个路由模块即拿即用&#xff0c;也就是下载运行就可用&#xff0c;并可以轻松地自行增加路由&#xff0c;无需去繁琐地修改路由配置&#…

就业相关(硕士)

一、嵌入式 1.机器人行业 1.1 大致情况 要做机器人行业&#xff0c;主要技术栈是运动控制、深度学习、强化学习、具身智能等&#xff0c;主要求职方向有运动控制算法工程师和机器人算法工程师等等。大致薪资在30w到50w不等&#xff0c;主要看方向&#xff08;双211&#xff…

C++编程:使用树莓派Pico制作光控小夜灯

在智能家居系统中,光控设备通过环境光强度的变化自动调节设备的状态,具有广泛的应用。常见的应用场景包括自动开关灯、调节LED亮度等。本项目基于树莓派Pico开发板,通过光敏电阻检测环境光强度,并利用PWM调光控制LED亮度,实现一个简单的光控小夜灯。本文将深入解析光敏电阻…