十大经典排序算法【快速了解】

news/2024/9/18 16:47:57/

文章目录

    • 一、算法分类
    • 二、经典排序算法总览
    • 三、算法复杂度
    • 四、代码实现


一、算法分类

十种常见排序算法可以分为两大类:

  • 比较类排序:
    • 通过比较来决定元素间的相对次序
    • 由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
  • 非比较类排序:
    • 不通过比较来决定元素间的相对次序
    • 它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
      在这里插入图片描述


二、经典排序算法总览

十大经典算法分别是:

  • 冒泡排序

    • 冒泡排序(Bubble Sort)是基于交换的排序
    • 每次遍历需要排序的元素,依次比较相邻的两个元素的大小,如果前一个元素大于后一个元素则两者交换,保证最后一个数字一定是最大的(假设按照从小到大排序
    • 最后一个元素已经排好序,下一轮只需要保证前面 n-1 个元素的顺序即可

    在这里插入图片描述

过程演示:待排序数组 {5, 4, 7, 1, 6, 2},升序排序

算法步骤:

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  2. 每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 重复步骤1~3,直到排序完成。

  • 选择排序
    • 前面说的冒泡排序是每一轮比较确定最后一个元素,中间过程不断地交换。
    • 而选择排序就是每次选择剩下的元素中最小的那个元素,与当前索引位置的元素交换,直到所有的索引位置都选择完成。

在这里插入图片描述
【算法步骤】n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  1. 初始状态:无序区为R[1..n],有序区为空;
  2. i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]R(i..n)
    • 该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换
    • 使R[1..i]R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区
  3. n-1趟结束,数组有序化了。

  • 插入排序
    • 选择排序是每次选择出最小的放到已经排好的数组后面
    • 而插入排序是依次选择一个元素,插入到前面已经排好序的数组中间,确保它处于正确的位置。
    • 当然,这是需要已经排好的顺序数组不断移动

在这里插入图片描述
【算法步骤】一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

  • 希尔排序
    • 希尔排序(Shell’s Sort)又称“缩小增量排序”(Diminishing Increment Sort),是插入排序的一种更高效的改进版本。
    • 插入排序的痛点在于不管是否是大部分有序,都会对元素进行比较,如果最小数在数组末尾,想要把它移动到数组的头部是比较费劲的。
    • 希尔排序是在数组中采用跳跃式分组,按照某个增量 gap 进行分组,分为若干组,每一组分别进行插入排序
      • 再逐步将增量 gap 缩小
      • 再每一组进行插入排序,循环这个过程,直到增量为 1。

在这里插入图片描述
【算法步骤】先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

  1. 选择一个增量序列t1,t2,…,tk,其中ti > tjtk = 1
  2. 按增量序列个数k,对序列进行k 趟排序;
  3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。
    • 仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

  • 快速排序
    • 快速排序比较有趣,选择数组的一个数作为基准数,一趟排序,将数组分割成为两部分
      • 一部分均小于/等于基准数
      • 另一部分大于/等于基准数。
    • 然后分别对基准数的左右两部分继续排序,直到数组有序。这体现了分而治之的思想,其中还应用到挖坑填数的策略。

在这里插入图片描述
【算法步骤】快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

  1. 从数列中挑出一个元素,称为 “基准”(pivot)
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
  3. 在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
  4. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

  • 归并排序
    • 前面的快速排序,体现了分治的思想,但是不够典型
    • 而归并排序则是非常典型的分治策略。归并的总体思想是先将数组分割,再分割
    • 分割到一个元素,然后再两两归并排序,做到局部有序,不断地归并,直到数组又被全部合起来。

在这里插入图片描述
算法步骤

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序
  3. 将两个排序好的子序列合并成一个最终的排序序列。

  • 排序
    • 桶排序,是指用多个桶存储元素,每个桶有一个存储范围
    • 先将元素按照范围放到各个桶中,每个桶中是一个子数组,然后再对每个子数组进行排序,最后合并子数组,成为最终有序的数组。
    • 这其实和计数排序很相似,只不过计数排序每个桶只有一个元素,而且桶存储的值为该元素出现的次数。

在这里插入图片描述
算法步骤

  1. 设置一个定量的数组当作空桶
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序
  4. 从不是空的桶里把排好序的数据拼接起来。

  • 排序
    • 堆排序,就是利用大顶堆或者小顶堆来设计的排序算法,是一种选择排序。
    • 堆是一种完全二叉树
      • 大顶堆:每个节点的数值都大于或者等于其左右孩子节点的数值。
      • 小顶堆:每个节点的数值都小于或者等于其左右孩子节点的数值。

在这里插入图片描述
算法步骤:

  1. 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  2. 堆顶元素R[1]最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n]
  3. 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)
  4. 不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

  • 计数排序
    • 计数排序,不是基于比较,而是基于计数
    • 比较适合元素数值相近且为整数的情况

