JAVA-数据结构-排序

1.直接插入排序

1.原理:和玩扑克牌一样,从左边第二个牌开始,选中这个,和前面的所有牌比较,插在合适的位置

public static void insertsort(int[] arr){//直接插入排序for (int i = 1; i < arr.length; i++) {//此循环用来从1开始确定牌的位置int j = i-1;//得到j前面一个元素int tmp = arr[i];//将i处元素取出来,用来作比较for (; j >=0 ; j--) {//此循环用来和i前面的比较,将i放在正确的位置if(arr[j] > tmp){arr[j+1] = arr[j];//若i前面的比i大则将前面的值赋值给后面}else{
//                    arr[j+1] = tmp;break;//比前面都要大,没有比较的必要}}arr[j+1] = tmp;//j走完上面循环为-1,上面走完一次循环j=0时为空,}}

直接插入排序特点

1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定

2.希尔排序

希尔排序是直接插入排序的Promax版本,将直接插入排序分为n份,比较完n份,排序即成功

思想:先选定一个整数,把待排序文件中所有记录分成多个组,
所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达
=1时,所有记录在统一组内排好序。

public static void shellSort(int[] array){//希尔排序是直接插入排序的优化int gap = array.length;while(gap > 0){//将每组距离最终干为1,即可成功gap /= 2;//得到每组的距离shell(array,gap);}}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--) {if(array[j] > tmp){array[j+gap] = array[j];}else{array[j+gap] = tmp;break;}}array[j+gap] = tmp;}}

3.选择排序

基本思想:一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元
素排完 。

 public static void selsctSort1(int[] array){//选择排序基础版for (int i = 0; i < array.length; i++) {int minIndex = i;//每循环一次确定一个从左往右的最小值int j = i+1;for (; j <array.length; j++) {if(array[minIndex] > array[j]){minIndex = j;//将minTndex和j的下标先进行交换,找到最小的和其交换}//从一次次循环中得出在[i,length)的最小值}swap(array,minIndex,i);}}public static void selsctSort(int[] array){//选择排序promax版int left = 0;int right = array.length-1;while (left < right){int minIndex = left;int maxIndex = left;//统一从没排序的起点开始for (int i = left+1; i < array.length; i++) {if(array[maxIndex] < array[i]){maxIndex = i;}if(array[minIndex] > array[i]){minIndex = i;}}swap(array,left,minIndex);swap(array,right,maxIndex);left++;right--;}}public static void swap(int[]array ,int minIndex,int j){int tmp = array[j];array[j] = array[minIndex];array[minIndex] = tmp;}
}

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

4. 堆排序

 降序建大堆,升序建小堆

详情思路请看之前写的堆部分

https://mp.csdn.net/mp_blog/creation/editor/139502440

 /*** 堆排序* 时间复杂度:O(n*logN)* 空间复杂度:O(1)* 稳定性:不稳定* @param array*/public static void heapSort(int[] array) {createHeap(array);int end = array.length-1;while (end > 0) {swap(array,0,end);siftDown(array,0,end);end--;}}private static void createHeap(int[] array) {for (int parent = (array.length-1-1)/2; parent >= 0; parent--) {siftDown(array,parent,array.length);}}/**** @param array* @param parent 每棵子树调整的根节点* @param length 每棵子树调整的结束节点*/private static void siftDown(int[] array, int parent, int length) {int child = 2 * parent + 1;while (child < length) {if(child + 1 < length && array[child] < array[child+1]) {child++;}if(array[child] > array[parent]) {swap(array, parent, child);parent = child;child = 2*parent+1;}else {break;}}}

6.快速排序

思想:任取待排序元素序列中的某元
素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有
元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

翻译过来实现过程就是取第一个数,分别在头和尾定义一个指针 ,头指针找比第一个数大的(需求就是把小的放在左边所以需要找大的和右边大的交换),尾指针找比第一个小的,两个都找到后,进行交换,确保左边的都是小于或等于第一个数的,右边都是大于或等于第一个数的,直到两个指针位置相等,然后再交换第一个与它们的位置,通过递归将它们分为一个个更小的然后即可完成

快速排序Hoare法实现过程

问题:为什么先从后面开始

如果先从前面开始则会造成最后汇合点大于key.

递归法

通过left和right的不断变化,直到left与right相遇为止,当不断分为很多的left和right后,

public class Sort {public static void swap(int[]array ,int minIndex,int j){int tmp = array[j];array[j] = array[minIndex];array[minIndex] = tmp;}public static void qsort(int[] array){int left = 0,right = array.length-1;parttrtions(array,left,right);}private static void parttrtions(int[]array,int left,int right){if(left>=right){return;}int start = parttrtion(array,left,right);parttrtions(array,left,start-1);parttrtions(array,start+1,right);}private static int parttrtion(int[] array,int left,int right){//Hoare版int privt = array[left];int end = right,start = left;while(start<end){while(start<end&& array[end] >= privt) {//从右往左直到找到比array[start](privt)小的放在end--;}while(start<end&&array[start] <= privt){//跳出小循环说明找到了比privt大的数start++;}swap(array,left,start);}return start;}private static int parttrtion1(int[] array,int left,int right){//挖坑法int privt = array[left];int end = right,start = left;while(start<end){while(start<end&& array[end] >= privt) {//从右往左直到找到比array[start](privt)小的放在end--;}array[start] = array[end];//将end下标的值来补充start的空缺while(start<end&&array[start] <= privt){//跳出小循环说明找到了比privt大的数start++;}array[end] = privt;//将start下标的值来补充end的空缺}return start;}
}

 快排的优化:

1.三数取中法:如果是单一的数则可能造成,单支树的产生,最高造成N(O*2),所以可以提前将中间的值给到start,这样能极大减少计算量

private static int getMiddleNum(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[left]) {return left;}else if(array[mid] < array[right]) {return right;}else {return mid;}}}

非递归法

 利用栈后进先出不断变化left和right的值

public static void qsort1(int[] array){int left = 0,right = array.length-1;int par = parttrtion(array,left,right);Stack<Integer> stack = new Stack<>();if(par>left+1){stack.push(left);stack.push(par-1);}if(par < right-1){stack.push(par+1);stack.push(right);}while(!stack.empty()){right = stack.pop();left = stack.pop();par = parttrtion(array,left,right);if(par>left+1){stack.push(left);stack.push(par-1);}if(par < right-1){stack.push(par+1);stack.push(right);}}}

总结: 

 1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)
