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

目录

❄️一、归并排序:

[☞ 基本思想:](#☞ 基本思想:)

[☞ 代码:](#☞ 代码:)

[☞ 归并排序的非递归方法:](#☞ 归并排序的非递归方法:)

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

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

❄️总结:


❄️一、归并排序:

☞ 基本思想:

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

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

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

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

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

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

分解操作:

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的知识啦,让我们尽情期待吧!!!拜拜~~~

相关推荐
NiNg_1_2342 分钟前
Python的sklearn中的RandomForestRegressor使用详解
开发语言·python·sklearn
大卫小东(Sheldon)4 分钟前
Java的HTTP接口测试框架Gatling
java
谢家小布柔6 分钟前
java中的继承
java·开发语言
黑色叉腰丶大魔王6 分钟前
《基于 Python 的网页爬虫详细教程》
开发语言·爬虫·python
爱吃西瓜的小菜鸡7 分钟前
【C语言】矩阵乘法
c语言·学习·算法
l1384942745112 分钟前
Java每日一题(2)
java·开发语言·游戏
苹果醋314 分钟前
SpringBoot快速入门
java·运维·spring boot·mysql·nginx
晓纪同学19 分钟前
QT创建一个模板槽和信号刷新UI
开发语言·qt·ui
WANGWUSAN6625 分钟前
Python高频写法总结!
java·linux·开发语言·数据库·经验分享·python·编程
Yvemil726 分钟前
《开启微服务之旅:Spring Boot 从入门到实践》(一)
java