在这里插入图片描述
算法步骤

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

  • 基数排序
    • 基数排序比较特殊,特殊在它只能用在整数(自然数)排序,而且不是基于比较的,
    • 其原理是将整数按照位分成不同的数字,按照每个数各位值逐步排序
    • 何为高位,比如 81,1 就是低位, 8 就是高位。
    • 分为高位优先和低位优先,先比较高位就是高位优先,先比较低位就是低位优先。

在这里插入图片描述

算法步骤:

  1. 取得数组中的最大数,并取得位数
  2. arr为原始数组,从最低位开始取每个位组成radix数组;
  3. radix进行计数排序(利用计数排序适用于小范围数的特点);


三、算法复杂度

常见排序算法复杂度
在这里插入图片描述
在这里插入图片描述

相关概念

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面
  • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面
  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数


四、代码实现

  • 冒泡排序(Bubble Sort)
function bubbleSort(arr) {var len = arr.length;for (var i = 0; i < len - 1; i++) {for (var j = 0; j < len - 1 - i; j++) {if (arr[j] > arr[j+1]) {        // 相邻元素两两对比var temp = arr[j+1];        // 元素交换arr[j+1] = arr[j];arr[j] = temp;}}}return arr;
}

在这里插入图片描述


  • 选择排序(Selection Sort)
function selectionSort(arr) {var len = arr.length;var minIndex, temp;for (var i = 0; i < len - 1; i++) {minIndex = i;for (var j = i + 1; j < len; j++) {if (arr[j] < arr[minIndex]) {     // 寻找最小的数minIndex = j;                 // 将最小数的索引保存}}temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}return arr;
} 

在这里插入图片描述


  • 插入排序(Insertion Sort)
function insertionSort(arr) {var len = arr.length;var preIndex, current;for (var i = 1; i < len; i++) {preIndex = i - 1;current = arr[i];while (preIndex >= 0 && arr[preIndex] > current) {arr[preIndex + 1] = arr[preIndex];preIndex--;}arr[preIndex + 1] = current;}return arr;
}

在这里插入图片描述


  • 希尔排序(Shell Sort)
function shellSort(arr) {var len = arr.length;for (var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行for (var i = gap; i < len; i++) {var j = i;var current = arr[i];while (j - gap >= 0 && current < arr[j - gap]) {arr[j] = arr[j - gap];j = j - gap;}arr[j] = current;}}return arr;
}

在这里插入图片描述


  • 归并排序(Merge Sort)
function mergeSort(arr) {var len = arr.length;if (len < 2) {return arr;}var middle = Math.floor(len / 2),left = arr.slice(0, middle),right = arr.slice(middle);return merge(mergeSort(left), mergeSort(right));
}function merge(left, right) {var result = [];while (left.length>0 && right.length>0) {if (left[0] <= right[0]) {result.push(left.shift());} else {result.push(right.shift());}}while (left.length)result.push(left.shift());while (right.length)result.push(right.shift());return result;
}

在这里插入图片描述


  • 快速排序(Quick Sort)
function quickSort(arr, left, right) {var len = arr.length,partitionIndex,left = typeof left != 'number' ? 0 : left,right = typeof right != 'number' ? len - 1 : right;if (left < right) {partitionIndex = partition(arr, left, right);quickSort(arr, left, partitionIndex-1);quickSort(arr, partitionIndex+1, right);}return arr;
}function partition(arr, left ,right) {     // 分区操作var pivot = left,                      // 设定基准值(pivot)index = pivot + 1;for (var i = index; i <= right; i++) {if (arr[i] < arr[pivot]) {swap(arr, i, index);index++;}       }swap(arr, pivot, index - 1);return index-1;
}function swap(arr, i, j) {var temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}

在这里插入图片描述


  • 堆排序(Heap Sort)
var len;    // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量function buildMaxHeap(arr) {   // 建立大顶堆len = arr.length;for (var i = Math.floor(len/2); i >= 0; i--) {heapify(arr, i);}
}function heapify(arr, i) {     // 堆调整var left = 2 * i + 1,right = 2 * i + 2,largest = i;if (left < len && arr[left] > arr[largest]) {largest = left;}if (right < len && arr[right] > arr[largest]) {largest = right;}if (largest != i) {swap(arr, i, largest);heapify(arr, largest);}
}function swap(arr, i, j) {var temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}function heapSort(arr) {buildMaxHeap(arr);for (var i = arr.length - 1; i > 0; i--) {swap(arr, 0, i);len--;heapify(arr, 0);}return arr;
}

在这里插入图片描述


  • 计数排序(Counting Sort)
function countingSort(arr, maxValue) {var bucket = new Array(maxValue + 1),sortedIndex = 0;arrLen = arr.length,bucketLen = maxValue + 1;for (var i = 0; i < arrLen; i++) {if (!bucket[arr[i]]) {bucket[arr[i]] = 0;}bucket[arr[i]]++;}for (var j = 0; j < bucketLen; j++) {while(bucket[j] > 0) {arr[sortedIndex++] = j;bucket[j]--;}}return arr;
}

在这里插入图片描述


  • 桶排序(Bucket Sort)
function bucketSort(arr, bucketSize) {if (arr.length === 0) {return arr;}var i;var minValue = arr[0];var maxValue = arr[0];for (i = 1; i < arr.length; i++) {if (arr[i] < minValue) {minValue = arr[i];                // 输入数据的最小值} else if (arr[i] > maxValue) {maxValue = arr[i];                // 输入数据的最大值}}// 桶的初始化var DEFAULT_BUCKET_SIZE = 5;            // 设置桶的默认数量为5bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;  var buckets = new Array(bucketCount);for (i = 0; i < buckets.length; i++) {buckets[i] = [];}// 利用映射函数将数据分配到各个桶中for (i = 0; i < arr.length; i++) {buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);}arr.length = 0;for (i = 0; i < buckets.length; i++) {insertionSort(buckets[i]);                      // 对每个桶进行排序,这里使用了插入排序for (var j = 0; j < buckets[i].length; j++) {arr.push(buckets[i][j]);                     }}return arr;
}

在这里插入图片描述


  • 基数排序(Radix Sort)
var counter = [];
function radixSort(arr, maxDigit) {var mod = 10;var dev = 1;for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {for(var j = 0; j < arr.length; j++) {var bucket = parseInt((arr[j] % mod) / dev);if(counter[bucket]==null) {counter[bucket] = [];}counter[bucket].push(arr[j]);}var pos = 0;for(var j = 0; j < counter.length; j++) {var value = null;if(counter[j]!=null) {while ((value = counter[j].shift()) != null) {arr[pos++] = value;}}}}return arr;
}

在这里插入图片描述


http://www.ppmy.cn/news/30007.html

相关文章

xgboost: 分割查找算法:贪婪算法、分桶算法

1、Basic Exact Greedy Algorithm 树学习的关键问题之一是找到最好的分割&#xff0c;如Eq(7)所示。 贪婪算法:分割查找算法枚举所有特征上的所有可能的分割。精确的贪婪算法如Alg. 1所示。为了高效地完成这一任务&#xff0c;算法必须首先根据特征值对数据进行排序&#xff…

配置本地 python GEE、geemap环境

1.安装anconda 百度搜索anconda清华镜像&#xff0c;从清华镜像中选择最新的anconda安装包&#xff0c;国内镜像网站下载速度较快&#xff0c;如果从国外官网下载速度相当慢&#xff0c;详细安装教程请参考&#xff1a; anconda安装教程https://blog.csdn.net/lwbCUMT/article…

MyBatis高频面试专题

一、介绍下MyBatis中的工作原理 1。介绍MyBatis的基本情况&#xff1a;ORM 2。原理&#xff1a; MyBatis框架的初始化操作处理SQL请求的流程 1.系统启动的时候会加载解析全局配置文件和对应映射文件。加载解析的相关信息存储在 Configuration 对象 Testpublic void test1(…

JavaScript(JS)

一、三种引入方式&#xff1a; 1、内部js 通过script标签嵌入到html里面 <script>alert(hello);</script> 2、外部js 写成一个单独的.js文件&#xff0c;让html引入进来 <script src"app.js"></script> 3、行内js 直接写到html内部 &…

SpringMVC文件上传、下载、国际化配置

Java知识点总结&#xff1a;想看的可以从这里进入 目录3.6、文件上传、下载3.6.1、文件上传3.6.2、文件下载3.7、国际化配置3.6、文件上传、下载 3.6.1、文件上传 form 表单想要具有文件上传功能&#xff0c;其必须满足以下 3 个条件。 form 表单的 method 属性必须设置为 p…

最近一年我都干了什么——反思!!

过去一年不管是学习方式还是心态上都和以往有了许多不同的地方&#xff0c;比较昏昏沉沉。最近慢慢找到状态了&#xff0c;就想赶紧记录下来。 学习 在学习新技术的过程中开始飘了&#xff0c;总感觉有了一些开发经验后就觉得什么都不用记&#xff0c;知道思路就行遇到了现场百…

Java高效率复习-SpringMVC[SpringMVC-2]

SpringMVC获取请求参数 SpringMVC获取请求参数的两种方式↓ 通过ServletAPI获取请求参数 将HttpServletRequest作为控制器方法的形参&#xff0c;此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 通过request的API——getParameter(String s)方法来获取…

2023王道考研数据结构笔记第四章串

第四章 串 4.1 串的定义 4.1.1 串的相关概念 串&#xff1a;即字符串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列。一般记为S‘a1a2…an’ (n>0) 其中S是串名&#xff0c;单引号&#xff08;注&#xff1a;有的地方用双引号&#xff0c;如Java、C&am…

用Python Flask为女朋友做一个简单的网站(附可运行的源码)

&#x1f31f;所属专栏&#xff1a;献给榕榕&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该专栏系为女友准备的&#xff0c;里面会不定时发一些讨好她的技术作品&#xff0c;感兴趣的小伙伴可以关注一下~&#x1f449;文章简介…

【数据结构初阶】详解“树”

目录 前言 1.树概念及结构 &#xff08;1&#xff09;树的概念 &#xff08;2&#xff09;树的名词介绍 &#xff08;3&#xff09;树的表示 ​编辑 2.二叉树概念及结构 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;特殊的二叉树 &#xff08;3&#xff0…

[深入理解SSD系列综述 1.5] SSD固态硬盘参数图文解析_选购固态硬盘就像买衣服?

版权声明&#xff1a;付费作品&#xff0c;未经许可&#xff0c;不可转载前言SSD &#xff08;Solid State Drive&#xff09;&#xff0c;即固态硬盘&#xff0c;通常是一种以半导体闪存&#xff08;NAND Flash&#xff09;作为介质的存储设备。SSD 以半导体作为介质存储数据&…

UNIX编程--Makefile入门

Makefile 文件命名和规则 文件命名 makefile 或者 Makefile Makefile 规则 一个 Makefile 文件中可以有一个或者多个规则目标 ... &#xff1a; 依赖 ...命令 (shell 命令)...目标&#xff1a;最终要生成的文件&#xff0c;伪目标除外依赖&#xff1a;生成目标所需的文件或是目…

【剧前爆米花--爪哇岛寻宝】MySQL中索引和事务

作者&#xff1a;困了电视剧 专栏&#xff1a;《MySQL数据库》 文章分布&#xff1a;这是一篇关于Java中异常类的文章&#xff0c;在本篇文章中详细讲解了异常的使用逻辑和底层的执行过程&#xff0c;如有疏漏&#xff0c;欢迎大佬指正&#xff01; 目录 索引 用法 底层逻辑…

HCIP第一个实验

实验要求与实验拓扑子网划分分析将骨干链路看成一个整体&#xff0c;路由器后的2个环回地址先看成一个&#xff0c;最后再进行拆分。计算得出&#xff0c;一共需要划分为6个子网段&#xff0c;取三位。再将每一条网段&#xff0c;按照题目要求进行划分最后完成子网划分。子网划…

synchronized和lock的区别

区别&#xff1a; 1.synchronized是关键字,Lock是接口; 2.synchronized是隐式的加锁,lock是显式的加锁; 3.synchronized可以作用于方法上,lock只能作用于方法块; 4.synchronized底层采用的是objectMonitor,lock采用的AQS; 5.synchronized是阻塞式加锁,lock是非阻塞式加锁支…

【0177】Linux中POSIX信号量实现机制

文章目录 1. 信号量概念1.1 信号量类比1.2 重要的观察1.3 信号量分类2. POSIX与System V信号量3. 信号量API4. 代码演示5. 信号量内核实现1. 信号量概念 在计算机科学中,信号量(semaphores )是一种变量或抽象数据类型,用于控制多个进程对公共资源的访问,并避免并发系统(如…

gazebo仿真轨迹规划+跟踪(不在move_base框架下)

以Tianbot为例子&#xff0c;开源代码如下&#xff1a; https://github.com/tianbot/tianbot_mini GitHub - tianbot/abc_swarm: Ant Bee Cooperative Swarm, indicating air-ground cooperation. This repository is for Tianbot Mini and RoboMaster TT swarm kit. 1.在…

借助CatGPT让turtlesim小乌龟画曲线

注意这里是CatGPT&#xff0c;不等同OpenAI的ChatGPT&#xff0c;但是用起来十分方便&#xff0c;效果也还行。详细说明ROS机器人turtlesim绘制曲线需要注意哪些ROS机器人turtlesim绘制曲线需要注意以下几点&#xff1a;绘制曲线前需要设置好turtlesim的初始位置和方向&#xf…

机器学习、数据挖掘和统计模式识别学习(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 机器学习是让计算机在没有明确编程的情况下采取行动的科学。在过去的十年中&#xff0c;机器学习为我们提供了自动驾驶汽车&…

蓝桥杯第十四届校内赛(第三期) C/C++ B组

一、填空题 &#xff08;一&#xff09;最小的十六进制 问题描述   请找到一个大于 2022 的最小数&#xff0c;这个数转换成十六进制之后&#xff0c;所有的数位&#xff08;不含前导 0&#xff09;都为字母&#xff08;A 到 F&#xff09;。   请将这个数的十进制形式作…