4. 稳定性:不稳定

7.归并排序

思想:先将数组分成很多小份,然后再进行排序,然后把排序完的数组重新整和,最终得到一个有序数组。

递归法

1.首先将大数组分为小数组,把大问题拆分为小问题,1.找到最底层的两个数组,2.排序

 public void mergeSortTmp(int[]a,int left,int right){//将数组先分开再合并if(left>=right){return;}int mid = (left+right)/2;mergeSortTmp(a,left,mid);//分成很多份,找到最左边mergeSortTmp(a,mid+1,right);//上层递归完成,找到对应要排序的另一个数组merge(a,mid,left,right);//两个都找到后,进行排序操作}

2.然后利用两个数组组合排序的方法,定义两个指针,取到小的添加到新的数组

private void merge(int[]a,int mid,int left,int right){int [] array = new int[right-left+1];int set = 0;int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;while(s1<e1&&s2<e2){if(a[s1] < a[s2]){array[set++] = a[s1++];}else {array[set++] = a[s2++];}}while (s1 <= mid) {array[set++] = array[s1++];}while (s2 <= right) {array[set++] = array[s2++];}for (int i = 0; i < array.length; i++) {a[i+left] = array[i];//分组后每一小组的下标并不是零}}

非递归法

思路:我们这个排序的核心就是1.一步步得到最小数组 2.一步步将两个小数组合并起来直到得到 大数组

所以可以在循环里嵌套循环,外面决定数组长度,里面循环将小数组排序合并,外循环设置每个小数组的相隔距离

 public void mergrSort1(int[] array){int left = 0,right = array.length-1;int gap = 1;//gap负责将数组分为array.length/2while(gap<array.length){for (int i = 0; i < array.length; i+=2*gap) {//得到小一号的数组并且进行排序合并,里面for循环是为了得到最多组数组left = i;int mid = left+gap-1;right = mid+gap;if(mid >= array.length) mid=array.length-1;if(right>=array.length) right = array.length-1;merge(array,mid,left,right);}gap *= 2;//世界线收束,每次小数组排序好后,再将更大数组排序}}}

总结:1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定

8.计数排序

思路:将原数组遍历一遍,得到原数组的最大值和最小值,将最大值和最小值相减,得到它们的取值范围,创建一个新数组,然后将对应的值给到,和其相对相等的下标,(比如数组的值为1给到开辟数组的1下标,)然后遍历新数组,赋值给原数组

/*** 计数排序:* 时间复杂度:O(范围 + n )*       范围越大  越慢* 空间复杂度:O(范围)* 稳定性:* @param array*/public static void countSort(int[] array) {//1. 找最大值 和 最小值 来确定 计数数组的大小int maxVal = array[0];int minVal = array[0];for (int i = 1; i < array.length; i++) {if(array[i] < minVal) {minVal = array[i];}if(array[i] > maxVal) {maxVal = array[i];}}int len = maxVal - minVal + 1;int[] count = new int[len];//2. 遍历原来的数组array把 每个元素 放到对应的计数数组当中 进行计数for (int i = 0; i < array.length; i++) {int index = array[i];count[index-minVal]++;}//3.依次 遍历计数数组 O(范围)int index = 0;for (int i = 0; i < count.length; i++) {while (count[i] != 0) {array[index] = i+minVal;index++;count[i]--;}}}

总结 

1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
2. 时间复杂度:O(MAX(N,范围))
3. 空间复杂度:O(范围)
4. 稳定性:稳定

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

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

相关文章

STM32 GPIO

GPIO&#xff08;通用输入输出口&#xff0c;General Purpose Input Output&#xff09;接口的功能是让嵌入式处理器能够通过软件灵活地读出或控制单个物理引脚上的高、低电平&#xff0c;实现内核和外部系统之间的信息交换。 GPIO是嵌入式处理器使用最多的外设&#xff0c;能够…

甲虫身体图像分割系统源码&数据集分享

甲虫身体图像分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientRepBiPAN&#xff06;yolov8-seg-C2f-FocusedLinearAttention等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challen…

毕设开源 大数据电影数据分析与可视化系统(源码+论文)

文章目录 0 前言1 项目运行效果2 设计概要3 最后 0 前言 &#x1f525;这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师…

简单粗暴理解GNN、GCN、GAT

GNN 思想&#xff1a;近朱者赤近墨者黑 GNN的流程&#xff1a; 聚合&#xff08;把邻居的信息贴到自己身上来&#xff0c;作为它自己特征的补足&#xff09;更新循环&#xff08;为什么要多次&#xff1f;看以下例子&#xff09; GNN能干嘛&#xff1f; 1.结点分类&#xf…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

【网络协议】TCP协议常用机制——延迟应答、捎带应答、面向字节流、异常处理,保姆级详解,建议收藏

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章&#xff0c;博主带大家梳理了一下TCP协议的几个核心机制&#xff0c;比如保证可靠性的 确认应答、超时重传 机制&#xff0c;和提高传输效率的 滑动窗口及其相关优化机…

Qt实现Halcon窗口显示当前图片坐标

一、前言 Halcon加载图片的窗口&#xff0c;不仅能放大和缩小图片&#xff0c;还可以按住Ctrl键显示鼠标下的灰度值&#xff0c;这种方式很方便我们分析缺陷的灰度和对比度。 二、实现方式 ① 创建显示坐标和灰度的widget窗口 下图的是widget部件&#xff0c;使用了4个label控…

常说的风险评估,那么「基于风险的测试 (RBT)」如何测试?

基于风险的测试 &#xff08;RBT&#xff09; 是一种测试方法&#xff0c;它根据风险的概率和影响确定测试活动的优先级。它涉及在潜在问题发生之前识别它们&#xff0c;并将资源分配给风险最高的测试区域。 在 RBT 中&#xff0c;“风险”是指缺陷的可能性及其对系统运行或业…

DS线性表之单链表的讲解和实现(2)

文章目录 前言一、链表的概念二、链表的分类三、链表的结构四、前置知识准备五、单链表的模拟实现定义头节点初始化单链表销毁单链表打印单链表申请节点头插数据尾插数据头删数据尾删数据查询数据在pos位置之后插入数据删除pos位置之后的数据 总结 前言 本篇的单链表完全来说是…

架设传奇SF时提示此服务器满员,GEE引擎点开始游戏弹出服务器满员的解决方法

昨天一个朋友在架设GEE的传奇服务端时遇到一个奇怪的问题&#xff0c;就是在服务器外网架设时&#xff0c;建好角色点开始游戏提示此服务器满员&#xff0c;这个问题一般比较少见&#xff0c;而且出现的话一般都是GEE引擎的版本。 他折腾了半天&#xff0c;一直没进游戏&#x…

Apache Linkis + OceanBase:如何提升数据分析效率

计算中间件 Apache Linkis 构建了一个计算中间件层&#xff0c;以实现上层应用程序和底层数据引擎之间的连接、治理和编排。目前&#xff0c;已经支持通过数据源的功能&#xff0c;实现用户通过Linkis 对接并使用 OceanBase数据库。 本文详细阐述了在 Apache Linkis v1.3.2中&a…

VGG16模型实现MNIST图像分类

MNIST图像数据集 MNIST&#xff08;Modified National Institute of Standards and Technology&#xff09;是一个经典的机器学习数据集&#xff0c;常用于训练和测试图像处理和机器学习算法&#xff0c;特别是在数字识别领域。该数据集包含了大约 7 万张手写数字图片&#xf…

线性代数在大一计算机课程中的重要性

线性代数在大一计算机课程中的重要性 线性代数是一门研究向量空间、矩阵运算和线性变换的数学学科&#xff0c;在计算机科学中有着广泛的应用。大一的计算机课程中&#xff0c;线性代数的学习为学生们掌握许多计算机领域的关键概念打下了坚实的基础。本文将介绍线性代数的基本…

高考技术——pandas使用

百家讲坛&#xff0c;谈论古今&#xff0c;今天我们不聊别的&#xff0c;我们来聊一聊中国的国宝——大熊猫&#xff08;bushi&#xff09; 好好&#xff0c;言归正传&#xff0c;我们今天来讲pandas import pandas as pd 申明无需多言&#xff0c;高考主要考察Series和Data…

Milvus向量数据库管理工具[Attu]实践

Attu是一款专为Milvus向量数据库打造的开源数据库管理工具&#xff0c;提供了便捷的图形化界面&#xff0c;极大地简化了对Milvus数据库的操作与管理流程。阿里云Milvus集成了Attu&#xff0c;以便更加高效地管理数据库、集合&#xff08;Collection&#xff09;、索引&#xf…

第四次论文问题知识点及问题

1、NP-hard问题 NP-hard&#xff0c;指所有NP问题都能在多项式时间复杂度内归约到的问题。 2、启发式算法 ‌‌启发式算法&#xff08;heuristic algorithm&#xff09;是相对于最优化算法提出的。它是一种基于直观或经验构造的算法&#xff0c;旨在以可接受的花费给出待解决…

树莓派3b安装ubuntu18.04服务器系统server配置网线连接

下载ubuntu镜像网址 img镜像&#xff0c;即树莓派官方烧录器使用的镜像网址 ubuntu18.04-server&#xff1a;ARM/RaspberryPi - Ubuntu Wiki 其他版本&#xff1a;Index of /ubuntu/releases 下载后解压即可。 发现使用官方烧录器烧录配置时配置wifi无论如何都不能使用&am…

GO网络编程(三):海量用户通信系统1:登录功能初步

一、准备工作 需求分析 1)用户注册 2)用户登录 3)显示在线用户列表 4)群聊(广播) 5)点对点聊天 6)离线留言 主界面 首先&#xff0c;在项目根目录下初始化mod&#xff0c;然后按照如下结构设计目录&#xff1a; 海量用户通信系统/ ├── go.mod ├── client/ │ ├──…

【C++】基于红黑树封装set和map

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言一、更高维度的泛型二、模版参数三、比较逻辑的重写四、迭代器4.1 const迭代器4.2 重载4.3 - -重载 五、完整代…

阿里P8面试官推荐学习的11大专题:java面试精讲框架文档

本篇文章给大家分享一波&#xff0c;阿里P8面试官推荐学习的11大专题&#xff1a;java面试精讲框架文档&#xff0c;主要包含11大块的内容&#xff1a;spring、springcloud、netty、zookeeper、kafka、Hadoop、HBASE、Cassandra、elasticsearch、spark、flink&#xff1b;希望大…