Java-数据结构-排序(三) |ू・ω・` )

server/2024/9/25 4:54:04/

目录

❄️一、归并排序:

              ☞ 基本思想:

             ☞ 代码:

             ☞ 归并排序的非递归方法:

❄️二、排序算法的分析:

 ❄️三、非基于比较的排序:

 ❄️总结:


❄️一、归并排序:

              ☞ 基本思想:

 归并排序是一个建立在归并操作上的一种排序算法,这个算法是采用分治法的典型案例。

 就是:将有序的子序列合并,得到一个完全有序的列表。

       即是先使每个子序列有序,再使子序列段间有序。

   若将两个有序的列表合并成一个列表,称为二路归并。

 我们来看看这个排序是如何进行排序的:

     就是分成了 分解操作 和 合并操作 ,那么我们的这个 分解操作是如何做的,合并操作又是如何做的?我们呢来一一的看看如何操作的:

分解操作:

   1、我们呢对于这个数据 开始位置设置为left ,结束位置设置为 right ,之后求出中间值 mid ,

   2、之后把left 到 mid 下标的值分为一组,mid +1 到 right 的值分为一组。

   3、对于 left 到 mid这一组,再分的话把 mid 的下标给到 right 之后再求 mid 位置。

   4、对于 mid+1 到 right 这一组,再分的话就把 mid+1 的下标给到 left 之后再求 mid 位置。

   5、这样直至我们的 left >= right 的时候结束。

OK,我们的分解思路就是这样的,我们呢来看看代码是如何编写的 :

java">public static void mergeSort(int[] array) {mergeSortTmp(array,0,array.length - 1);}private static void mergeSortTmp(int[] array, int left, int right) {if (left >= right) {return;}//分解操作int mid = (left + right) / 2;mergeSortTmp(array,left,mid);mergeSortTmp(array,mid+1,right);}

  合并操作:

1、我们在每次分解完一个区间的数据之后呢,就对其进行合并操作,合并之后就是有序的数据了

2、比如我们合并长度为2 的两个有序的数据,就是相当于合并两个有序的数组

3、我们要知道每个数组的开始和结尾

 第一个数组:开头是left 用s1 保存,结尾是mid 用e1 保存

 第二个数组:开头是mid+1 用s2 保存,结尾是right 用e2 保存

4、我们把 s1 和 s2 下标的值进行比较之后小的值呢放到新的数组中,只要有一个超过了e1或者e2就需要退出循环,进行下一步的判断操作。

5、还有判断哪个数组放到新的数组中,之后再把没放入的放进数组中

6、把排好序的数组放到原先的数组中,但是要注意放的时候我们的原数组的下标要加上一个left

     因为我们第二次排序的时候呢下标不是从 0 开始的是从 left 下标开始的。

我们来看看代码是如何编写的: 

java">private static void merge(int[] array, int left, int mid, int right) {int[] tmp = new int[right - left + 1];int k = 0;int s1 = left;int e1 = mid;int s2 = mid + 1;int e2 = right;while(s1 <= e1 && s2 <= e2) {if (array[s1] <= array[s2]) {tmp[k++] = array[s1++];}else {tmp[k++] = array[s2++];}}while (s1 <= e1) {tmp[k++] = array[s1++];}while (s2 <= e2) {tmp[k++] = array[s2++];}for (int i = 0; i < k; i++) {array[i+left] = tmp[i];}}

这就是我们的合并排序的代码了,我们来看看整体的代码:


             ☞ 代码:

java"> /*** 归并排序* 时间复杂度:O(N*logN)* 空间复杂度:O(N)* 稳定性:稳定* @param array*/public static void mergeSort(int[] array) {mergeSortTmp(array,0,array.length - 1);}private static void mergeSortTmp(int[] array, int left, int right) {if (left >= right) {return;}//分解操作int mid = (left + right) / 2;mergeSortTmp(array,left,mid);mergeSortTmp(array,mid+1,right);//每一个分解完之后呢,都要进行排序合并操作merge(array,left,mid,right);}private static void merge(int[] array, int left, int mid, int right) {int[] tmp = new int[right - left + 1];int k = 0;int s1 = left;int e1 = mid;int s2 = mid + 1;int e2 = right;while(s1 <= e1 && s2 <= e2) {if (array[s1] <= array[s2]) {tmp[k++] = array[s1++];}else {tmp[k++] = array[s2++];}}while (s1 <= e1) {tmp[k++] = array[s1++];}while (s2 <= e2) {tmp[k++] = array[s2++];}for (int i = 0; i < k; i++) {array[i+left] = tmp[i];}}

             ☞ 归并排序的非递归方法:

  我们的非递归呢,就是把我们的分解操作变成非递归的操作,那么如何做呢?

  对于分解操作,我们一开始是不是可以看成它们是 一个一个有序,之后是两个两个有序,之后是四个四个有序,这样下去就可以把我们的分解操实现了。

1、我们定义一个 gap 用来 判断是几个一组的

      我们的 gap 每次变化都是 乘2 的,并且 gap < 数组长度 才可以执行下面的操作

2、我们的定义个 i 从 0 下标开始,我们的 left 就是 i 

    这里我们的 i 不能是++操作进行往下走,我们的 i 这里是 i = i + gap*2

3、mid = left + gap - 1

     在赋值之后呢,我们的mid 要进行判断操作,是否是 >= 数组的长度 ,如果是,就把其进行 - 1

     因为这里我们之后要传给 合并有序数组的操作,防止数组越界

4、right = mid + gap

    这里同样要进行判断操作,是否是 >= 数组的长度 ,如果是,就把其进行 - 1

 

 代码:

java">public static void mergeSort(int[] array) {mergeSortNor(array);}private static void mergeSortTmp(int[] array, int left, int right) {if (left >= right) {return;}//分解操作int mid = (left + right) / 2;mergeSortTmp(array,left,mid);mergeSortTmp(array,mid+1,right);//每一个分解完之后呢,都要进行排序合并操作merge(array,left,mid,right);}
//非递归实现归并
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;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;}}


❄️二、排序算法的分析:

排序方法最好平均最坏(时间复杂度)空间复杂度稳定性
冒泡排序O(N^2)O(N^2)O(N^2)O(1)稳定
插入排序O(N)O(N^2)O(N^2)O(1)稳定
选择排序O(N^2)O(N^2)O(N^2)O(1)不稳定
希尔排序O(N)O(N^1.3)O(N^1.5)O(1)不稳定
堆排序O(N*logN)O(N*logN)O(N*logN)O(1)不稳定
快速排序O(N*logN)O(N*logN)O(N^2)O(log(N))~O(N)不稳定
归并排序O(N*logN)O(N*logN)O(N*logN)O(N)稳定

 ❄️三、非基于比较的排序:

     我们之前介绍的排序都是需要比较的排序方法,我们还有不需要比较的排序方法:计数排序、基数排序、桶排序。

我们的非基于比较的排序可以通过 “传送门” 来了解:

基数排序:

              基数排序

桶排序:

              桶排序

当然如果需要 计数排序的 传送门 的话,这里也有:

              计数排序

 


 ❄️总结:

      OK,到这里呢我们的排序呢就结束了,这次关于排序的代码呢还是比较多的,要认真的理解它们,同时要画图的去理解它们的执行流程。 下一篇博客呢我们就要介绍关于Map与Set的知识啦,让我们尽情期待吧!!!拜拜~~~


http://www.ppmy.cn/server/121667.html

相关文章

深度学习:数据增强

目录 前言 一、为什么要使用数据增强&#xff1f; 二、数据增强有哪些方法&#xff1f; 1. 几何变换 2. 颜色变换 3. 噪声添加 4. 裁剪 5. 混合技术 6. 其他方法 三、代码实现 前言 数据增强是深度学习中常用的一种技术&#xff0c;旨在通过对训练数据进行各种变换来…

研1日记15

1. 文心一言生成&#xff1a; 在PyTorch中&#xff0c;nn.AdaptiveAvgPool1d(1)是一个一维自适应平均池化层。这个层的作用是将输入的特征图&#xff08;或称为张量&#xff09;在一维上进行自适应平均池化&#xff0c;使得输出特征图的大小在指定的维度上变为1。这意味着&…

《微信小程序实战(4) · 地图导航功能》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

24年蓝桥杯及攻防世界赛题-MISC-1

2 What-is-this AZADI TOWER 3 Avatar 题目 一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息?隐藏内容即flag 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc/outguess] └─$ outguess -r 035bfaa85410429495786d8ea6ecd296.jpg flag1.txt Reading 035bf…

Redis常见知识点

数据类型 String Redis字符串存储字节序列&#xff0c;包括文本、序列化对象和二进制数组。 默认情况下 单个Redis字符串最大值不能超过512m 常用命令 SETNX仅当键不存在时才存储字符串值。对于实现锁很有用。MGET在一次操作中检索多个字符串值。INCRBY原子地增加&#xff…

详解 C++中的模板

目录 前言 一、函数模板 1.定义 2.函数模板的实现 3.模板函数的实例化 4.模板参数的省略 1.函数模板的实参推导 2.类模板的实参推导 3.默认模板参数 4.特殊情况:无法推导的模板 5.推导失败的情况 二、类模板 1.概念和定义 2.类模板定义 3.类模板的使用 4.类模板…

23个Python在自然语言处理中的应用实例

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Python作为一门功能强大的编程语言&#xff0c;凭借其丰富的库和工具集&#xff0c;成为了实现各种NLP任务的首选。以下是一个关于Python在NLP中应用的广泛实例的前言&#xff0c;旨在概述Python在NLP领域的多样性和…

力扣 中等 1901.寻找峰值II

文章目录 题目介绍题解 题目介绍 题解 需要明白一个事实&#xff1a;从任意一个点出发&#xff0c;可以经过一个递增路径&#xff0c;找到一个极大值点。 求出一行的最大值&#xff0c;如果这行最大值比上面的要小&#xff0c;那峰值&#xff08;之一&#xff09;就会在上面 …