【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 选择排序

思想:

选择排序是一种简单直观的排序算法。它的核心思想是:

  1. 每次从未排序的部分中选择最小(或最大)的元素,并将其放到已排序部分的末尾。
  2. 重复上述过程,直到所有元素都被排序。

时间复杂度: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 非递归快速排序

思想:

  1. 通过挖坑法先求得基准下标
  2. 通过基准下标将基准左右两边序列的start和end存进栈中,存入栈中的先后顺序要一致
  3. 通过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;}}

六、总结

在这里插入图片描述
此篇博客的全部代码!!!

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

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

相关文章

内存 管理

1、如何在LCD上面实现SD卡文件浏览&#xff1f; 需要读取所有文件名到内存&#xff0c;方法是定义一个数组才存储所有文件名。&#xff08;最大文件名的长度和文件个数&#xff09; 2、内存管理是什么&#xff1f; 指软件运行时对MCU内存资源的分配和使用的技术。要实现两个函…

1月21日星期二今日早报简报微语报早读

1月21日星期二&#xff0c;农历腊月廿二&#xff0c;早报#微语早读。 1、多地官宣&#xff1a;2025年可有序、限时或在限定区域燃放烟花爆竹&#xff1b; 2、TikTok恢复在美服务&#xff1b;特朗普提出继续运营TikTok方案&#xff0c;外交部&#xff1a;若涉及收购中国企业应…

深度学习python基础(第三节) 函数、列表

本节主要介绍函数、列表的基本语法格式。 函数 与c语言的函数差不多&#xff0c;就是语法基本格式不同。 name "loveyou" length len(name) print("字符串的长度为&#xff1a;%d" % length) # 自定义函数 def countstr(data):count 0for i in da…

STM32 FreeROTS Tickless低功耗模式

低功耗模式简介 FreeRTOS 的 Tickless 模式是一种特殊的运行模式&#xff0c;用于最小化系统的时钟中断频率&#xff0c;以降低功耗。在 Tickless 模式下&#xff0c;系统只在有需要时才会启动时钟中断&#xff0c;而在无任务要运行时则完全进入休眠状态&#xff0c;从而降低功…

65,【5】buuctf web [SUCTF 2019]Upload Labs 2

进入靶场 1,源代码 点击题目时有个就有个admin.php <?php // 引入配置文件 include config.php;class Ad{public $cmd;public $clazz;public $func1;public $func2;public $func3;public $instance;public $arg1;public $arg2;public $arg3;// 构造函数&#xff0c;用于初…

Apache Tomcat文件包含漏洞复现(详细教程)

1.漏洞原理 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;其安装后会默认开启ajp连接器&#xff0c;方便与其他web服务器通过ajp协议进行交互。属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发…

springboot基于安卓的智启教育服务平台app

基于Spring Boot的智启教育服务平台App是一个结合了Spring Boot后端框架与安卓前端技术的综合性教育服务平台。 一、技术背景与架构 1.开发语言&#xff1a;后端采用Java语言开发&#xff0c;充分利用Java的跨平台性、面向对象特性和强大的后端处理能力。前端则使用安卓开发技…

我的创作纪念日,纪念我的第512天

目录 年末 年初 入围 博客 变动 生活 期待 年末 很快&#xff0c;2024年已经过去了&#xff0c;本想在跨年夜的时候营造一点小小的仪式感&#xff0c;结果也因为身体的原因放弃了&#xff0c;浑身感觉疼痛&#xff0c;躺在床上&#xff0c;闭上眼睛&#xff0c;什么也不…

2025/1/21 学习Vue的第四天

睡觉。 --------------------------------------------------------------------------------------------------------------------------------- 11.Object.defineProperty 1.在我们之前学习JS的时候&#xff0c;普通得定义一个对象与属性。 <!DOCTYPE html> <h…

卸载和安装Git小乌龟、git基本命令

