[Collection与数据结构] 七大排序算法汇总

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(93平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

1.概述

1.1 概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

1.2 常见应用

  1. 高校排行
    在这里插入图片描述
  2. 商品排序
    在这里插入图片描述

2. 常见排序

2.1 直接插入排序

从序列的第二个位置开始为基准,把前面的一个元素依次与下一个元素比较,前一个元素大于后一个元素(升序),则交换,如果碰到小于的,则证明前几个元素已经有序了,因为是从第二个元素开始进行插入排序的,直接break掉.
动态演示:
在这里插入图片描述

/*** 插入排序* @param array 传入的数组*/public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {//基准从1开始for (int j = i-1; j >= 0; j--) {if (array[j] > array[j+1]){//把前面的元素依次比较swap(j,j+1,array);}else {break;//遇到不符合条件的直接break}}}}private static void swap(int a,int b,int[] array){int tmp = array[a];array[a] = array[b];array[b] = tmp;}

特性总结:

  1. 元素越趋于有序,插入排序越快,因为遇到比较不符合条件的直接回break掉.
  2. 时间复杂度:两层循环,O(n2)
  3. 空间复杂度:只在数组本身上进行了操作,O(1)
  4. 稳定性:稳定

2.2 希尔排序

希尔排序实际上是直接插入排序的一种升级版,先把序列中的元素按照一定的间隔个数分成多个组,之后把各个组中的元素进行排序,之后缩小缩小间隔个数,也就是缩小组数,增大各个组中的元素个数,再次排序,直到元素之间的间隔小于1为止.
动态演示:
在这里插入图片描述

 /*** 希尔排序,本质上是插入排序的一种升级版* @param array*/public static void shellSort(int[] array){int gap = array.length;while (gap > 1){//数据间隙大于1时继续希尔排序gap = gap/2;//缩小数据间隙shell(array,gap);}}private static void shell(int[] array,int gap){for (int i = gap; i < array.length; i++) {//针对每一组数据进行插入排序for (int j = i-gap; j >= 0; j-=gap) {//只不过每次的步数变成了gapif (array[j] > array[j+gap]){swap(j,j+gap,array);}else {break;}}}}

其实我们观察上述代码,我们为什么说他是直接插入排序的升级版,是因为,它相比直接插入排序只是改变了每次走的步数.

特性总结:

  1. 希尔排序是针对直接插入排序的优化
  2. 当gap>1时都是预排序,目的是让数据越来越接近有序.当gap==1的时候,就是直接插入排序,这时数据已经趋于有序了,直接插入排序就会特别快.
  3. 时间复杂度:目前仍然存在争议,一般认为是O(n1.25~1.6n1.25)
  4. 稳定性:不稳定

2.3 选择排序

从第一个元素开始,寻找比基准元素小的元素,下标保存到tmp中,之后继续寻找比tmp小的元素,直到找到最小的元素为止,之后交换基准元素和tmp下标的元素,基准后移,一些此类推.
动态演示:

在这里插入图片描述

/*** 选择排序* @param array*/public static void selectSort(int[] array){for (int i = 0; i < array.length; i++) {int min = i;//最小值的下标赋值为i,如果没有找到比min下标小的,说明i就是最小的int j = i+1;for (; j < array.length; j++) {if (array[min] > array[j]){min = j;}}swap(min,i,array);}}

特性总结:

  1. 时间复杂度:O(n2)
  2. 空间复杂度:O(1)
  3. 稳定性:不稳定
  4. 这种排序方法虽然好理解,但是由于效率太低,日常开发中很少用.

2.4 冒泡排序

之所以叫冒泡排序,是因为就像水中的气泡一样,一点一点地浮出水面.先确定排序的趟数(下标最大值),就是外层循环,再确定排序交换的次数(下标最大值-i),就是内层循环,遇到比自己小的就交换,这样最大值就像冒泡一样排到了最后.
优化: 如果发现在内层循环遍历的时候,一次都没有交换,说明已经有序,我们通过flag来标记.
动态演示:
在这里插入图片描述

/*** 冒泡排序* @param array*/public static void bubbleSort(int[] array){for (int i = 0; i < array.length-1; i++) {//如果遍历到最后一个元素,就没有必要比较了,就要-1boolean flag = true;for (int j = 0; j < array.length-i-1; j++) {//这里必须-1,因为如果不-1,就会遍历到最后一个元素,j+1就会越界if (array[j] > array[j+1]){swap(j+1,j,array);flag = false;//发生了交换.说明不有序,设置为false}}if (flag){//如果flag == true,说明没有发生交换,整个数组已经有序return;//直接返回}}}

特性总结:

  1. 时间复杂度:O(n2)
  2. 空间复杂度:O(1)
  3. 稳定性:稳定

2.5 堆排序

首先如果是升序的话,先创建一个大根堆,让end指向最后一个元素为什么不创建小根堆呢?是因为小根堆只可以保证父节点是最小的,而不可以保证子节点是从小到大排列的.之后把堆顶元素和堆尾元素交换,就把整个堆的最大元素排到了最后.之后继续把该堆向下调整为大根堆,之后让end向前移动
动态演示:
在这里插入图片描述

/*** 堆排序,从小到大排序,创建大根堆* @param array*/public static void heapSort(int[] array){int end = array.length-1;createBigHeap(array);//先创建大根堆while (end > 0){swap(0,end,array);//交换堆顶元素和最后一个元素,把堆顶最大的元素放在最后end--;//end向前移动shiftDown(0,end,array);//再次向下调整为大根堆//先向下调整,再--,因为向下调整的时候,while循环没有等号,如果传入end-1,倒数第二个结点就调整不到}}private static void createBigHeap(int[] array){for (int i = (array.length-1-1)/2; i >= 0 ; i--) {shiftDown(i,array.length-1,array);}}private static void shiftDown(int parent,int end,int[] array){int child = parent*2+1;while (child <= end){if (child+1 < end && array[child] < array[child+1]) {child++;}if (array[child] > array[parent]){swap(parent,child,array);parent = child;child = child*2+1;}else {break;}}}

特点总结:

  1. 堆排序适用于海量数据排序,数据越多,堆排序效率越高.
  2. 时间复杂度:复杂度主要集中于向下调整中,元素个数x树的高度,O(n*log2n)
  3. 空间复杂度:没有额外空间,O(1)
  4. 稳定性:不稳定

2.6 快速排序(重点)

之所以叫快速排序,说明它是真的快.快速排序整体思想为分治思想,就是把通过递归的思想把整个数组通过一定的方法切成二叉树的形式,之后对每科子树进行排序.
快速排序的方法有两种,一种是霍尔法,一种是挖坑法.

2.6.1 霍尔法

分别定义start和end指向数组首和尾,选取第一个元素为key,之后先让end向前移动,找到比key小的元素,之后再让start向后移动,找到比key大的元素,之后交换end和start下标的值,以此类推.直到start和end相遇,把相遇位置的元素和key交换,之后以相遇点分治,递归以此类推.
动态演示:
在这里插入图片描述

/*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}swap(left,mid,array);//把区间内的中间值放在头int pos = position(left,right,array);//通过霍尔法找到分治点quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}/*** 霍尔法找到相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position(int start,int end,int[] array){int tmp = array[start];int i = start;//提前准备比较数据的下标while (start < end){while (start < end && array[end] >= tmp){//先走后面,注意加上等号end--;}while (start < end && array[start] <= tmp){//加前一个条件是为了防止出现已经排好序的极端情况start++;}swap(start,end,array);//当在前面找到比tmp大的数据,在后面找到比tmp大的数据,就交换}swap(i,start,array);//当start和end相遇的时候,交换数列头元素和相遇地方的元素return start;//返回相遇的点,以相遇的点分制}

2.6.2 挖坑法

先把key(首)元素下标放入tmp中,让end向前移动,找到比tmp小的元素,填上key元素的坑,之后让start向后移动找到比tmp大的元素,填上上一个end的坑.以此类推,最后让tmp填上start和end相遇位置的坑.之后分治,递归重复上述操作.

 /*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}swap(left,mid,array);//把区间内的中间值放在头int pos = position2(left,right,array);quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}/***挖坑法找相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position2(int start,int end,int[] array){int tmp = array[start];while (start < end){if (start < end && array[end] >= tmp){//先走后面,否则下面没法填坑end--;}array[start] = array[end];if (start < end && array[start] <= tmp){start++;}array[end] = array[start];}array[start] = tmp;return start;}

2.6.3 快速排序优化

  • 由于快速排序越来越趋向有序,所以我们可以以分治之后数组的长度作为基准,当小于一定的值之后,就可以对分治区域使用插入排序.
  • 为了防止出现二叉树单分支的情况而降低效率,所以我们需要在分治区间找到中间大小的元素,与首元素交换.

快速排序最终版:

/*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}//优化2:在霍尔法或者挖坑法使得数组不断趋于有序时,我们就可以发挥直接插入排序的优势//越趋于有序,越快if (right-left < 7){insertSort2(left,right,array);}//优化1:寻找中间大小的数字,防止出现单分支情况导致效率太低int mid = findmid(array,left,right);swap(left,mid,array);//把区间内的中间值放在头int pos = position(left,right,array);quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}private static void insertSort2(int start,int end,int[] array){for (int i = start+1; i <= end; i++) {for (int j = i-1; j < end; j++) {if (array[j] > array[j+1]){swap(j,j+1,array);}else {break;}}}}//比较区间内的开始,中间,结束位置的值private static int findmid(int[] array,int start,int end){int mid = (start+end)/2;//区间内的中间位置//先比较左右开始和结束的值if (array[start] < array[end]){if (array[end] < array[mid]){//mid插入它们两个之间的三个空隙return end;} else if (array[mid] > array[start]) {return mid;}else {return start;}}else {if (array[start] < array[mid]){return start;} else if (array[end] < array[mid]) {return mid;}else {return end;}}}/*** 霍尔法找到相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position(int start,int end,int[] array){int tmp = array[start];int i = start;//提前准备比较数据的下标while (start < end){while (start < end && array[end] >= tmp){//先走后面,注意加上等号end--;}while (start < end && array[start] <= tmp){//加前一个条件是为了防止出现已经排好序的极端情况start++;}swap(start,end,array);//当在前面找到比tmp大的数据,在后面找到比tmp大的数据,就交换}swap(i,start,array);//当start和end相遇的时候,交换数列头元素和相遇地方的元素return start;//返回相遇的点,以相遇的点分制}/***挖坑法找相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position2(int start,int end,int[] array){int tmp = array[start];while (start < end){if (start < end && array[end] >= tmp){//先走后面,否则下面没法填坑end--;}array[start] = array[end];if (start < end && array[start] <= tmp){start++;}array[end] = array[start];}array[start] = tmp;return start;}

2.7 归并排序

先把数组从中间拆分开,让每个小数组有序,之后把小数组合并回来,大数组就是有序的.也是分治思想,整体也是一棵二叉树的形状.
动态演示:

在这里插入图片描述

/*** 归并排序* @param array*/public static void mergSort(int[] array){mergFunc(0,array.length-1,array);}private static void mergFunc(int left,int right,int[] array){//拆分数组int mid = (left+right)/2;if (left >= right){//递归到left>=right的时候,直接返回return;}//向两侧递归mergFunc(left,mid,array);mergFunc(mid+1,right,array);//开始合并merg(left,right,mid,array);}//在合并的时候进行排序private static void merg(int left,int right,int mid,int[] array){int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;int k = 0;int [] tmp = new int[right-left+1];while (s1 <= e1 && s2 <= e2){if (array[s1] < array[s2]){tmp[k] = array[s1];k++;s1++;}else {tmp[k] = array[s2];k++;s2++;}}//看哪个数组还有数据,拷贝进去while (s1 <= e1){tmp[k] = array[s1];k++;s1++;}while (s2 <= e2){tmp[k] = array[s2];k++;s2++;}//把临时数组中的数据拷贝到原数组中for (int i = 0; i < tmp.length; i++) {array[left+i] = tmp[i];}}

特性总结:

  1. 时间复杂度:元素个数x数的高度,O(n*log2n)
  2. 空间复杂度:额外申请了一个数组,所以是O(n)
  3. 稳定性:稳定

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

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

相关文章

Python查询PostgreSQL数据库

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; Python与PostgreSQL的连接 需要了解如何在Python中连接到PostgreSQL数据库。这通常涉及到使用一个库&#xff0c;如psycopg2&#xff0c;它是Python中用于PostgreSQL的最流行的适配器。安装psycopg2非常简单&#x…

好用的win10电脑桌面便利贴,桌面便签小工具

在日常办公中&#xff0c;我们经常需要记录重要事项、提醒任务或者临时想法。这时&#xff0c;一款好用的电脑桌面便签或便利贴小工具就显得尤为重要。它们能够帮助我们高效地管理信息&#xff0c;提升工作效率。 那么好用的win10电脑桌面便利贴是哪个呢&#xff1f;电脑桌面便…

oracle 8i系统检查

oracle 8i系统检查 set echo on spool d:\bk\1.txt select sysdate from dual; --版本信息 select * from v$version; --安装的产品 col PARAMETER for a50; col value for a10; select * from v$option order by 2; --用户信息 set linesize 100 set pagesize 100 COL USE…

SpringBoot集成阿里云短信验证码服务

一&#xff1a;前言 最近在项目开发过程中&#xff0c;需要去写一个发送手机短信验证码的功能。在网上查了一下&#xff0c;有很多服务器可供选择&#xff0c;本文的话是基于阿里云服务的短信验证码功能实现。 关于注册和开通服务这些需要操作的&#xff0c;请各位小伙伴参考官…

Burp和Proxifier抓包微信小程序

1、Burp设置代理 2、浏览器下载证书 3、安装证书 4、Proxifier设置代理 5、Proxifier设置Proxification Rule 6、Burp查看抓包数据 打开一个小程序&#xff0c;可以看到WeChatAppEx的流量先经过Proxifier&#xff0c;再经过127.0.0.1:8080到Burp

CWDM、DWDM、MWDM、LWDM:快速了解光波复用技术

在现代光纤通信领域&#xff0c;波分复用&#xff08;WDM&#xff09;技术作为一项先进的创新脱颖而出。它通过将多个不同波长和速率的光信号汇聚到一根光纤中来有效地传输数据。本文将深入探讨几种关键的 WDM 技术&#xff08;CWDM、DWDM、MWDM 和 LWDM&#xff09;&#xff0…

字节8年经验之谈 —— 手把手教你做测试流程优化!

一、需求阶段 1. 梳理提需求流程 &#xff08;1&#xff09;规范需求list时间 有些团队可能会今天提一个需求&#xff0c;明天提一个&#xff1b;可以制定一个每周过需求list的时间&#xff0c;统一安排过本周的需求&#xff0c;并对需求进行优先级排序&#xff0c;开发和QA…

Android 状态栏WiFi图标的显示逻辑

1. 状态栏信号图标 1.1 WIFI信号显示 WIFI信号在状态栏的显示如下图所示 当WiFi状态为关闭时&#xff0c;状态栏不会有任何显示。当WiFi状态打开时&#xff0c;会如上图所示&#xff0c;左侧表示有可用WiFi&#xff0c;右侧表示当前WiFi打开但未连接。 当WiFi状态连接时&#x…

创造未来知识管理新篇章:Ollama与AnythingLLM联手打造个人与企业的安全知识库!

一 Ollama 1.1 简介 Ollama是一个开源的大型语言模型服务工具,它帮助用户快速在本地运行大模型。通过简单的安装指令,用户可以执行一条命令就在本地运行开源大型语言模型,如Llama 2。Ollama极大地简化了在Docker容器内部署和管理LLM的过程,使得用户能够快速地在本地运行大…

Vite构造Vue3

环境安装 node.js安装-CSDN博客 初始化Vue项目安装脚手架_vue init webpack安装脚手架-CSDN博客 选择Vue框架 &#xff0c;项目名称可以自定义&#xff0c;我使用默认的 vite-project 选择JS 进入项目安装依赖 安装路由

Linux服务器常用巡检命令

在Linux服务器上进行常规巡检是确保服务器稳定性和安全性的重要措施之一。以下是一些常用的巡检命令和技巧&#xff1a; 1. 查看系统信息 1.1 系统信息显示 命令&#xff1a;uname -a ​​​​ [rootlinux100 ~]# uname -a Linux linux100 4.15.0-70-generic #79-Ubuntu SMP…

mac自定义快捷键打开系统应用

最终效果是达成altg直接打开浏览器&#xff0c;解放双手、再也不需要移动鼠标双击打开应用啦&#xff01;&#xff01;&#xff01;&#xff5e; 1.commandspace输入自动操作 2.选择快速操作 3.选择使用工具、运行appleScrpit 4.输入打开浏览器代码 tell application "G…

2024数维杯数学建模B题思路分析

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

【算法系列】栈

目录 leetcode题目 一、删除字符串中的所有相邻重复项 二、比较含退格的字符串 三、基本计算器 II 四、字符串解码 五、验证栈序列 六、有效的括号 七、最小栈 八、逆波兰表达式求值 九、用栈实现队列 十、用队列实现栈 leetcode题目 一、删除字符串中的所有相邻重…

数据结构-二叉树-二叉搜索树

一、概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左树上所有节点的值都小于根节点的值。 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值。 它…

2024年 Java 面试八股文——SpringCloud篇

目录 1.Spring Cloud Alibaba 中的 Nacos 是如何进行服务注册和发现的&#xff1f; 2.Spring Cloud Alibaba Sentinel 的流量控制规则有哪些&#xff1f; 3.Spring Cloud Alibaba 中如何实现分布式配置管理&#xff1f; 4.Spring Cloud Alibaba RocketMQ 的主要特点有哪些&…

干货 | 嵌入式OTA升级实现原理

我曾经一个经理&#xff0c;被老板骂到狗血淋头的场景&#xff0c;还历历在目。 原因是&#xff0c;产品大批量出货了&#xff0c;发现了一个偶发性的BUG。 这意味着&#xff0c;所有卖出去的产品&#xff0c;都得退回来&#xff0c;重新烧录程序。 估计当时经理在想&#xff0…

fork后如何同步最新的代码

1.查看自己的库并添加远程源库 #查看所有远程库的url git remote -v; #添加源项目url&#xff08;upstream是自己定义的一个名字&#xff0c;可以删 git remote remove upstream&#xff09; git remote add upstream 这里替换为源项目url; #查看所有远程库的url&…

哪个牌子的电容笔好用?618五款爆款电容笔评测,不踩雷!

随着信息技术不断发展&#xff0c;iPad慢慢成为了现代年轻人工作、娱乐和学业的必备智能工具之一。然而&#xff0c;市场上涌现出众多品牌的电容笔&#xff0c;也存在着大量低质量的电容笔产品。这些产品往往无法达到预期的书写和绘画效果&#xff0c;反而可能导致用户体验不佳…

AI适老化!10秒一张的AI姓氏头像,居然要卖9块9?中老年用户都说好!

看短视频的你&#xff0c;一定会刷到过这样的直播间&#xff1a; 现在大家明白了&#xff0c;这是一个做姓氏图像的直播间。我刚开始刷到的时候也觉得这种头像好看&#xff0c;高大上&#xff0c;也想做一个这样的图像&#xff0c;来当自己的微信头像。 做这样的图像需要排队刷…