当前位置: 首页 > news >正文

常见排序算法总结

文章目录

  • 比较排序
    • 冒泡排序
    • 选择排序
    • 插入排序
    • 归并排序
    • 快速排序
    • 堆排序
    • 希尔排序
  • 非比较排序(桶排序)
    • 计数排序
    • 基数排序

比较排序

冒泡排序

嵌套循环,每次内层循环执行时,数组的每两个元素交换,将一个最大/小的数排到数组末尾

在这里插入图片描述

public void bubbleSort(int[] arr){for (int i = 0; i < arr.length; i++) {// 内层循环中,每轮都是让最后一个位置排好序,然后外层循环向前递进for (int j = 0; j < arr.length - i - 1; j++) {if (arr[j] > arr[j+1]){  // 把大的数挪到后面int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}
}

选择排序

嵌套循环,每次内层循环执行时,子数组的后m-1个元素寻找最小值,再与子数组的首元素比较,如果更大/小就交换

在这里插入图片描述

public void selectSort(int[] arr){for (int i = 0; i < arr.length - 1; i++){    // len个元素只需比较n-1次int min_idx = i;for (int j = i + 1; j < arr.length; j++){if (arr[j] < arr[min_idx])     // 在i+1后面的数两两比较,找到最小下标min_idx = j;}// 内层遍历完之后,我们拿到后面的元素的最小值下标min_id,要和前面的下标i元素进行值的对比if (arr[min_idx] < arr[i]){        // 能篡位就篡位!arr[min_idx] = arr[min_idx] ^ arr[i];arr[i]       = arr[min_idx] ^ arr[i];arr[min_idx] = arr[min_idx] ^ arr[i];}}
}

插入排序

嵌套循环,默认第一个元素不处理,每插入/增加一个数,就依次跟前面的数两两对比,将前面的所有数进行排好序

在这里插入图片描述

public void insertSort(int[] arr){for (int i = 1; i < arr.length; i++) {  // 外层循环len-1次// 对应外层的len-1次,内层分别循环1到len-1次,且后一个数 < 前一个数才会进循环交换for (int j = i - 1; j >= 0 && arr[j + 1] < arr[j]; j--){// 如果后一个元素更小,就交换到前面来arr[j]     = arr[j] ^ arr[j + 1];arr[j + 1] = arr[j] ^ arr[j + 1];arr[j]     = arr[j] ^ arr[j + 1];}}
}

归并排序

递归到最底层时会执行merge排序,回溯时排序保证了此时两个子数组都必然有序

在这里插入图片描述

// 不传参默认对整个数组进行归并排序
public void mergeSort(int[] arr) {if (arr == null || arr.length < 2) return;mergeSort(arr, 0, arr.length - 1);
}
// 传参则对[l, r]区间进行归并排序
public void mergeSort(int[] arr, int l, int r) {if (l == r) return;int mid = l + ((r - l) >> 1);mergeSort(arr, l, mid);mergeSort(arr, mid + 1, r);merge(arr, l, mid, r);  // 回溯位置归并,所以此时的子数组皆已排序完成
}
// 对 arr 的 [l, m]  [m+1, r] 两部分子数组进行归并排序
public void merge(int[] arr, int l, int m, int r) {int[] help = new int[r - l + 1];  // 辅助数组,暂时存放归并后的数组int i = 0;// 两个子数组的起始索引位置 p1 p2int p1 = l, p2 = m + 1;// 精髓:看数据哪边小,就先挪哪边的数据到help数组里while (p1 <= m && p2 <= r) help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];while (p1 <= m) help[i++] = arr[p1++];while (p2 <= r) help[i++] = arr[p2++];// 将暂存的归并后的数组,覆盖到 arr 上,使原数组排好序for (i = 0; i < help.length; i++) {arr[l + i] = help[i];}
}

快速排序

整体的quickSort函数swap后,再进行partition,划分三部分后,<区域 >区域 分别递归调用局部的quicksort

在这里插入图片描述

public void quickSort(int[] arr) {if (arr == null || arr.length < 2) return;quickSort(arr, 0, arr.length - 1);
}public void quickSort(int[] arr, int l, int r) {if (l < r) {// 左神的随机:让最右的r与[l,r-1]之间的随机一个数交换swap(arr, l + (int) (Math.random() * (r - l + 1)), r);// 先partition再进递归(与归并的回溯时merge区分)int[] p = partition(arr, l, r);quickSort(arr, l, p[0] - 1); // = 区域的左部分quickSort(arr, p[1] + 1, r); // = 区域的右部分}
}public int[] partition(int[] arr, int l, int r) {int less = l - 1;int more = r;while (l < more) {if (arr[l] < arr[r]) {swap(arr, ++less, l++);} else if (arr[l] > arr[r]) {swap(arr, --more, l);} else {l++;}}swap(arr, more, r);  // 最右那个 = 划分值挪回原位return new int[] { less + 1, more };  // = 区域:[ less+1, more ]
}public void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

堆排序

堆是一种比较特殊的完全二叉树

分为:大根堆小根堆

由于完全二叉树的结构性质,可以使用数组或列表等线性数据结构来存储堆(此处用优先级队列)

大根堆:每个子树的最大节点是头结点

小根堆:每个子树的最小节点是头结点

在这里插入图片描述

public static void heapSort(int[] arr) {if (arr == null || arr.length < 2) return;// 1. 先构建大根堆,完成后就已知arr最大值(根节点的value)// 传统 heapInsert1// for (int i = 0; i < arr.length; i++) {//    heapInsert1(arr, i);// }// 进化 heapInsert2heapInsert2(arr);// 2. 取出根节点这个最大值,与末尾节点做交换,然后最大值相当于到末尾排好序了,所以移除这个末尾(最大值)元素//    末尾节点到根节点位置后就heapify,再去重新进行大根堆的构建int size = arr.length;swap(arr, 0, --size);while (size > 0) {heapify(arr, 0, size);swap(arr, 0, --size);}
}
// 1. 构建大根堆   v1.0 传统版
public static void heapInsert1(int[] arr, int index) {while (arr[index] > arr[(index - 1) / 2]) {swap(arr, index, (index - 1) /2);index = (index - 1)/2 ;}
}
// 1. 构建大根堆   v2.0 进化版
public static void heapInsert2(int[] arr){for (int i = arr.length - 1; i >= 0; i--){heapify(arr, i, arr.length);}
}
// 2. 某个数在index位置,能否往下(数组下标越大的方向)移动
public static void heapify(int[] arr, int index, int size) {int left = index * 2 + 1;while (left < size) {int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;largest = arr[largest] > arr[index] ? largest : index;if (largest == index)break;swap(arr, largest, index);index = largest;left = index * 2 + 1;}
}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

希尔排序

间隔分组,且分组间隔依次减半,每次分组后,每个组内排序都是插入排序

相比于一开始就用插入排序,希尔排序的比较次数更少,效率更高

为什么呢?大概是因为插入排序没预处理,极端情况可能让一个很小很右的数一直比比比比比,比到最开头,浪费比较次数

而希尔排序会让每次分组比较后,基本上左侧大区间 < 右侧大区间 类似 log(n) 但实际复杂度为 O ( n 1.3 − 2 ) O(n^{1.3-2}) O(n1.32) -表示范围,不是减号

所以其实最坏情况和插入排序一样,只不过可能性较小,正常都比插入排序好些

public void shellSort(Comparable[] arr) {// 不断减半分组排序for (int gap = arr.length / 2; gap > 0; gap /= 2) {// 对每个步长的整个数组进行插入排序for (int i = gap; i < arr.length; i++) {// 内层就是插入排序,但交换的间隔单位为gap,不会影响其他分组for (int j = i; j >= gap && arr[j].compareTo(arr[j - gap]) < 0; j -= gap) {// 交换元素Comparable temp = arr[j];arr[j] = arr[j - gap];arr[j - gap] = temp;}}}
}

非比较排序(桶排序)

计数排序

省流:词频表

// only for 0~200 value,可以更大,但太占内存空间了,还不如换别的
// 仅适用于数组数据较为集中密集的情况,太稀疏的话,中间一堆内存空间浪费
public void countSort(int[] arr) {if (arr == null || arr.length < 2) return;int max = Integer.MIN_VALUE;for (int i = 0; i < arr.length; i++) {max = Math.max(max, arr[i]);}// 一个词频表int[] bucket = new int[max + 1];for (int i = 0; i < arr.length; i++) {bucket[arr[i]]++;}// 词频表中的数据依次取出放到arr,保证有序int i = 0;for (int j = 0; j < bucket.length; j++) {while (bucket[j]-- > 0) {arr[i++] = j;}}
}

基数排序

数字按最多多少位,先补齐

从个位开始排,开始进桶再出桶,完成个位上的优先级排序

从十位开始排,还是进桶出桶,完成十位上的优先级排序

依次百位,千位… 越往后,越晚排,优先级越高

同时之前的优先级也会保留下来

所有都排完,数组就有序了(升序/降序)

某种情况比计数排序好,因为数字,如果按照普通十进制理解,则只需准备10个不同数字的桶就好了!

局限:得根据多少进制准备多个桶,需要有进制这个前提规则!

前提得知道空间范围,比如人的年龄,正数[0-200],否则内存爆炸!

所以这种不基于比较的算法应用范围很局限,大部分情况下,不如之前的所有比较算法!

图解如下:
在这里插入图片描述

前缀和处理,倒序入桶,以及词频——比较难理解,可以看下面左神讲解

左神桶排序 2:15:00

// 只适合非负数
public void radixSort(int[] arr) {if (arr == null || arr.length < 2) return;radixSort(arr, 0, arr.length - 1, maxbits(arr));
}
// 计算数组中最大元素的位数(比如324就是三位数)
public int maxbits(int[] arr) {int max = Integer.MIN_VALUE;for (int i = 0; i < arr.length; i++) {max = Math.max(max, arr[i]);}int res = 0;while (max != 0) {res++;max /= 10;}return res;
}public void radixSort(int[] arr, int begin, int end, int digit) {final int radix = 10;  // 默认十进制int i = 0, j = 0;// 有多少个数就准备多少个辅助空间int[] bucket = new int[end - begin + 1];// 有多少个“十进制位”,就出桶进桶多少次,所以循环digit次(从个位开始算)for (int d = 1; d <= digit; d++) {int[] count = new int[radix];// 1. 遍历每一个arr元素,根据外层循环次数,取出个/十/百...位上的数字(getDigit的作用)for (i = begin; i <= end; i++) {j = getDigit(arr[i], d);count[j]++;}// 2. 遍历好个/十/百...位上的所有数字后,count数组记录了对于数字出现的频数//    接下来,把词频数换成前缀数,记录<=当前索引的数字个数,处理成如下效果://                        "10个空间"//          count[0] 当前位(d位)是 0      的数字有多少个//          count[1] 当前位(d位)是 0和1   的数字有多少个//          count[2] 当前位(d位)是 0,1和2 的数字有多少个//          count[i] 当前位(d位)是 0-i    的数字有多少个for (i = 1; i < radix; i++) {count[i] = count[i] + count[i - 1];}// 3. 入桶操作:从右往左遍历,根据个/十/百...位上的数字大小进行相应入桶,排好序for (i = end; i >= begin; i--) {j = getDigit(arr[i], d);bucket[count[j] - 1] = arr[i];count[j]--;}// 4. 出桶操作:将bucket(help)辅助数组,覆盖赋值到原来的数组arr中for (i = begin, j = 0; i <= end; i++, j++) {arr[i] = bucket[j];}}
}
// 获取一个整数 x 在指定位数 d 上的数字
public int getDigit(int x, int d) {return ((x / ((int) Math.pow(10, d - 1))) % 10);
}

相关文章:

常见排序算法总结

文章目录 比较排序冒泡排序选择排序插入排序归并排序快速排序堆排序希尔排序 非比较排序&#xff08;桶排序&#xff09;计数排序基数排序 比较排序 冒泡排序 嵌套循环&#xff0c;每次内层循环执行时&#xff0c;数组的每两个元素交换&#xff0c;将一个最大/小的数排到数组…...

网页HTTP协议 get请求和post请求区别?(HTTP中Get、Post、Put与Delete的区别)(HTTP请求方法、HTTP请求方式、HTTP方法)

文章目录 设计GET、POST、DELETE 等多种请求方法的原因1. 符合语义化设计2. 允许服务器对不同的请求方法进行优化处理3. 提高数据传输的安全性4. 遵循现有的网络架构5. 提高网络通信的效率6. 支持 RESTful API 设计 设计GET、POST、DELETE 等多种请求方法的原因 后端之所以要分…...

攻防世界 re新手模式

Reversing-x64Elf-100 64位ida打开 看if语句&#xff0c;根据i的不同&#xff0c;选择不同的数组&#xff0c;后面的2*i/3选择数组中的某一个元素&#xff0c;我们输入的是a1 直接逆向得到就行 二维字符数组写法&#xff1a;前一个是代表有几个字符串&#xff0c;后一个是每…...

Ajax是什么?如何在HTML5中使用Ajax?

Ajax是什么&#xff0c;它如何工作&#xff1f; Ajax是什么 Ajax&#xff0c;全称Asynchronous Javascript And XML&#xff08;异步JavaScript和XML&#xff09;&#xff0c;是一种创建交互式网页应用的网页开发技术。它允许网页在不重新加载整个页面的情况下&#xff0c;与…...

Python+Flask+MySQL/Sqlite的个人博客系统(前台+后端管理)【附源码,运行简单】

PythonFlaskMySQL/Sqlite的个人博客系统&#xff08;前台后端管理&#xff09;【附源码&#xff0c;运行简单】 总览 1、《个人博客系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 管理员登录2.2 程序主页面2.3 笔记新增界面2.4 文章新增界面2.5 文章/笔记管理界面2…...

【Android性能优化】Android CPU占用率检测原理和优化方向

【Android性能优化】Android CPU占用率检测原理和优化方向 CPU相关知识 CPU占用的基本计算公式 (1 - 空闲态运行时间/总运行时间) * 100% Hz、Tick、Jiffies&#xff1a; Hz&#xff1a;Linux核心每隔固定周期会发出timer interrupt (IRQ 0)&#xff0c;HZ是用来定义每一秒有…...

AWS Certified Developer Associate备考笔记

AWS Certified Developer Associate备考笔记 缓慢更新中&#xff0c;如果你也正在关注该考试&#xff0c;请点赞后评论感兴趣的章节&#xff0c;可加快我的更新速度 &#x1f603; 文章目录 AWS Certified Developer Associate备考笔记一、IAM二、EC2三、EC2 Instance Storage…...

数据质量8个衡量标准

在数据驱动的时代&#xff0c;数据质量对于企业的决策和业务运营至关重要。为了确保数据的有效性和可靠性&#xff0c;我们需要根据一些关键要素来衡量数据的质量。本文将介绍数据质量的8个衡量标准&#xff0c;包括准确性、精确性、真实性、及时性、即时性、完整性、全面性和关…...

Redis 跳跃列表与紧凑列表

Redis 跳跃列表&#xff08;Skip List&#xff09; 跳跃列表是一种高效的数据结构&#xff0c;它结合了有序数组和链表的优点&#xff0c;能够在 O(log n) 时间内进行插入、删除和查找操作。Redis 使用跳跃列表来实现有序集合&#xff08;sorted set&#xff09;的底层数据结构…...

达梦数据库的系统视图v$arch_status

达梦数据库的系统视图v$arch_status 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$ARCH_STATUS 是一个动态性能视图&#xff08;Dynamic Performance View&#xff09;&#xff0c;用于显示归档日志的状态信息。这个视图可以帮助数据库管理员监控和管理数…...

【Rust光年纪】Rust 中常用的数据库客户端库:核心功能与使用场景

探秘 Rust 语言下的多种数据库客户端库&#xff1a;从安装到实际应用 前言 在现代的软件开发中&#xff0c;数据库是不可或缺的一部分。为了与数据库进行交互&#xff0c;开发人员需要使用各种数据库客户端来执行操作、构建查询等。本文将介绍一些用于 Rust 语言的常见数据库…...

网络安全防御【防火墙双机热备带宽管理综合实验】

目录 一、实验拓扑图 二、实验要求 三、实验思路&#xff1a; 四、实验步骤&#xff1a; 1、FW3的网络相关配置&#xff1a; 2、FW1的新增配置&#xff1a; 3、交换机LSW6&#xff08;总公司&#xff09;的新增配置&#xff1a; 4、双机热备技术配置&#xff08;双机热…...

19.x86游戏实战-创建MFC动态链接库

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…...

图论建模技巧搜集

一些经典题目 找可达路径 UVa - 11604 General Sultan 平面图最小割对偶图最短路 UVa - 1376 Animal Run 最小割建模 UVa - 1515 Pool construction 费用流建模 洛谷P3159 [CQOI2012] 交换棋子 一些可以转化为二分图最大权匹配的建模题 UVa1006/LA2238 Fixed Partition Me…...

pytorch学习(九)激活函数

1.pytorch常用激活函数如下&#xff1a; #ReLU激活函数 #Leaky ReLU激活函数 #Sigmoid激活函数 #Tanh激活函数 #Softmax激活函数 #Softplus2.代码 import torch.nn as nn import torch import numpy from torch.utils.tensorboard import SummaryWriterwriter SummaryWriter…...

conda 环境打包与使用

conda 环境导出 使用 Conda 打包环境&#xff0c;可以创建一个可重复使用的环境文件&#xff0c;便于在不同的机器上重新创建相同的环境。以下是具体的步骤&#xff1a; 1. 创建 Conda 环境 如果你还没有创建一个 Conda 环境&#xff0c;可以使用以下命令创建一个新环境&…...

jenkins 插件版本冲突

一、Jenkins安装git parameter 插件重启后报错与临时解决方案 cd /root/.jenkins cp config.xml config.xml.bak vim config.xml <authorizationStrategy class"hudson.security.FullControlOnceLoggedInAuthorizationStrategy"><denyAnonymousReadAcces…...

Python print() 格式化输出

Python print{} 格式化输出 1. print()2. 浮点数 (float)References 1. print() 传递给函数的值称为参数。 引号没有打印在屏幕上&#xff0c;它们只是表示字符串的起止&#xff0c;不是字符串的一部分。可以用这个函数在屏幕上打印出空行&#xff0c;只要调用 print() 就可以…...

【Qt+opencv】计时函数与图像变换

文章目录 前言计算时间函数图像变换旋转镜像缩放 总结 前言 在图像处理和计算机视觉的应用中&#xff0c;我们经常需要对图像进行各种变换&#xff0c;如旋转、缩放、剪切等。同时&#xff0c;为了评估算法的性能&#xff0c;我们也需要对代码的执行时间进行精确的测量。OpenC…...

nodejs下载+react安装

一、nodejs安装 1、nodejs下载 具体安装可参考连接&#xff1a;2023最新版Node.js下载安装及环境配置教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了_nodejs安装及环境配置-CSDN博客 下载地址&#xff1a;Node.js — 下载 Node.js 测…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...