卸载 Git 打开控制面板&#xff1a; 按 Win R 打开运行对话框&#xff0c;输入 control 并按回车键。或直接在功能搜索里搜索“控制面板”。在控制面板中&#xff0c;选择“程序”或“程序和功能”。 查找并卸载 Git&#xff1a; 在程序列表中找到“Git”或“Git for Windows…

OSI5GWIFI自组网协议层次对比

目录 5G网络5G与其他协议栈各层映射 5G网络 物理层 (PHY) 是 5G 基站协议架构的最底层&#xff0c;负责将数字数据转换为适合无线传输的信号&#xff0c;并将接收到的无线信号转换为数字数据。实现数据的编码、调制、多天线处理、资源映射等操作。涉及使用新的频段&#xff08…

ThinkPHP 8的多对多关联

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…

可视化-numpy实现线性回归和梯度下降法

代码如下&#xff1a; import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib.patches import Patch# 生成二维输入数据 np.random.seed(0) X1 2 * np.random.rand(100, 1) # 第一个特征 X2 3 * np.random.rand(10…

python_在钉钉群@人员发送消息

python_在钉钉群人员发送消息 1、第一种 企业内部机器人群聊实现人接入指南&#xff0c;适用于群机器人接收消息&#xff0c;处理完一系列的动作之后&#xff0c;将消息返回给发消息的人员&#xff0c;同时该人员。 需要在企微后台新建一个自建应用&#xff0c;在自建应用里…

递归练习六(普通练习11-15)

一、例题 1、有效数独 36. 有效的数独 - 力扣&#xff08;LeetCode&#xff09; 2、填数独 37. 解数独 - 力扣&#xff08;LeetCode&#xff09; 3、单词搜索 79. 单词搜索 - 力扣&#xff08;LeetCode&#xff09; 4、黄金矿工 1219. 黄金矿工 - 力扣&#xff08;LeetCod…

【生产力工具】ChatGPT for Windows桌面版本安装教程

使用桌面版的ChatGPT目前可解决官方轻微降智的问题。 文章目录 准备安装步骤步骤 1: 更改系统区域设置步骤 2: 关闭系统代理&#xff08;如果你正在使用的话&#xff09;步骤 3: 启动EXE文件步骤 4: 完成安装 准备 下载并保存好 ChatGPT桌面版的EXE安装文件。 下载地址1&…

兼职全职招聘系统架构与功能分析

2015工作至今&#xff0c;10年资深全栈工程师&#xff0c;CTO&#xff0c;擅长带团队、攻克各种技术难题、研发各类软件产品&#xff0c;我的代码态度&#xff1a;代码虐我千百遍&#xff0c;我待代码如初恋&#xff0c;我的工作态度&#xff1a;极致&#xff0c;责任&#xff…

【ESP32】ESP32连接JY61P并通过WIFI发送给电脑

前言 手头上有个ESP32&#xff0c;发现有wifi功能&#xff0c;希望连接JY61P并通过WIFI把姿态数据发送给电脑 1.采用Arduino IDE编译器&#xff1b;需要安装ESP32的开发板管理器&#xff1b; 2.电脑接受数据是基于python的&#xff1b; 1. ESP32 连接手机WIFI #include <…

第23篇 基于ARM A9处理器用汇编语言实现中断<五>

Q&#xff1a;怎样修改HPS Timer 0定时器产生的中断周期&#xff1f; A&#xff1a;在上一期实验的基础上&#xff0c;可以修改按键中断服务程序&#xff0c;实现红色LED上的计数值递增的速率&#xff0c;主程序和其余代码文件不用修改。 实现以下功能&#xff1a;按下KEY0…

E-Prime2实现List嵌套

用E-Prime实现一个简单的List嵌套&#xff0c;实验流程基于斯特鲁程序&#xff08;色词一致/不一致实验&#xff09;。 首先File-New&#xff0c;新建一个空白项目 此时生成流程如下 Experiment Object是实验中被用到的流程或者控件对象&#xff0c;SessionProc是总流程&#x…