【JavaDS】排序——快排 & 归并

简介: 【JavaDS】排序——快排 & 归并

上接【JavaDS】排序——快速排序

快排的另一种 partition 方法


通过算法的设计将序列分成如图所示的三个区间


               [ from, s )               元素 <= pivot


               [ s, i )                     元素 >= pivot


               [ i, to )                    待比较元素


遍历 [ from, to )


比较 array[i] 和 pivot ,array[i] < pivot ,交换 i 和 s 的元素,同时 i++,s++;


                                    array[i] > pivot, i++;


遍历比较完成之后,交换 pivot 和 s 的值


13.png

代码参考

private static int partitionMethodC(long[] array, int from, int to) {
        int s = from;
        long pivot = array[to];
        for (int i = from; i < to; i++) {   // 遍历 [from, to)
            // 这里加 == 号也保证不了稳定性,有交换操作
            if (array[i] < pivot) {
                // TODO: 可以进行简单的优化:如果 i == s,就不交换
                long t = array[i];
                array[i] = array[s];
                array[s] = t;
                s++;
            }
        }
        array[to] = array[s];
        array[s] = pivot;
        return s;
    }

快排的几个常见优化手段

1. 前提结论:在待排序元素比较少的情况下,快排的速度低于插排,所以,在待排序元素个数的个数低于一个阈值(20)时,直接使用插排完成


2. partition 算法上的优化(比如,把 == pivot 的提前找出来),


               同时选择多个基准值,比如三个,记为 p1, p2, p3, 其中 p1 < p2 < p3 , 如下图所示


3. 选择 pivot 的方式上优化


       三数取中法


               取区间最开始,最中间以及最后面的三个数,取这三个数大小上是中间的数作为基准值,最后再把确定的基准值交换到区间最后面


14.png


归并排序

将区间分成如图所示的两个小区间,如果可以使左右两个区间都变得有序,那么合并两个有序区间之后,整个区间变得有序

归并排序的基本思想

1. 如果待排序区间已经有序(区间内的元素个数 <= 1),则排序操作直接返回


2. 确定区间中间位置的下标 mid ( mid = from + (size / 2)),所以 [ from, to ) 的区间,被我们从逻辑上视为是左右两个小区间([ from, mid) 和 [ mid, to ))组成


3. 先对左右两个小区间使用相同的方法,进行排序


4. 当左右两个小区间已经有序时,执行合并两个有序区间的操作,得到一个最终的有序大区间


具体步骤演示


15.png


和并两个小区间为一个有序大区间的方法

合并两个有序区间,需要用到同等大小的一个额外空间

从两个区间分别挑出最小的元素比较,确定两个元素在新区间内的相对位置,循环执行此过程,直至一个小区间内的元素全部被比较,如果另一个区间内还有元素,则按照顺序插入新区间即可


代码参考

private static void merge(long[] array, int from, int mid, int to) {
        // 先计算出来额外空间需要多个,计算两个区间加起来多少个元素
        int size = to - from;
        // 申请一个额外的数组作为临时保存的地方
        long[] other = new long[size];  // 需要一个 和 n 长度一致的空间
        int left = from;    // 左边小区间的下标
        int right = mid;    // 右边小区间的下标
        int dest = 0;       // 临时空间的下标
        // 只要左右两个小区间还有元素要参与比较
        while (left < mid && right < to) {
            if (array[left] <= array[right]) {
                other[dest++] = array[left++];
            } else {
                other[dest++] = array[right++];
            }
        }
        // 其中一个区间的元素取完了,另一个区间里一定还有元素,再把剩余的元素,统统放入 other
        // 看起来左右两个都写了,但执行起来的时候一定只有一个会执行
        while (left < mid) {
            other[dest++] = array[left++];
        }
        while (right < to) {
            other[dest++] = array[right++];
        }
        // 把 other 中的有序元素,复制回 array 中,要注意下标的问题
        for (int i = 0; i < size; i++) {
            array[from + i] = other[i];     // array 下标的基准是从 [from] 开始,other 下标的基准是从 [0] 开始
                                            // offset(偏移)是一致的,都是 i
        }
    }


