当前位置: 首页 > 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 测…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...