详解七大排序算法
对于排序算法,是我们在数据结构阶段,必须要牢牢掌握的一门知识体系,但是,对于排序算法,里面涉及到的思路,代码……各种时间复杂度等,都需要我们,记在脑袋瓜里面!!尽量一丢丢不要出现差错!面试所必备的精彩提问!!
言归正传:对于排序,我们首先需要知道的是:排序的概念!!
排序的概念!
所谓的排序,,就是使一串记录,按照其中的某个或者某些关键字的大小,递增递减的排序起来的操作!!
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍然在r[j]之前,这种排序算法是稳定的,否则是不稳定的!!
就比如:9 5 2 7 3 6 4 5 8 0 这些数据而言!

内部排序:数据元素部分放在内存的排序
外部排序:数据元素不能同时放在内存中,根据排序过程的要求不同,在内存与外存之间移动数据的排序(要排序的数据,在内存中放不下!!)
下面笔者就以七种常见的排序算法为列,来带大家走进排序!!(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序)
1.插入排序:
插入排序:把待排序的记录按照其关键码值的大小,逐个插入到一个已经排序好的有序序列中,直到所有的记录插完为止,从而得到一个新的有序序列(扑克牌)
下面请看笔者的代码:
public static void insertSort(int[] arr){//对传入的数组进行排序for (int i = 1; i<arr.length; i++){for (int j = i-1; j>=0; j--){if(arr[j]>arr[j+1]){//稳定的int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}elsebreak;}}System.out.println(Arrays.toString(arr));}public static void main(String[] args) {int[] array={12,56,32,67,10,19,4};insertSort(array);}
2.希尔排序
希尔排序的思想:先选定一个整数,把待排序文件中的所有记录分成多个组,所有距离为一样的放在同一个组内,并对每一组的记录进行插入排序,取重复上述分组和排序的工作,当达到=1时,所有记录在统一组内排序好(先分组,5组,3组,最后为1组)
假设初始的数据为: 9 1 2 5 7 4 8 6 3 5
那么,我们有着一下 的简单排序过程:

经过上述的过程,我们可以看出:组数越多,每组进行排序的数据越少!(两两交换(使用插入排序)越有序越快),组数越少,每组数据越多(数据在慢慢变得有序)
那么,我们对于希尔排序,有着一下的几点总结:
希尔排序是对直接插入排序算法的优化!
当gap>1时,都是预排序,目的是让数组接近有序,当gap=1时,数组已经接近有序了,这样就会很快,这样整体而言,可以达到优化的效果,我们实现后可以进行性能测试的对比!
希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中,给出的希尔排序的时间复杂度不固定!
有了上述的思考,我们接下来就该实现一下代码了:
public static void shellSort(int[] array){int gap=array.length;//分组while (gap>1){shell(array,gap);gap=gap/2;}//整体进行插入排序,此时gap=1shell(array,1);}//插入排序public static void shell(int[] array,int gap){for (int i = 0; i <array.length; i++) {int tmp=array[i];int j=i-gap;for(;j>=0;j=j-gap){if (array[j]>tmp){array[j+gap]=array[j];}else {break;}}array[j+gap]=tmp;}}public static void main(String[] args) {int[] array={12,56,32,67,10,19,4};shellSort(array);System.out.println(Arrays.toString(array));}
3.选择排序
在了解选择排序之前,我们需要知道的是:
选择排序的思想:每一次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完,直接选择排序!
第一次从R[0]到R[n-1]中选出最小值,与R[0]进行交换,第二次从R[1]到R[n-1]中选出最小值与R[1]交换……,以此类推,从而得到从小到大的有序排序
经过上面的简单分析,我们可以得出下列的有效代码:
public static void selectSort(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i + 1; j < array.length; j++) {if (array[j] < array[minIndex]) {minIndex = j;//minIndex保存最小数据的下标值!}}swap(array, i, minIndex);}}private static void swap(int[] array,int i,int j){int tmp=array[i];array[i]=array[j];array[j]=tmp;}public static void main(String[] args) {int[] array={12,56,32,67,10,4};selectSort(array);System.out.println(Arrays.toString(array));}
4.堆排序
对于堆排序,是指利用堆积树(堆),这种数据结构所设计的一种排序算法,它是一种选择排序,通过堆来进行选择数据
需要注意的是:排升序建大堆,排降序建小堆!!
那么,根据笔者之前的堆排序的环节:https://blog.csdn.net/weixin_64308540/article/details/129217324?spm=1001.2014.3001.5502我们可以有着一下的简单代码:
public static void heapSort(int[] array){createBigHeap(array);//创建一个大根堆int end=array.length-1;while (end>0){//等于0的时候就不换了swap(array,0,end);//交换shiftDown(array,0,end);//向下调整end--;}}private static void createBigHeap(int[] array){//建立大根堆从最后一颗子树开始for (int parent = (array.length-1-1)/2; parent >=0 ; parent--) {shiftDown(array,parent,array.length);//array,length是指结束位置}}//向下调整private static void shiftDown(int[] array,int parent,int len){int child=2*parent+1;while (child<len){//至少有左孩子if (child+1<len && array[child]<array[child+1]){//有右孩子//此时child是左孩子最大值的下标child++;}if (array[child]>array[parent]){swap(array,child,parent);//交换parent=child;child=2*parent+1;}else {break;}}}private static void swap(int[] array,int i,int j){int tmp=array[i];array[i]=array[j];array[j]=tmp;}public static void main(String[] args) {int[] array={12,56,32,67,10,4};heapSort(array);System.out.println(Arrays.toString(array));}
5.交换排序
对于交换排序,我们在之前就已经有过接触,其实就是最简单的冒泡排序
交换排序的基本思想:所谓交换就是根据序列中的两个记录键值的比较结果,交换这两个记录在序列中的位置!
交换排序的特点:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动
下面笔者就以冒泡排序来进行书写代码:
方法1:
public static void bubblesort2(int[] array ) {//趟数for (int i = 0; i < array.length-1; i++) {//每趟执行的次数boolean flg=false;for(int j=0;j<array.length-1-i;j++) {if(array[j]>array[j+1]) {int tmp=array[j+1];array[j+1]=array[j];array[j]=tmp;}flg=true;}if(flg==false) {return ;}}}public static void main(String[] args) {int[] array={1,29,10,36,5,21,46,3,6};bubblesort2(array);System.out.println(Arrays.toString(array));}
方法2:
public static void bubbleSort2(int[] array){for (int i = 0; i < array.length; i++) {for (int j = 0; j < array.length-1-i; j++) {if (array[j]>array[j+1])swap(array,j,j+1);}}}private static void swap(int[] array,int i,int j){int tmp=array[i];array[i]=array[j];array[j]=tmp;}public static void main(String[] args) {int[] array={12,56,32,67,10,19,4};bubbleSort2(array);System.out.println(Arrays.toString(array));}
在上述代码中,方法1是对方法2的简单优化!!
在方法1中,我们通过一个:boolean flg=false;来优化了代码!!原因在于,在进行冒泡排序的时候,可能对于一串数据,排到一半就有序了,那么,在没有优化之前,肯定还得一个一个尝试去遍历,但是,在优化以后,可以节约时间!!
6.快速排序
快速排序的思想:任取待排序元素序列中的某元素(一般是第一个元素),作为基准值,按照该排序码,将待排序的集合分为两个子序列,左子序中的所有元素均小于基准值,右子序中的所有元素均大于基准值,然后最左右子序列都重复该过程,直到所有的元素都排序在相应的位置为止!!
对于上述的简单思想,我们有着挖坑法!Hoare法!
下面我们先讲解一下挖坑法:
先将第一个数据存放在一个临时变量key中,形成一个坑位!
设置两个变量i,j,排序开始的时候,i=0,j=N-1!
以第一个数组元素作为关键数据,赋值给key,即key=A[0]!
从j开始向前搜素,即由后开始向前搜素(j--),找到第一个小于key的值A[j],将A[j]与A[i]的值进行交换!
从i开始向后搜素,即由前开始向后搜素(i++),找到第一个大于key的值A[i],将A[i]与A[j]的值交换!
重复步骤3,4,直到i==j为止!
对于上述的思路,我们可以用递归来实现!!
package zyh.example.demo.algorithm.kuaisupaixu;import java.util.Arrays;/**
* @ClassName KuaiPai13
* @Author zhangyonghui
* @Description
* @Date 2022/3/29 11:26
* @Version 1.0
**/
public class KuaiPai13 {public static void main(String[] args) {int[] arr = new int[]{4, 7, 6, 5, 3, 2, 8, 1};quickSort(arr, 0, arr.length - 1);System.out.println(Arrays.toString(arr));}/*** 快速排序--挖坑法* @param arr 数组* @param startIndex 左边界索引* @param endIndex 右边界索引*/public static void quickSort(int[] arr, int startIndex, int endIndex) {// 递归结束条件:startIndex大等于endIndex的时候if (startIndex >= endIndex) {return;}// 得到基准元素位置int pivotIndex = partition(arr, startIndex, endIndex);// 用分治法递归数列的两部分quickSort(arr, startIndex, pivotIndex - 1);quickSort(arr, pivotIndex + 1, endIndex);}/*** 具体每一轮的快速排序:* @param arr 数组* @param startIndex 左边界索引* @param endIndex 右边界索引* @return 返回基准值的位置,此时基准值左边的元素都小于基准值,基准值右边的元素都大于基准值*/private static int partition(int[] arr, int startIndex, int endIndex) {// 取第一个位置的元素作为基准元素int pivot = arr[startIndex];// 初始化坑的位置,初始等于pivot基准值的位置int kengIndex = startIndex;//初始化左右游标/指针int leftYb = startIndex;int rightYb = endIndex;//大循环在左右指针重合时结束while ( leftYb<rightYb ) {//right指针从右向左进行比较// leftYb<rightYb ,左游标永远小于右游标,是遍历元素并发生元素变动的前提:while ( leftYb<rightYb) {// 先遍历右边,// 如果元素大于基准值--右游标左移:if (arr[rightYb] >= pivot) {rightYb--;}else{ //如果右边的当前元素小于基准值了,那么将该元素填入坑中,该元素本来的位置成为新的坑;arr[kengIndex] = arr[rightYb];kengIndex = rightYb;leftYb++;break;}}//再遍历左边,// leftYb<rightYb ,左游标永远小于右游标,是遍历元素并发生元素变动的前提:while (leftYb<rightYb) {//如果元素小于基准值--左游标右移,if (arr[leftYb] <= pivot) {leftYb++;}else{ //如果左边的当前元素大于基准值了,那么将该元素填入坑中,该元素本来的位置成为新的坑;arr[kengIndex] = arr[leftYb];kengIndex = leftYb;rightYb--;break;}}}//跳出了大循环,说明此时此刻左右游标是重合的,这时将基准值放在重合位置(最后一个坑),// 此时,基准值左边的元素都小于基准值,基准值右边的元素都大于基准值,这一轮交换宣告结束;arr[kengIndex] = pivot;return kengIndex;}}
接下来进入Hoare法!
right找到比基准小的停下来,left找到比基准大的停下来,进行比较,循环往复,最后当right==left的时候,将此时对应的值与基准进行比较!
请看笔者代码:
public class Main {static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};public static void main(String[] args) {fastsort(0, a.length-1);for (int i = 0; i < a.length; i++) {System.out.print(a[i] + " ");}}private static int Hoare(int l, int r) {int p = a[l];int i = l-1;int j = r+1 ;while (true) {do {j--;} while (a[j] > p);do {i++;} while (a[i] < p);if (i < j) {int temp = a[i];a[i] = a[j];a[j] = temp;} elsereturn j;}}private static void fastsort(int l, int r) {if (l < r) {int s = Hoare(l, r);fastsort(l, s);fastsort(s+1, r);}}
}
7.归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列,即,先使每个子序列有序,再使子序列断间有序!
主要的思路及其过程,如下图所示:

那么,接下来请看代码吧!!(递归实现)
//递归实现
public static void mergeSort(int[] array){mergeSortFunc(array,0, array.length);}private static void mergeSortFunc(int[] array,int left,int right){if (left>=right){return;}//分解int mid=(left+right)/2;mergeSortFunc(array,left,mid);mergeSortFunc(array,mid+1,right);merge(array,left,right,mid);//合并}private static void merge(int[] array,int start,int end,int mid){int s1=start;int s2=mid+1;int[] tmp=new int[end-start+1];//申请一个数组int k=0;//tmp数组下标while (s1<=mid && s2<=end){if (array[s1]<= array[s2]){tmp[k++]=array[s1++];}else {tmp[k++]=array[s2++];}}while (s1<=mid){tmp[k++]=array[s1++];}while (s2<=end){tmp[k++]=array[s2++];}for (int i = 0; i < tmp.length; i++) {array[i+start]=tmp[i];}}
感兴趣的老铁,可以看一下非递归实现的:
//非递归public static void mergeSort2(int[] array){int gap=1;while (gap<array.length){for (int i = 0; i < array.length; i++) {int left=i;int mid=left+gap+1;if (mid>= array.length){mid=array.length-1;}int right=mid+gap;if (right>=array.length){right=array.length-1;}merge(array,left,right,mid);}gap=gap*2;}}
七大排序算法大致就到此结束了!!拜拜!
相关文章:

详解七大排序算法
对于排序算法,是我们在数据结构阶段,必须要牢牢掌握的一门知识体系,但是,对于排序算法,里面涉及到的思路,代码……各种时间复杂度等,都需要我们,记在脑袋瓜里面!…...

Vue+ECharts实现可视化大屏
由于项目需要一个数据大屏页面,所以今天学习了vue结合echarts的图标绘制 首先需要安装ECharts npm install echarts --save因为只是在数据大屏页面绘制图表,所以我们无需把它设置为全局变量。 可以直接在该页面引入echarts,就可以在数据大…...

百度Apollo规划算法——轨迹拼接
百度Apollo规划算法——轨迹拼接引言轨迹拼接1、什么是轨迹拼接?2、为什么要进行轨迹拼接?3、结合Apollo代码为例理解轨迹拼接的细节。参考引言 在apollo的规划算法中,在每一帧规划开始时会调用一个轨迹拼接函数,返回一段拼接轨迹…...

6. unity之脚本
1. 说明 当整个游戏运行起来之后,我们无法再借助鼠标来控制物体,此时可以使用脚本来更改物体的各种姿态,驱动游戏的整体运动逻辑。 2. 脚本添加 首先在Assets目录中,新创建一个Scripts文件夹,在该文件内右键鼠标选择…...

flink-note笔记:flink-state模块中broadcast state(广播状态)解析
github开源项目flink-note的笔记。本博客的实现代码都写在项目的flink-state/src/main/java/state/operator/BroadcastStateDemo.java文件中。 项目github地址: github 1. 广播状态是什么 网上关于flink广播变量、广播状态的讲解很杂。我翻了flink官网发现,实际上在1.15里面…...

vue——预览PDF
下载插件 npm install --save vue-pdf创建组件 <template><div class"ins-submit-docs-content ins-submit-docs-pdf"><div v-if"loading" style"position: absolute; top: 40%; width: 100%;text-align: center;"><el-l…...

数据库复习
什么是数据库系统 数据库系统是指在计算机系统中引入数据库后构成的系统,一般由数据库、数据库管理系统(及其开发工具)、应用系统、数据库管理员和用户构成 数据库系统的特点是什么? 数据结构化数据的共享性高,冗余度低且易扩充数据独立性高数…...

vscode插件推荐
文章目录前言一、vscode插件推荐?1、 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code2、Auto Close Tag3、Auto Import3、Error Lens4、vscode-icons5、ES7 React/Redux/React-Native snippets6、GitLens — Git supercharged7、JavaScript…...

THUPC2023初赛总结
今天参加了THUPC2023初赛,感觉还行。 比赛本来是11:00-16:00,但出了点问题,比赛延迟了十分钟。 刚开始,我从第一题往后看,寻找简单的题。 过了一会儿,一看排行榜,怎么最后一题全是绿的&#…...

unity知识点小结02
虚拟轴 虚拟轴就是一个数值在-11内的轴,这个数轴上重要的数值就是-1,0和1。当使用按键模拟一个完整的虚拟轴时需要用到两个按键,即将按键1设置为负轴按键,按键2设置为正轴按键。在没有按下任何按键的时候,虚拟轴的数值为0…...

总线(四)Modbus总线 协议
文章目录Modbus技术背景Modbus OSI分布Moudbus分类通讯过程Moudbus协议通信过程以及报文解析RTU 与 ASCII 收发数据区别Modbus技术背景 Modbus是一种串行通信协议。 1971年,Modicon公司首次退出Modbus协议,ModbusRTU和Modbus ASCII诞生于此。 后来施耐德…...

Cadence Allegro 导出Component Report详解
⏪《上一篇》 🏡《总目录》 ⏩《下一篇》 目录 1,概述2,Component Report作用3,Component Report示例4,Component Report导出方法4.1,方法14,2,方法2B站关注“硬小二”浏览更多演示视频 1,...

程序猿成长之路之密码学篇-DES算法详解
DES的算法实现原理详情请见 https://blog.csdn.net/qq_31236027/article/details/128209185 DES算法密钥获取详情请见 https://blog.csdn.net/qq_31236027/article/details/129224730 编码工具类获取详见 https://blog.csdn.net/qq_31236027/article/details/128579451 DES算法…...

maven生命周期、阶段与默认绑定插件梳理
maven生命周期、阶段与默认绑定插件梳理 CSDN博客 码云源码 1.maven生命周期、阶段与默认绑定插件 序号生命周期lifecycle阶段phase默认绑定插件(链接官网)默认绑定插件(链接maven库)说明1cleancleanmaven-clean-pluginmaven-clean-plugin清理2.1buildvalidate——验证2.2b…...

【数学基础】
文章目录『 第1讲 高等数学预备知识 』1.1 函数的概念与特性函数的四种特性【 重要结论 】1.2 函数的图像直角坐标系下的图像极坐标系下的图像参数方程1.3 常用基础知识【 情报#1 】『 第2讲 数列极限 』2.1 引言2.2 求数列极限【 情报#2 】『 第1讲 高等数学预备知识 』 1.1 …...

网上电子商城的设计与实现
技术:Java、JSP等摘要:21 世纪以来,人类经济高速发展,人们的生活发生了日新月异的变化,特别是计算机的应用及普及到经济和社会生活的各个领域。在消费领域,网上购物已经成为大众所接受的一种新型的消费方式…...

2023thupc总结
A 大富翁 很有意思的题 ∑x∈A∑y∈B[x支配y]−∑x∈A∑y∈B[y支配x]−∑x∈Awx\sum_{x\in A}\sum_{y\in B}[x支配y]-\sum_{x\in A}\sum_{y\in B}[y支配x]-\sum_{x\in A}w_x∑x∈A∑y∈B[x支配y]−∑x∈A∑y∈B[y支配x]−∑x∈Awx ∑x∈A∑y[x支配y]−∑x∈A∑y[y支…...

【数据库】MySQL数据库基础
目录 1.数据库: 2.数据库基本操作 2.1 MySQL的运行原理 2.2显示数据库: 2.3创建数据库 2.4使用数据库 2.5删除数据库 3.常见的数据类型 3.1数值类型: 3.2字符型类型 3.3日期类型 4.表的操作 4.1创建表 4.2查看表 4.3删除表 5.汇总…...

grid了解
结构 <div class"grid"><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>&l…...

2023年全国最新工会考试精选真题及答案13
百分百题库提供工会考试试题、工会考试预测题、工会考试真题、工会证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 81.女职工委员会在()下开展工作。 A.企业工会委员会领导 B.企业工会委员会指导 …...

初识HTML技术
文章目录一、为什么学习前端?二、第一个HTML文件VSCode三. HTML元素四. HTML页面一、为什么学习前端? 我们作为一个后端程序员,为什么还要学习前端,因为我们的终极目的是实现web开发,搭建网站,网站 前端 后端 比如我们随便…...

我们为什么要用消息队列?
消息队列是系统设计中存在时间最长的中间件之一,从系统有通信需求开始,就产生了消息队列。 消息队列的使用场景 在日常系统设计与实现的过程中,下面3种场景会涉及到消息队列: 异步处理流量控制服务解耦 异步处理 典型的应用场…...

Linux进程控制
进程控制fork函数进程终止退出码常见的退出方式进程等待什么是进程等待,为什么要进程等待阻塞与非阻塞进程替换替换原理替换函数执行系统命令执行自己写的程序模拟实现简易的shellfork函数 fork函数是创建一个子进程,之前用过。 #include <unistd.h…...

PMP项目管理引论介绍
目录1. 指南概述和目的1.1 项目管理标准1.2 道德与专业行为规范2 基本要素2.1 项目2.2 项目管理的重要性2.3 项目、项目集、项目组合以及运营管理之间的关系2.3.1 概述2.3.2. 项目组合与项目集管理2.3.3. 运营管理2.3.4. 组织级项目管理和战略2.3.5. 项目管理2.3.6. 运营管理与…...

计算机视觉废钢堆提取问题
计算机视觉废钢堆提取问题 背景介绍 在钢铁炼制中,废钢是非常重要的原料,不同等级废钢对于钢成品影响很大,因此需要对废钢进行正确分类。某废钢料场中,卸料区域布置了多个摄像头,用于拍摄卸料场中废钢堆,…...

判断水仙花数-课后程序(Python程序开发案例教程-黑马程序员编著-第二章-课后作业)
实例5:判断水仙花数 水仙花数是一个3位数,它的每位数字的3次幂之和等于它本身,例如13 53 33 153,153就是一个水仙花数。 本实例要求编写程序,实现判断用户输入的3位数是否为水仙花数的功能。 实例目标 掌握Pytho…...

目标检测: 数据增强代码详解
1. 常见的数据增强 1.1 翻转图像 左右水平翻转 假设图片的宽高为w,h,bdbox左上角A坐标为(x1,y1), 右下角B为(x2,y2)。经过左右水平翻转后,bdbox的左上角A1坐标(w-x2,y1) ,右下角B1坐标为(w-x1,y2)左右水平翻转的代码实现如下:from PIL import Image image = Image.open(i…...

第二讲:ambari编译复盘,如何实现一次性成功编译ambari
上节课我们已经讲解了如何成功编译ambari源码,安装ambari-server rpm包以及成功部署ambari。本节课我们来复盘一下上节课的编译过程,以及思考如何实现一次性成功编译ambari。 要想一次性成功编译ambari,那么就需要将预置工作做好,比如: maven镜像源配置,node_moudle模块…...

Windows下jdk安装与卸载-超详细的图文教程
jdk安装 下载jdk 由于现在主流就是jdk1.8,所以这里就下载jdk1.8进行演示。官方下载地址:https://www.oracle.com/java/technologies/downloads/#java8-windows。 官方下载需要注册oracle账号,国内下载有可能速度慢,若不想注册账…...

Jackson CVE-2018-5968 反序列化漏洞
0x00 前言 同CVE-2017-15095一样,是CVE-2017-7525黑名单绕过的漏洞,主要还是看一下绕过的调用链利用方式。 可以先看: Jackson 反序列化漏洞原理 或者直接看总结也可以: Jackson总结 影响版本:至2.8.11和2.9.x至…...