7 种基于比较的排序

快速排序、归并排序、冒泡排序、插入排序、希尔排序、选择排序、堆排序


按照不同的标准,划分这些排序


1. 具备稳定性的排序:冒泡、插排、归并


2. 平均情况下,执行速度分为两组:


       1)慢:冒泡、插排、选择——排序的元素个数在 10万 级别左右


       2)快:快排、归并、希尔、堆排——个数在 1忆 级别


3. 空间角度


       1)空间复杂度是 O(1) :冒泡、插排、希尔、选择、堆排


       2)空间复杂度是 O(log(n) ~ O(n)):快排


       3)空间复杂度是 O(n):归并


4. 属于减治算法(每次问题规模减少1):冒泡、插排、希尔、选择、堆排


   属于分治算法(把问题分成多个子问题分别处理):快排、归并


目录
相关文章
|
机器学习/深度学习 PyTorch 算法框架/工具
RGCN的torch简单案例
RGCN 是指 Relational Graph Convolutional Network,是一种基于图卷积神经网络(GCN)的模型。与传统的 GCN 不同的是,RGCN 可以处理具有多种关系(边)类型的图数据,从而更好地模拟现实世界中的实体和它们之间的复杂关系。 RGCN 可以用于多种任务,例如知识图谱推理、社交网络分析、药物发现等。以下是一个以知识图谱推理为例的应用场景: 假设我们有一个知识图谱,其中包含一些实体(如人、物、地点)以及它们之间的关系(如出生于、居住在、工作于)。图谱可以表示为一个二元组 (E, R),其中 E 表示实体的集合,R 表示关系的集合,每个关系 r ∈ R
1957 0
|
8月前
|
机器学习/深度学习 计算机视觉
YOLOv11改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制
YOLOv11改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制
2234 2
YOLOv11改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制
|
10月前
|
人工智能 物联网 PyTorch
ChatTTSPlus:开源文本转语音工具,支持语音克隆,是 ChatTTS 的扩展版本
ChatTTSPlus 是一个开源的文本转语音工具,是 ChatTTS 的扩展版本,支持语音克隆、TensorRT 加速和移动模型部署等功能,极大地提升了语音合成的性能和灵活性。
702 5
ChatTTSPlus:开源文本转语音工具,支持语音克隆,是 ChatTTS 的扩展版本
|
11月前
|
移动开发
USB-TTL连接ESP8266不识别串口/串口助手回复乱码
【11月更文挑战第14天】当USB-TTL连接ESP8266出现不识别串口或乱码问题时,应检查硬件连接(线路、电源)、串口设置(驱动、串口选择、数据位等)及软件固件(AT指令、固件版本、串口助手)。确保所有设置正确无误。
1304 0
|
存储 安全 Go
CSRF 实验:Token 不存在绕过验证
CSRF 实验:Token 不存在绕过验证
Map.entry方法总结
Map.entry方法总结
|
人工智能
MidJourney以图生图的详细教程(含6种案例介绍)(下)
MidJourney以图生图的详细教程(含6种案例介绍)
|
Linux Docker 容器
Linux彻底卸载Docker包括运行拉取的镜像
Linux彻底卸载Docker包括运行拉取的镜像
191 1
|
JavaScript 前端开发 Java
【JCEF】SWT嵌入浏览器(包含VUE的)
【JCEF】SWT嵌入浏览器(包含VUE的)
332 1
|
机器学习/深度学习 计算机视觉 Python
【Python计算机视觉】项目实战之图像增强imguag对关键点变换、标注框变化(附源码 超详细必看)
【Python计算机视觉】项目实战之图像增强imguag对关键点变换、标注框变化(附源码 超详细必看)
358 0