当前位置: 首页 > news >正文

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. 稳定性:稳定

相关文章:

JAVA-数据结构-排序

1.直接插入排序 1.原理&#xff1a;和玩扑克牌一样&#xff0c;从左边第二个牌开始&#xff0c;选中这个&#xff0c;和前面的所有牌比较&#xff0c;插在合适的位置 public static void insertsort(int[] arr){//直接插入排序for (int i 1; i < arr.length; i) {//此循环…...

初识数据结构--时间复杂度 和 空间复杂度

数据结构前言 数据结构 数据结构是计算机存储、组织数据的方式(指不仅能存储数据&#xff0c;还能够管理数据-->增删改)。指相互之间存在一种或多种特定关系的数据元素的集合。没有单一的数据结构对所有用途都有用&#xff0c;所以我们要学习各种的数据结构&#xff0c;比…...

Ubuntu QT 交叉编译环境搭建

文章目录 下载安装qtCreatornot a valid identifier 的错误 安装g下载并安装交叉编译器下载交叉编译器安装交叉编译器 下载编译 ARM 的Qt平台源码配置arm的QT平台 下载安装qtCreator 去QT下载官网下载对应需要的QT软件。 这里下载5.12.96版本的 改变安装包权限&#xff0c;…...

C语言中缓冲区底层实现以及数据输入的处理

C语言中缓冲区底层实现以及数据输入的处理 一、缓冲区的概念 在C语言的标准输入输出操作中&#xff0c;缓冲区&#xff08;Buffer&#xff09; 扮演着至关重要的角色。在计算机系统中&#xff0c;缓冲区是一块用于暂存数据的内存区域。在输入输出&#xff08;I/O&#xff09;…...

RocketMQ事务消息原理

一、RocketMQ事务消息原理&#xff1a; RocketMQ 在 4.3 版本之后实现了完整的事务消息&#xff0c;基于MQ的分布式事务方案&#xff0c;本质上是对本地消息表的一个封装&#xff0c;整体流程与本地消息表一致&#xff0c;唯一不同的就是将本地消息表存在了MQ内部&…...

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…...

Go语言中的通道 (Channel) 实践:Goroutine之间的通信

1. 引言 在Go语言中&#xff0c;并发编程是其核心优势之一。与其他编程语言不同&#xff0c;Go语言推荐使用通道 (Channel) 来进行多线程或并发任务的协调与通信&#xff0c;而非使用锁机制。本文将介绍如何通过通道在多个goroutine之间进行通信&#xff0c;避免竞争条件和复杂…...

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…...

Spring Boot开发:从入门到精通

Spring Boot开发&#xff1a;从入门到精通 当你在开发一个新的Java应用时&#xff0c;是否曾经感到苦恼于繁琐的配置和重复的代码&#xff1f;Spring Boot就像一位友好的助手&#xff0c;向你伸出援手&#xff0c;让开发变得轻松愉快。从这一单一框架中&#xff0c;你可以快速…...

《数据结构》--队列【各种实现,算法推荐】

一、认识队列 队列是一种常见的数据结构&#xff0c;按照先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;的原则排列数据。也就是说&#xff0c;最早进入队列的元素最先被移除。队列主要支持两种基本操作&#xff1a; 入队&#xff08;enqueue&#xff0…...

面试八股文对校招的用处有多大?--GDB篇

前言 1.本系列面试八股文的题目及答案均来自于网络平台的内容整理&#xff0c;对其进行了归类整理&#xff0c;在格式和内容上或许会存在一定错误&#xff0c;大家自行理解。内容涵盖部分若有侵权部分&#xff0c;请后台联系&#xff0c;及时删除。 2.本系列发布内容分为12篇…...

Unity用VS打开FGUI脚本变成杂项怎么处理?

在Unity中使用Visual Studio&#xff08;VS&#xff09;打开FGUI脚本时&#xff0c;如果脚本显示为杂项文件&#xff0c;这通常意味着VS没有正确识别或关联这些脚本文件。以下是一些解决此问题的步骤&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;大家…...

交叉熵损失函数(Cross-Entropy Loss Function)解释说明

公式 8-11 的内容如下&#xff1a; L ( y , a ) − [ y log ⁡ a ( 1 − y ) log ⁡ ( 1 − a ) ] L(y, a) -[y \log a (1 - y) \log (1 - a)] L(y,a)−[yloga(1−y)log(1−a)] 这个公式表示的是交叉熵损失函数&#xff08;Cross-Entropy Loss Function&#xff09;&#…...

和外部机构API交互如何防止外部机构服务不可用拖垮调用服务

引言 在现代的分布式系统和微服务架构中&#xff0c;服务之间的通信往往通过API进行&#xff0c;尤其是在与外部机构或第三方服务进行交互时&#xff0c;更需要通过API实现功能的集成。然而&#xff0c;由于外部服务的可控性较差&#xff0c;其服务的不可用性&#xff08;如响…...

自动猫砂盆真的有必要吗?买自动猫砂盆不看这四点小心害死猫。

现在越来越多铲屎官选择购买自动猫砂盆来代替自己给猫咪铲屎&#xff0c;可是自动猫砂盆真的有必要吗&#xff1f;要知道&#xff0c;在现在忙碌的生活中&#xff0c;有很多人因为工作上的忙碌而不小心忽视了猫咪&#xff0c;猫咪的猫砂盆堆满粪便&#xff0c;要知道猫砂盆一天…...

国外解压视频素材哪里找?五个海外解压视频素材网站推荐

国外解压视频素材哪里找&#xff1f;五个海外解压视频素材网站推荐 如果你正在寻找国外的解压视频素材&#xff0c;那么今天这篇文章一定能帮助你。无论是修牛蹄、洗地毯&#xff0c;还是切肥皂、玩解压游戏等&#xff0c;下面分享的几个网站都是你找到高质量海外解压视频素材…...

Android一个APP里面最少有几个线程

Android一个APP里面最少有几个线程 参考 https://www.jianshu.com/p/92bff8d6282f https://www.jianshu.com/p/8a820d93c6aa 线程查看 Android一个进程里面最少包含5个线程&#xff0c;分别为&#xff1a; main线程(主线程&#xff09;FinalizerDaemon线程 终结者守护线程…...

位操作解决数组的花样遍历

文章目录 题目 一、思路&#xff1a; 二、代码 总结 题目 leetcodeT289 https://leetcode.cn/problems/game-of-life/description/ 一、思路&#xff1a; 这题思路很简单&#xff0c;对每个位置按照题目所给规则进行遍历&#xff0c;判断周围网格的活细胞数即可。但是题目要求…...

【面试宝典】深入Python高级:直戳痛点的题目演示(下)

目录 &#x1f354; Python下多线程的限制以及多进程中传递参数的⽅式 &#x1f354; Python是如何进⾏内存管理的&#xff1f; &#x1f354; Python⾥⾯如何拷⻉⼀个对象&#xff1f; &#x1f354; Python⾥⾯search()和match()的区别&#xff1f; &#x1f354; lambd…...

Hive数仓操作(十七)

一、Hive的存储 一、Hive 四种存储格式 在 Hive 中&#xff0c;支持四种主要的数据存储格式&#xff0c;每种格式有其特点和适用场景&#xff0c;不过一般只会使用Text 和 ORC &#xff1a; 1. Text 说明&#xff1a;Hive 的默认存储格式。存储方式&#xff1a;行存储。优点…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

「Java基本语法」变量的使用

变量定义 变量是程序中存储数据的容器&#xff0c;用于保存可变的数据值。在Java中&#xff0c;变量必须先声明后使用&#xff0c;声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例&#xff1a;声明与初始化 public class VariableDemo {publi…...

HTML版英语学习系统

HTML版英语学习系统 这是一个完全免费、无需安装、功能完整的英语学习工具&#xff0c;使用HTML CSS JavaScript实现。 功能 文本朗读练习 - 输入英文文章&#xff0c;系统朗读帮助练习听力和发音&#xff0c;适合跟读练习&#xff0c;模仿学习&#xff1b;实时词典查询 - 双…...

多模态学习路线(2)——DL基础系列

目录 前言 一、归一化 1. Layer Normalization (LN) 2. Batch Normalization (BN) 3. Instance Normalization (IN) 4. Group Normalization (GN) 5. Root Mean Square Normalization&#xff08;RMSNorm&#xff09; 二、激活函数 1. Sigmoid激活函数&#xff08;二分类&…...