【Java数据结构】排序
【Java数据结构】排序
- 一、排序
- 1.1 排序的概念
- 1.2 排序的稳定性
- 1.3 内部排序和外部排序
- 1.3.1 内部排序
- 1.3.2 外部排序
- 二、插入排序
- 2.1 直接插入排序
- 2.2 希尔排序
- 三、选择排序
- 3.1 选择排序
- 3.2 堆排序
- 四、交换排序
- 4.1 冒泡排序
- 4.2 快速排序
- Hoare法:
- 挖坑法:
- 前后指针:
- 4.3 快速排序的优化
- 4.3.1 三数取中法
- 4.3.2 递归到小的子区间时,使用直接插入排序
- 4.4 非递归快速排序
- 五、归并排序
- 5.1 递归归并排序
- 5.2 非递归归并排序
- 六、总结
博客最后附有整篇博客的全部代码!!!
一、排序
1.1 排序的概念
排序是计算机科学中一个非常基础且重要的概念,它指的是将一组对象按照某种顺序排列的过程。排序算法是实现排序功能的具体方法,通过对数据进行比较、交换或移动等操作,使数据元素按照指定的顺序排列。
1.2 排序的稳定性
稳定性是一个重要的概念,它描述了排序算法是否能够保持相同元素的相对顺序不变。
排序稳定性:
一个排序算法是稳定的,如果在排序过程中,两个具有相同键值(或值)的元素在排序前后的相对顺序保持不变。换句话说,如果元素A和B在排序前满足A在B之前,并且它们的键值相同,那么排序后A仍然在B之前。
例如:
下面一组数据,里面有两个相同的值‘8’(为了展现它们的相对位置,我们将两个相同值的‘8’用不同元素表示出来)。在排序之前‘8’
1.3 内部排序和外部排序
1.3.1 内部排序
内部排序是指在排序过程中,所有待排序的数据都能同时存储在内存中进行处理。由于内存访问速度较快,内部排序通常效率较高,但受限于内存容量,适用于数据量较小的场景。
特点:
存储:所有数据存储在内存中。
效率:通常较快,因为内存访问速度快。
适用场景:数据量较小(通常在几万甚至几十万以内)。
1.3.2 外部排序
外部排序是指待排序的数据量过大,无法全部加载到内存中,需要借助外存(如磁盘)来完成排序的过程。外部排序通常涉及将数据分块处理,排序后再合并。
特点:
存储:数据主要存储在外存(如磁盘),内存仅用于存储部分数据。
效率:通常较慢,因为外存访问速度远低于内存。
适用场景:数据量巨大(如数百万甚至数十亿条记录),无法全部加载到内存中。
二、插入排序
2.1 直接插入排序
思想:
将待排序的元素逐个插入到已经排好序的序列中,从而逐步扩展有序序列的长度,直到所有元素都被插入,整个序列变为有序。
时间复杂度:O(N^2)。
空间复杂度:O(1)。
稳定性:稳定。
代码:
public void insertSort(int[] array){int tmp=0;for(int i=1;i<array.length-1;i++){tmp=array[i];int j=i-1;for(;j>=0;j--){if(tmp<array[j]){array[j+1]=array[j];}else{break;}}array[j+1]=tmp;}}
2.2 希尔排序
思想:
希尔排序(Shell Sort)是插入排序的一种改进版本,通过将数组分成多个子序列进行排序,逐步缩小子序列的间隔(增量),最终使整个数组有序。
其核心思想如下:
选择增量序列:初始增量通常为数组长度的一半,随后逐步减小,直到增量为1。
分组排序:按照当前增量将数组分成多个子序列,对每个子序列进行插入排序。
逐步缩小增量:重复上述过程,直到整个数组基本有序,最后使用增量为1的插入排序完成最终排序。
时间复杂度:O(n^1.3 )至 O( n^1.5)之间。
空间复杂度:O(1)。
稳定性:不稳定。
代码:
public void shellSort(int[] array){int gap=array.length;while(gap>1){gap=gap/2;shell(array,gap);}}private void shell(int[] array, int gap) {int tmp=0;for (int i = gap; i < array.length ; i++) {tmp=array[i];int j=i-gap;for(;j>=0;j-=gap){if(tmp<array[j]){array[j+gap]=array[j];}else{break;}}array[j+gap]=tmp;}}
三、选择排序
3.1 选择排序
思想:
选择排序是一种简单直观的排序算法。它的核心思想是:
- 每次从未排序的部分中选择最小(或最大)的元素,并将其放到已排序部分的末尾。
- 重复上述过程,直到所有元素都被排序。
时间复杂度:O(N^2)。
空间复杂度:O(1)。
稳定性:不稳定。
代码:
public void selectSort(int[] array){int minIndex=0;for (int i=0;i<array.length;i++){minIndex=i;for(int j=i+1;j<array.length;j++){if(array[minIndex]>array[j]){minIndex=j;}}int tmp=array[i];array[i]=array[minIndex];array[minIndex]=tmp;}}
延伸:
思路:
定义两个变量‘minIndex’和‘maxIndex’来接收遍历完一遍数组得到的最大值和最小值下标,将得到的最大值和最小值下标分别与这组数组的最左边和最右边的值交换,以此类推。
时间复杂度:O(n²)
空间复杂度:O(1)
稳定性:不稳定
代码:
public void selectSort2(int[] array) {int left=0;int right=array.length-1;int len=array.length;while(left<right){int minIndex=left;int maxIndex=left;for (int i = left; i < len; i++) {if(array[i]<array[minIndex]){minIndex=i;}if(array[i]>array[maxIndex]){maxIndex=i;}}swap(array,left,minIndex);left++;swap(array,right,maxIndex);right--;len--;}}public void swap(int[] array,int x,int y){int tmp=array[x];array[x]=array[y];array[y]=tmp;}
3.2 堆排序
思路:
建立大根堆,将大根堆的堆顶元素和最后一个元素进行交换,交换完后将剩下的堆重新调整,以此类推。
时间复杂度:O(N*logN)。
空间复杂度:O(1)。
稳定性:不稳定。
代码:
public void heapSort(int[] array){//创建堆createHeap(array);int end=array.length-1;while(end>0){swap(array,0,end);shiftDown(array,0,end);end--;}}public void createHeap(int[] array){for(int parent=(array.length-1-1)/2;parent>=0;parent--){shiftDown(array,parent,array.length);}}public void shiftDown(int[] array,int parent,int length){int child =parent*2+1;while(child<length){//如果孩子存在,找到左右孩子中较小的孩子,用child标记if (child + 1 < length && array[child] < array[child+1]) {child++;}if(array[parent]<=array[child]){swap(array,parent,child);parent=child;child=parent*2+1;}else{break;}}}
四、交换排序
4.1 冒泡排序
思想:
核心思想是通过相邻元素之间的比较和交换,逐步将最大(或最小)的元素“冒泡”到数组的末尾(或开头)。这个过程重复进行,直到整个数组有序。
时间复杂度:O(N^2) 。
空间复杂度:O(1)。
稳定性:稳定。
代码:
public void bubbleSort(int[] array){boolean flag=true;for (int i = 0; i < array.length-1; i++) {for (int j = 0;j<array.length-1-i;j++ ){if(array[j]>array[j+1]){swap(array,j,j+1);flag=false;}}if(flag){break;}}}
4.2 快速排序
思想:
核心思想是通过分区操作将数组分为两部分,使得一部分的所有元素都小于(或等于)另一部分的所有元素,然后递归地对这两部分进行排序。
时间复杂度:O(N*logN)至O(n^2)。
空间复杂度:O(logN)至O(N)。
稳定性:不稳定。
Hoare法:
思路:
选定序列第一个为基准,从后边往前找到比基准小的停下来,从前边找到比基准大的停下来,交换直到左右相遇,相遇下标的值与基准交换。
代码:
public void quickSort(int[] array){hoareSort(array,0,array.length-1);}public void hoareSort(int[] array,int start,int end) {if(start>=end){return;}int pivot = partition(array, start, end);hoareSort(array,start,pivot-1);hoareSort(array,pivot+1,end);}private int partition(int[] array, int left, int right) {int flag=left;while(left<right){while(left<right&&array[right]>=array[flag]){right--;}while(left<right&&array[left]=<array[flag]){left++;}swap(array,left,right);}swap(array,left,flag);return left;}
挖坑法:
思路:
选定序列第一个为基准,从后往前找,找到小于基准的,将其放到基准的位置,接下来从前往后找,找到比基准大的,放到先前后面找到的比基准小的位置,以此类推。
代码:
private int partition2(int[] array, int left, int right) {int flag=array[left];while(left<right){while(left<right&&array[right]>=flag){right--;}array[left]=array[right];while(left<right&&array[left]<=flag){left++;}array[right]=array[left];}array[left]=flag;return left;}
前后指针:
思路:
选定序列第一个为基准,定义两个prev和cur来标记下标,遍历序列,满足cur下标的值小于基准,并且prev++下标和cur下标不在同一个下标,交换prev和cur下标的值,如果不满足条件,cur++。
代码:
private int partition3(int[] array, int left, int right) {int prev=left;int cur=prev+1;while(cur<=right){if(array[cur]<array[left]&&array[++prev]!=array[cur]){swap(array,prev,cur);}cur++;}swap(array,prev,left);return prev;}
4.3 快速排序的优化
4.3.1 三数取中法
优点:
优化性能:通过选择中值作为基准值,减少了因数据分布不均匀而导致的性能退化。
提高稳定性:在处理接近有序或完全逆序的数据时,性能更加稳定。
代码:
public void hoareSort(int[] array,int start,int end) {if(start>=end){return;}int midIndex=getNumber(array,start,end);swap(array,start,midIndex);int pivot = partition(array, start, end);hoareSort(array,start,pivot-1);hoareSort(array,pivot+1,end);}private int getNumber(int[] array,int left,int right){int mid=(left+right)/2;if(array[left]<array[right]){if(array[mid]<array[left]){return left;} else if (array[mid]>array[right]) {return right;}else{return mid;}}else{if(array[mid]<array[right]){return right;} else if (array[mid]>array[left]) {return left;}else{return mid;}}}
4.3.2 递归到小的子区间时,使用直接插入排序
优点:
因为直接插入排序的特点就是越有序越快。
代码:
public void hoareSort(int[] array,int start,int end) {if(start>=end){return;}
// int midIndex=getNumber(array,start,end);
// swap(array,start,midIndex);if (end - start+1 <= 10) {insertSortRange(array,start,end);return;}int pivot = partition(array, start, end);hoareSort(array,start,pivot-1);hoareSort(array,pivot+1,end);}private void insertSortRange(int[] array, int start, int end) {int tmp=0;for(int i=start+1;i<=end;i++){tmp=array[i];int j=i-1;for(;j>=start;j--){if(tmp<array[j]){array[j+1]=array[j];}else{break;}}array[j+1]=tmp;}}
4.4 非递归快速排序
思想:
- 通过挖坑法先求得基准下标
- 通过基准下标将基准左右两边序列的start和end存进栈中,存入栈中的先后顺序要一致
- 通过pop()弹出start和end,再通过挖坑法求得基准下标,以此类推,当栈为空,则证明已经排序好了
代码:
public void quickNor(int[] array,int start,int end) {Stack<Integer> stack=new Stack<>();int pivot = partition2(array, start, end);if(pivot>start+1){stack.push(start);stack.push(pivot-1);}if(pivot<end-1){stack.push(pivot+1);stack.push(end);}while(!stack.isEmpty()){end=stack.pop();start=stack.pop();pivot=partition2(array, start, end);if(pivot>start+1){stack.push(start);stack.push(pivot-1);}if(pivot<end-1){stack.push(pivot+1);stack.push(end);}}}
五、归并排序
5.1 递归归并排序
思路:
归并排序是一种分治排序算法,其核心思想是将数组分成多个小部分,分别对这些小部分进行排序,然后逐步合并这些有序部分,最终得到一个完全有序的数组。
时间复杂度:O(N*logN)。
空间复杂度:O(N)。
稳定性:稳定。
代码:
public void mergeSort(int[] nums) {mergeSortSplit(nums, 0, nums.length - 1);}private void mergeSortSplit(int[] nums, int left, int right) {if (left >= right) {return;}//分解int mid = (left + right) / 2;mergeSortSplit(nums, left, mid-1);mergeSortSplit(nums, mid + 1, right);//合并merge(nums, left, mid, right);}private void merge(int[] nums, int left, int mid, int right) {int[] tmp = new int[right - left + 1];int k=0;int s1=left;int s2=mid + 1;while(s1<=mid&&s2<=right){if(nums[s1]<=nums[s2]){tmp[k++]=nums[s1++];}else{tmp[k++]=nums[s2++];}}while(s1<=mid){tmp[k++]=nums[s1++];}while(s2<=right){tmp[k++]=nums[s2++];}for(int i=left; i<k; i++){nums[i]=tmp[i];}}
5.2 非递归归并排序
public void mergeSortNor(int[] array){int gap=1;while(gap<array.length){for(int i=0;i<array.length;i=i+gap*2){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,mid,right);}gap*=2;}}
六、总结
此篇博客的全部代码!!!
相关文章:

【Java数据结构】排序
【Java数据结构】排序 一、排序1.1 排序的概念1.2 排序的稳定性1.3 内部排序和外部排序1.3.1 内部排序1.3.2 外部排序 二、插入排序2.1 直接插入排序2.2 希尔排序 三、选择排序3.1 选择排序3.2 堆排序 四、交换排序4.1 冒泡排序4.2 快速排序Hoare法:挖坑法ÿ…...

我的求职之路合集
我把我秋招和春招的一些笔面试经验在这里发一下,网友们也可以参考一下。 我的求职之路:(1)如何谈自己的缺点 我的求职之路:(2)找工作时看重的点 我的求职之路:(3&…...

数据结构(四) B树/跳表
目录 1. LRU 2. B树 3. 跳表 1. LRU: 1.1 概念: 最近最少使用算法, 就是cache缓存的算法. 因为cache(位于内存和cpu之间的存储设备)是一种容量有限的缓存, 有新的数据进入就需要将原本的数据进行排出. 1.2 LRU cache实现: #include <iostream> #include <list>…...

Arcgis国产化替代:Bigemap Pro正式发布
在数字化时代,数据如同新时代的石油,蕴含着巨大的价值。从商业决策到科研探索,从城市规划到环境监测,海量数据的高效处理、精准分析与直观可视化,已成为各行业突破发展瓶颈、实现转型升级的关键所在。历经十年精心打磨…...

LBS 开发微课堂|AI向导接口服务:重塑用户的出行体验
为了让广大开发者 更深入地了解 百度地图开放平台的 技术能力 轻松掌握满满的 技术干货 更加简单地接入 位置服务 我们特别推出了 “位置服务(LBS)开发微课堂” 系列技术案例 第六期的主题是 《AI向导接口服务的能力与接入方案》 随着地图应…...

AI导航工具我开源了利用node爬取了几百条数据
序言 别因今天的懒惰,让明天的您后悔。输出文章的本意并不是为了得到赞美,而是为了让自己能够学会总结思考;当然,如果有幸能够给到你一点点灵感或者思考,那么我这篇文章的意义将无限放大。 背景 随着AI的发展市面上…...

openstack单机安装
openstack单机安装 网卡配置安装依赖开启虚拟环境修改配置文件 部署openstack部署openstack客户端访问可视化界面Horizon补充 本篇主要讲述Ubuntu2204单机安装openstackstable/2024.2。其他版本的Linux系统或者openstack版本,请参考openstack官网。 网卡配置 需要配…...

Vue3实现小红书瀑布流布局任意组件动态更新页面方法实践
思路 1.首先定义一个瀑布流容器,它的高度暂定(后面会更新)。把需要布局的组件(这里叫做waterfall-item)放在瀑布流容器里面渲染出来。使用绝对定位(position: absolute),把它移到屏幕…...

深度学习项目--基于LSTM的糖尿病预测探究(pytorch实现)
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 前言 LSTM模型一直是一个很经典的模型,一般用于序列数据预测,这个可以很好的挖掘数据上下文信息,本文将使用LSTM进行糖尿病…...

Next.js 实战 (十):中间件的魅力,打造更快更安全的应用
什么是中间件? 在 Next.js 中,中间件(Middleware)是一种用于处理每个传入请求的功能。它允许你在请求到达页面之前对其进行修改或响应。 通过中间件,你可以实现诸如日志记录、身份验证、重定向、CORS配置、压缩等任务…...

python+playwright自动化测试(四):元素操作(键盘鼠标事件)、文件上传
目录 鼠标事件 悬停 移动 按键 点击 滚轮操作 拖拽 键盘事件 输入文本内容 type输入内容 fill输入内容 按键操作press 文件上传 下拉选/单选框/复选框 滚动条操作 鼠标事件 悬停 page.get_by_text(设置,exactTrue).nth(1).hover() 移动 page.mouse.move(x33…...

【论文+源码】Diffusion-LM 改进了可控文本生成
这篇论文探讨了如何在不重新训练的情况下控制语言模型(LM)的行为,这是自然语言生成中的一个重大开放问题。尽管近期一些研究在控制简单句子属性(如情感)方面取得了成功,但在复杂的细粒度控制(如…...

双目立体校正和Q矩阵
立体校正 对两个摄像机的图像平面重投影,使二者位于同一平面,而且左右图像的行对准。 Bouguet 该算法需要用到双目标定后外参(R,T) 从上图中可以看出,该算法主要分为两步: 使成像平面共面 这个办法很直观ÿ…...

vscode 自用插件
vscode按住ctrl鼠标左键无法跟踪跳转方法名,装这些插件就可以 vscode-elm-jump:常规的代码跳转定义 Vue CSS Peek:跳转css定义 vue-helper:变量函数只跳转定义 Vetur 代码提示 Baidu Comate 自动帮你写console.log Turbo Console Log: ctrl alt l 选中变量之后&am…...

OpenCV:在图像中添加高斯噪声、胡椒噪声
目录 在图像中添加高斯噪声 高斯噪声的特性 添加高斯噪声的实现 给图像添加胡椒噪声 实现胡椒噪声的步骤 相关阅读 OpenCV:图像处理中的低通滤波-CSDN博客 OpenCV:高通滤波之索贝尔、沙尔和拉普拉斯-CSDN博客 OpenCV:图像滤波、卷积与…...

DuckDB:Golang操作DuckDB实战案例
DuckDB是一个嵌入式SQL数据库引擎。它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的。DuckDB支持各种数据类型和SQL特性。凭借其在以内存为中心的环境中处理高速分析的能力,它迅速受到数据科学家和分析师的欢迎。在这篇博文中࿰…...

MySQL入门(数据库、数据表、数据、字段的操作以及查询相关sql语法)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

kotlin的协程的基础概念
Kotlin的协程是一种用于简化异步编程的强大工具。 理解协程的基础概念可以帮助开发者有效地利用其能力。 以下是Kotlin协程的一些关键基础概念: 协程(Coroutines) : 协程是一种用于处理并发任务的编程模型,它可以在单…...

Spring--SpringMVC使用(接收和响应数据、RESTFul风格设计、其他扩展)
SpringMVC使用 二.SpringMVC接收数据2.1访问路径设置2.2接收参数1.param和json2.param接收数据3 路径 参数接收4.json参数接收 2.3接收cookie数据2.4接收请求头数据2.5原生api获取2.6共享域对象 三.SringMVC响应数据3.1返回json数据ResponseBodyRestController 3.2返回静态资源…...

隐藏php版本信息x-powered-by
在生产环境中,并不想让别人知道用的是什么版本的php,可以把x-powered-by隐藏掉 在nginx配置文件加上fastcgi_hide_header X-Powered-By; 如下图所示 配置修改后平滑重启nginx...

哈夫曼树(构建、编码、译码)(详细分析+C++代码实现)
D 哈夫曼树 题目要求 编写一个哈夫曼编码译码程序。针对一段文本,根据文本中字符出现频率构造哈夫曼树,给出每个字符的哈夫曼编码,并进行译码,计算编码前后文本大小。 为确保构建的哈夫曼树唯一,本题做如下限定&…...

C++ 二叉搜索树
目录 概念 性能分析 二叉搜索树的插入 二叉树的查找 二叉树的前序遍历 二叉搜索树的删除(重点) 完整代码 key与value的使用 概念 对于一个二叉搜索树 若它的左子树不为空,则左子树上所有的节点的值都小于等于根节点的值若它的右子树不为空…...

docker构建Java项目镜像常用的Java版本,国内私有仓库公网快速下载,解决从docker.io无法下载的问题
2015工作至今,10年资深全栈工程师,CTO,擅长带团队、攻克各种技术难题、研发各类软件产品,我的代码态度:代码虐我千百遍,我待代码如初恋,我的工作态度:极致,责任ÿ…...

低代码系统-氚云、简道云表单控件对比
组件对比 氚云 简道云 是否都有 1 单行文本 单行文本 ☑️ 2 多行文本 多行文本 ☑️ 3 日期 日期时间 ☑️ 4 数字 数字 ☑️ 5 单选框 单选按钮组 ☑️ 6 复选框 复选框组 ☑️ 7 下拉框 下拉框 ☑️ 8 附件 附件 ☑️ 9 图片 图片 ☑️ 10 地址 地…...

为什么IDEA提示不推荐@Autowired❓️如果使用@Resource呢❓️
前言 在使用 Spring 框架时,依赖注入(DI)是一个非常重要的概念。通过注解,我们可以方便地将类的实例注入到其他类中,提升开发效率。Autowired又是被大家最为熟知的方式,但很多开发者在使用 IntelliJ IDEA …...

Unity在WebGL中拍照和录视频
原工程地址https://github.com/eangulee/UnityWebGLRecoder Unity版本2018.3.6f1,有点年久失修了 https://github.com/xue-fei/Unity.WebGLRecorder 修改jslib适配了Unity2021 效果图 录制的视频 Unity在WebGL中拍照和录视频...

爬虫基础之爬取某站视频
目标网址:为了1/4螺口买小米SU7,开了一个月,它值吗?_哔哩哔哩_bilibili 本案例所使用到的模块 requests (发送HTTP请求)subprocess(执行系统命令)re (正则表达式操作)json (处理JSON数据) 需求分析: 视频的名称 F12 打开开发者工具 or 右击…...

mongoDB常见指令
即使我们自己开发用不到mongoDB,但是接手别人项目的时候,别人如果用了,我们也要会简单调试一下 虽然mongoDB用的不是sql语句,但语句的逻辑都是相似的,比如查看数据库、数据表,增删改查这些 我们下面以doc…...

人工智能之深度学习_[5]-神经网络优化学习率衰减优化正则化方法
文章目录 神经网络入门二3 神经网络优化方法3.1 梯度下降算法回顾3.2 反向传播(BP算法)3.2.1 反向传播概念3.2.2 反向传播详解 3.3 梯度下降优化方法3.3.1 指数加权平均3.3.2 动量算法Momentum3.3.3 AdaGrad3.3.4 RMSProp3.3.5 Adam3.3.6 小结 4 学习率衰…...

Oracle之Merge into函数使用
Merge into函数为Oracle 9i添加的语法,用来合并update和insert语句。所以也经常用于update语句的查询优化: 一、语法格式: merge into A using B on (A.a B.a) --注意on后面带括号,且不能更新join的字段 when matched then upd…...