排序-八大排序FollowUp

news/2024/5/17 11:58:17

FollowUp

1.插入排序

(1).直接插入排序

时间复杂度:
最坏情况下:0(n^2)
最好情况下:0(n)
当数据越有序 排序越快

适用于: 待排序序列 已经基本上趋于有序了!
空间复杂度:0(1)
稳定性:稳定的

   public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {int tmp = array[i];int j = i - 1;for (; j >= 0 ; j--) {//这里加不加等号 和稳定有关系// 但是:本身就是一个稳定的排序 可以实现为不稳定的排序// 但是 本身就是一个不稳定的排序 是不可能变成一个稳定的排序的if(array[j] > tmp){array[j + 1] = array[j];}else {break;}}array[j+1] = tmp;}}

 (2).希尔排序(缩小增量排序)

重点是最后还是会把整体作一组来直接插入排序

  public static void shellSort(int[] array){int gap = array.length;while(gap > 1){shell(array,gap);gap /= 2;}}public static void shell(int[] array, int gap){for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i - gap;for (;j >= 0; j -= gap) {if(array[j] > tmp){array[j+gap] = array[j];}else {break;}}array[j+gap] = tmp;}}

 2.选择排序

(1).直接选择排序

在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

    public static void selectSort(int[] array){for (int i = 0; i < array.length; i++) {int mixIndex = i;for (int j = i+1; j < array.length; j++) {if(array[mixIndex] > array[j]){mixIndex = j;}}int tmp = array[i];array[i] = array[mixIndex];array[mixIndex] = tmp;}}

【直接选择排序的特性总结】
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

(2.)双向选择排序:

 public static void selectSort2(int[] array){int left = 0;int right = array.length-1;while(left < right){int minIndex = left;int maxIndex = left;for (int i = left+1; i < right; i++) {if(array[i] > array[maxIndex]){maxIndex = i;}if(array[i] < array[minIndex]){minIndex = i;}swap(array,left,minIndex);//防止最大的是在第一个的时候if(maxIndex == left){maxIndex = minIndex;}swap(array,right,maxIndex);left++;right--;}}}

(3).堆排序

具体的思路在PriorityQueue(一)——用堆实现优先级队列

    public static void heapSort(int[] array){creatHeap(array);int end = array.length-1;while(end > 0){swap(array,0,end);siftDown(array,0,end);end--;}}private static void creatHeap(int[] array) {for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {siftDown(array,parent,array.length);}}private static void siftDown(int[] array,int parent,int len) {int child = 2*parent + 1;while(child < len){if(child +1 < len && array[child] < array[child+1]){child++;}if(array[child] > array[parent]){swap(array,child,parent);parent = child;child = 2*parent + 1;}else {break;}}}
public static void swap(int[] array, int i, int j){int tmp = array[i];array[i] = array[j];array[j] = tmp;}

3.交换排序

(1).冒泡排序

优化:

时间复杂度:0(N^2)
如果加了优化:最好情况下 可以达到0(n)

空间复杂度:0(1)

稳定性:稳定的排序
优化:每一趟都需要判断 上一趟 有没有交换

    public static void bubbleSort(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]){swap(array,j,j+1);flg =true;}}//说明上一趟没有交换,也就是有序了if(!flg){break;}}}public static void swap(int[] array, int i, int j){int tmp = array[i];array[i] = array[j];array[j] = tmp;}

(2).快速排序 

 
时间复杂度
最好的情况下:0(N*logN) 最坏情况下:0(N^2)逆宇|有序空间复杂度:
最好的情况下:0(logN) 最坏情况下:0(N)逆序/有序
稳定性:不稳定

快排最好和最坏情况分析

Hoare法

记录下key L和R相向出发,R找比Key小的值,L找比Key大的值,R先找找到后,L再找,两个找到交换;直到L和R相遇,相遇的位置为最后L找到的小于Key的值(让R先找的原因),此时的L就是pivot ,将Key和L交换

然后以pivot为中点,将它左右两边的循环以上操作也就是递归直到传入的L和R为相同的,那么任何一个以pivot为中点的数组都变成有序的了

pivot指的是l和r相遇的位置 

  public static void  quickSort(int[] array){quick(array,0, array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end){return;}int pivot = partitionHoare(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int partitionHoare(int[] array, int left, int right) {int tmp = array[left];int i = left;while(left < right){while(left < right && array[right] >= tmp){right--;}while (left < right && array[left] <= tmp){left++;}swap(array,left,right);}swap(array,i,left);return left;}

总结:

 

 

 挖坑法

向将L的第一个位置为key,也就是坑位置,然后还是R先走找到比key小的就将R下标的值给坑位,此时R为坑位,L再走,找到比L大的值,放到坑位,L此时变为坑位,直到R和L相遇,还是保证L和R相遇的时候,是R找的比Key小的放到坑位里,然后将相遇的坑位放入Key

   public static void  quickSort(int[] array){quick(array,0, array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end){return;}int pivot = partitionHole(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int partitionHole(int[] array, int left, int right) {int tmp = array[left];int t = left;while(left < right){while(left < right && array[right] >= tmp){right--;}array[left] = array[right];while (left < right && array[left] <= tmp){left++;}array[right] = array[left];}array[left] = tmp;return left;}

总结: 

前后指针法

cur指向left加1的位置,prev指向left的位置,cur往前走,当遇到一个小于left下标值,并且此时cur和prev指向的不是同一个位置,那么cur和prev下标的值互换,直到cur超过right此时将prev和left下标的值互换,并返回prev,即是相对的中间位置

 public static void quickSort(int[] array) {quick(array, 0, array.length - 1);}
public static int partition(int[] array, int left, int right){int prev = left;int cur = left + 1;while (cur <= right){if(array[cur] < array[left] && array[++prev] != array[cur]){swap(array,prev,cur);}cur++;}swap(array,left,prev);return prev;}private static void quick(int[] array,int start,int end) {if(start >= end){return;}if(end - start + 1 <= 15){insertSort(array,start,end);return;}int index = middleNume(array,start,end);swap(array,start,index);int pivot = partition(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}

优化

 public static void  quickSort(int[] array){quick(array,0, array.length-1);}    
private static void quick(int[] array,int start,int end) {if(start >= end){return;}if(end - start + 1 <= 15){insertSort(array,start,end);return;}int index = middleNume(array,start,end);swap(array,start,index);int pivot = partitionHoare(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int middleNume(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;}}}public static void insertSort(int[] array,int left,int right){for (int i = left+1; i <= right; i++) {int tmp = array[i];int j = i - 1;for (; j >= left ; j--) {if(array[j] > tmp){array[j + 1] = array[j];}else {break;}}array[j+1] = tmp;}}

非递归的方法 

  public static void  quickSortNor(int[] array){int start = 0;int end = array.length -1;Stack<Integer> stack =new Stack<>();int pivot = partitionHoare(array,start,end);if(pivot - 1 > start){stack.push(start);stack.push(pivot-1);}if(pivot+1 < end){stack.push(pivot+1);stack.push(end);}while(!stack.empty()){end =stack.pop();start = stack.pop();pivot = partitionHoare(array,start,end);if(pivot - 1 > start){stack.push(start);stack.push(pivot-1);}if(pivot+1 < end){stack.push(pivot+1);stack.push(end);}}}private static int partitionHoare(int[] array, int left, int right) {int tmp = array[left];int i = left;while(left < right){while(left < right && array[right] >= tmp){right--;}while (left < right && array[left] <= tmp){left++;}swap(array,left,right);}swap(array,i,left);return left;}

4. 归并排序

时间复杂度:0(N*logN)

空间复杂度:0(logN)

稳定性:稳定的

排序目前为止3个稳定的排序:直接插入排序、冒泡排序、归并排序

   public static void mergeSort(int[] array){mergeSortFun(array,0,array.length-1);}public static void mergeSortFun(int[] array,int start,int end){if(start >= end){return;}int mid = (start + end)/2;mergeSortFun(array,start,mid);mergeSortFun(array,mid+1,end);//左右两边数组合并merge(array,start,mid,end);}public static void merge(int[] array,int left,int mid, int right){int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;//两边的数组合并数组的长度int[] tmpArray = new int[right - left +1];int k = 0;while (s1 <= e1 && s2 <= e2){if(array[s1] < array[s2]){tmpArray[k++] = array[s1++];}else {tmpArray[k++] = array[s2++];}}while (s1 <= e1){tmpArray[k++] = array[s1++];}while (s2 <= e2){tmpArray[k++] = array[s2++];}for (int i = 0; i < tmpArray.length; i++) {array[left+i] = tmpArray[i];}}

 非递归

   public static void merge(int[] array,int left,int mid, int right){int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;//两边的数组合并数组的长度int[] tmpArray = new int[right - left +1];int k = 0;while (s1 <= e1 && s2 <= e2){if(array[s1] < array[s2]){tmpArray[k++] = array[s1++];}else {tmpArray[k++] = array[s2++];}}while (s1 <= e1){tmpArray[k++] = array[s1++];}while (s2 <= e2){tmpArray[k++] = array[s2++];}for (int i = 0; i < tmpArray.length; i++) {array[left+i] = tmpArray[i];}}public static 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;int right = mid + gap;if(mid >= array.length){mid = array.length - 1;}if(right >= array.length){right = array.length - 1;}merge(array,left,mid,right);}gap = gap*2;}}

5.非比较排序

 使用场景是给定一个指定的待排序的序列

    public static void countSort(int[] array){int minVal = array[0];int maxVal = array[0];for (int i = 0; i < array.length; i++){if(array[i] > maxVal){maxVal = array[i];}if(array[i] < minVal){minVal = array[i];}}int len = maxVal - minVal + 1;int[] count = new int[len];for (int i = 0; i < array.length; i++) {count[array[i]-minVal]++;}int index = 0;for (int i = 0; i < array.length; i++) {while(count[0] > 0){array[index] = i + minVal;index++;count[i]--;}}}

 海量数据的排序问题


外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序
1. 先把文件切分成 200 份,每个 512 M
2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
3. 进行 2路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

 记录当前电脑的时间

long startTime =System.currentTimeMillis();


http://www.mrgr.cn/p/60357518

相关文章

项目运行到手机端

运行到真机 手机和点到连在同一个wifi网络下面点击hbuiler上面的预览得到一个&#xff0c;network的网址这个时候去在手机访问&#xff0c;那么就可以访问网页了 跨域处理 这个时候可能会访问存在跨域问题 将uniapp的H5版本运行到真机进行调试&#xff0c;主要涉及到跨域问题…

Ubuntu 24.04 LTS (Noble Numbat) 正式版发布

Ubuntu 24.04 LTS (Noble Numbat) 正式版发布 Canonical 的第 10 个长期支持版本在性能工程、企业安全和开发人员体验方面树立了新标准 请访问原文链接&#xff1a;Ubuntu 24.04 LTS (Noble Numbat) 正式版发布&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。…

数组模拟双链表-java

通过数组来模拟双链表&#xff0c;并执行一些插入和删除的功能。 目录 一、问题描述 二、模拟思路 1.变量解释 2.数组初始化 3.在下标是k的结点后面插入一个结点 4.删除下标为k的结点 5.基本功能解释 三、代码如下 1.代码如下&#xff1a; 2.读入数据&#xff1a; 3…

Java设计模式 _结构型模式_桥接模式

一、桥接模式 1、桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式。用于把一个类中多个维度的抽象化与实现化解耦&#xff0c;使得二者可以独立变化。 2、实现思路 使用桥接模式&#xff0c;一定要找到这个类中两个变化的维度&#xff1a;如支…

使用LinkAI创建AI智能体,并快速接入到微信/企微/公众号/钉钉/飞书..

LinkAI 作为企业级一站式AI Agent 智能体搭建与接入平台,可以使用LinkAI创建专属智能体,并将它连接到并快速接入到微信/企微/公众号/钉钉/飞书/web等​ LinkAI 作为企业级一站式AI Agent 智能体搭建与接入平台,不仅为用户和客户提供能够快速搭建具备行业知识和个性化设定的 …

基于CodeMirror开发在线编辑器时遇到的问题及解决方案

需求:实现json在线编辑并支持校验,基于此使用了 CodeMirror在线编辑,jsonlint校验输入数据 // package.json:"dependencies": {"codemirror": "^5.53.2","core-js": "^3.8.3","jsonlint": "^1.6.3",…

【VMware vCenter】连接和使用vCenter Server嵌入式vPostgres数据库。

vCenter Server 早期支持内嵌(embedded)和外部(external)数据库,内嵌数据库就是vPostgres,基于VMware Postgres数据库(PostgreSQL数据库),外部数据库用的多的是Oracle数据库和SQL Server数据库。因为早期使用内嵌的PostgreSQL数据库只能用于小型环境,比如仅支持几十台…

对于 CF1107E 中 dp 状态设计的一点想法

我在这延伸谱线誊写勾勒 / 试图将歌唱的意义勘破不太想发到洛谷讨论区,就往这里放了。 我觉得现有的题解都没说明白为什么本题的状态和转移能覆盖所有情况,并且感觉也非常不自然,没见过的话感觉挺难发现这么一个东西。 然而这个 dp 其实是可以自然地推导出来的。 首先发现这…

线性代数-行列式-p1 矩阵的秩

目录 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质 4. 自己补充点

网络应用层之(6)L2TP协议详解

网络应用层之(6)L2TP协议 Author: Once Day Date: 2024年5月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

解决vscode连接远程服务器出现Bad owner or permissions on C:\\Users\\Administrator/.ssh/config 过程试图写入的管道不存在。

1.找到.ssh文件夹。它通常位于C:\Users2.右键单击.ssh文件夹,然后单击“属性”,选择“安全”3.单击“高级”。 单击“禁用继承”,单击“确定”。 将出现警告弹出窗口。单击“从此对象中删除所有继承的权限”。 4.此时所有用户都将被删除。添加所有者。在同一窗口中,单击“编…

TCP的三次握手过程

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的...TCP是面向连接的、可靠的、基于字节流的传输层通信协议。 TCP是面向连接的协议,所以使用 TCP前必须先建立连接,而建立连接…

C++成员初始化列表

我们在类的构造函数中使用成员初始化列表可以带来效率上的提升&#xff0c;那么成员初始化列表在编译后会发生什么就是这篇文章要探究的问题 文章目录 引入成员初始化列表用成员初始化列表优化上面的代码成员初始化列表展开成员初始化列表的潜在危险 参考资料 引入 考虑下面这…

天地图路径规划功能实现

目录 1、天地图路径规划2、路径规划3、参数说明4、Demo 1、天地图路径规划 天地图Web服务API为用户提供HTTP/HTTPS接口&#xff0c;即开发者可以通过这些接口使用各类型的地理信息数据服务&#xff0c;可以基于此开发跨平台的地理信息应用。 Web服务API对所有用户开放。使用本…

windows密码存储以及hashdump所得信息解析

1. windows登录的明文密码,存储过程是怎么样的,密文存在哪个文件下,该文件是否可以打开,并且查看到密文 在Windows中密码通常不会以明文形式存储。系统会通过保存密码的哈希值来确保安全性。 这个过程涉及到NTLM或Kerberos身份认证协议,它们负责加密存储密码。 以下是存储…

【模板】生成函数 I

多项式与形式幂级数多项式:\(A(x)=\sum\limits_{i=0}^{n}a_ix^i\)。 形式幂级数:\(A(x)=\sum\limits_{i\ge0}a_ix^i\)。形式幂级数不用考虑其收敛域。形式幂级数(多项式)的运算 设 \(A(x)=\sum\limits_{i\ge0}a_ix^i,B(x)=\sum\limits_{i\ge0}b_ix^i\)。\(A(x)+B(x)=\sum\l…

两院院士泌尿外科专家吴阶平教授

吴阶平&#xff08;1917-2011&#xff09;&#xff0c;男&#xff0c;江苏常州人&#xff0c;1933年天津汇文中学毕业&#xff0c;保送到北平燕京大学医预科&#xff0c;1937年毕业于北平燕京大学获理学士学位&#xff0c;1942年毕业于北平协和医学院获医学博士学位&#xff0c…

用 Python 开发一个【GIF表情包制作神器】

用python成为了微信斗图届的高手然后,好多人表示:虽然存了很多表情包但似乎还不是很过瘾因为它不可以自己来定制我们可不可以根据一些表情素材然后自己制作专属表情包呢像这样本来小帅b想自己实现一个表情包制作器后来发现已经有人在 GitHub 分享了 主要功能就是 可以在原有的…

云原生Kubernetes: K8S 1.29版本 部署Sonarqube

一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K8S node节点1.29.0192.168.204.10已部署Kuboard &#xff08;2&#xff09;master节点查看集群 1&…

DRM

DRM是Linux目前主流的图形显示框架,相比FB架构,DRM更能适应当前日益更新的显示硬件。 比如FB原生不支持多层合成,不支持VSYNC,不支持DMA-BUF,不支持异步更新,不支持fence机制等等,而这些功能DRM原生都支持。 同时DRM可以统一管理GPU和Display驱动,使得软件架构更为统一…