基于元素小组的归并排序算法

news2025/1/19 21:36:12

问题说明

什么是针对元素小组的归并排序算法,举个例子:假如有一个数组[1,2,3,4,5,6,7,8,9],{1,2,3}为一个小组,{4,5,6}为一个小组,{7,8,9}为一个小组,现需要根据每个小组的第一个元素来进行排序,小组需要一起移动,则降序排序之后的数组为[7,8,9,4,5,6,1,2,3]。

为什么需要这样排序呢,这样有什么好处?比如需要存储多条线段,每根线段有三个属性,分别为xminYmaxY,如图所示
在这里插入图片描述
是不是很容易想到使用List<int[]>来存储,每个int[]存储一条线段,虽然这样很容易实现,但是这样不仅会占用更多的内存,后面在使用的时候速度也会比较慢。为了节省内存和后面使用的内存,可以只用一个List<Integer>来存储线段,只需要三个相连的元素来一起表示一条线段即可,比如索引[0,1,2]的三个元素一起表示一条线段,索引[3,4,5]的三个元素一起表示另一条线段。

使用这种方式,在遍历线段的时候非常简单,直接使用for(int i=0; i<list.size(); i+=3),每次分别取出ii+1i+2对应的元素即可。但是如果想要对线段排序呢?很多读者是不是没有写过类似的程序,本文提供一种排序方法供读者参考

基于元素小组归并排序算法

首先为什么要基于归并排序算法来实现呢?因为归并排序的平均情况、最好情况、最坏情况的时间复杂度都是O(n log n),性能较好

归并排序原理

归并排序使用分治思想,“分"即将大数组变成小数组,“治”即将小数组合并为大数组,并在合并的过程中进行排序
在这里插入图片描述

集合版本

【抽象排序类】
其中compare为抽象方法,需要子类去自定义排序规则

package com.dam.algorithm.version3.merge;

import java.util.List;

/**
 * @Author dam
 * @create 2023/9/13 14:39
 */
public abstract class GroupMergeSort {

    /**
     * @param list
     * @param groupSize 组的大小
     */
    public void sort(List<Integer> list, int groupSize) {
        // 归并排序需要一个额外空间来存储排序之后的数组
        int[] temp = new int[list.size()];
        mergeSort(list, 0, list.size() / groupSize - 1, temp, groupSize);
    }

    /**
     * 分+合方法
     *
     * @param arr
     * @param left
     * @param right
     * @param temp
     */
    private void mergeSort(List<Integer> arr, int left, int right, int[] temp, int groupSize) {
        // 只要left<right,就可以继续分
        if (left < right) {
            // 中间索引
            int mid = (left + right) / 2;
            // 向左递归进行分解
            mergeSort(arr, left, mid, temp, groupSize);
            // 向右递归进行分解
            mergeSort(arr, mid + 1, right, temp, groupSize);
            // 合并(最先合并栈顶的元素)
            merge(arr, left, mid, right, temp, groupSize);
        }
    }

    /**
     * 合并的方法
     *
     * @param list  排序的原始数组
     * @param left  左边有序序列的初始索引
     * @param mid   中间索引
     * @param right 右边索引
     * @param temp  做中转的数组
     */
    private void merge(List<Integer> list, int left, int mid, int right, int[] temp, int groupSize) {
        // 初始化i, 左边有序序列的初始索引
        int i = left;
        // 初始化j, 右边有序序列的初始索引
        int j = mid + 1;
        // 指向temp数组的当前索引
        int cur = 0;

        /// 先把左右两边(有序)的数据按照规则填充到temp数组,直到左右两边的有序序列,有一边处理完毕为止
        while (i <= mid && j <= right) {
            if (compare(list.get(groupSize * i), list.get(groupSize * j))) {
                // --if-- 如果compare方法返回true,这里的compare由用户自定义,即将左边的当前元素填充到temp数组中
                setValueFromListToArr(temp, cur, list, i, groupSize);
                cur += 1;
                i += 1;
            } else {
                // 否则,将右边有序序列的当前元素填充到temp数组
                setValueFromListToArr(temp, cur, list, j, groupSize);
                cur += 1;
                j += 1;
            }
        }

        /// 把有剩余数据的一边的数据依次全部填充到temp
        while (i <= mid) {
            // --if-- 左边的有序序列还有剩余的元素,就全部填充到temp
            setValueFromListToArr(temp, cur, list, i, groupSize);
            cur += 1;
            i += 1;
        }
        while (j <= right) {
            // --if-- 右边的有序序列还有剩余的元素,就全部填充到temp
            setValueFromListToArr(temp, cur, list, j, groupSize);
            cur += 1;
            j += 1;
        }

        /// 将temp数组的元素拷贝到list中
        cur = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            setValueFromArrToList(list, tempLeft, temp, cur, groupSize);
            cur += 1;
            tempLeft += 1;
        }

    }

    /**
     * 如果想要 升序 ,那num1<num2的时候就返回true ; 反之为降序
     *
     * @param num1
     * @param num2
     * @return
     */
    public abstract boolean compare(Integer num1, Integer num2);

    /**
     * 定义方法以交换两个组中的元素,将集合的小组的元素设置到数组的小组中
     * 例如:切换第1组和第2组。我们需要将第1组的所有元素与第2组的所有元素交换
     * @param receiptArr
     * @param receiveIndex
     * @param sendList
     * @param sendIndex
     * @param groupSize
     */
    private void setValueFromListToArr(int[] receiptArr, int receiveIndex, List<Integer> sendList, int sendIndex, int groupSize) {
        for (int i = 0; i < groupSize; i++) {
            receiptArr[groupSize * receiveIndex + i] = sendList.get(groupSize * sendIndex + i);
        }
    }

    private void setValueFromArrToList(List<Integer> receiptList, int receiveIndex, int[] sendArr, int sendIndex, int groupSize) {
        // 一次设置多个元素
        for (int i = 0; i < groupSize; i++) {
            receiptList.set(groupSize * receiveIndex + i, sendArr[groupSize * sendIndex + i]);
        }
    }

}

【子类】

package com.dam.algorithm.version3.merge;

import com.dam.algorithm.version3.shell.GroupShellSort;

/**
 * @Author dam
 * @create 2023/9/13 13:55
 */
public class VScanLineGroupMergeSort extends GroupMergeSort {
    /**
     * 单例模式
     */
    private static volatile VScanLineGroupMergeSort instance;

    private VScanLineGroupMergeSort() {
    }

    public static VScanLineGroupMergeSort getInstance() {
        if (instance == null) {
            synchronized (VScanLineGroupMergeSort.class) {
                if (instance == null) {
                    instance = new VScanLineGroupMergeSort();
                }
            }
        }
        return instance;
    }

    @Override
    public boolean compare(Integer num1, Integer num2) {
        // 如果num1更小,先填充num1到temp中,说明排序类型为升序排序
        if (num1 < num2) {
            return true;
        }
        return false;
    }
}

数组版本

package com.dam.algorithm.version3.merge;

/**
 * @Author dam
 * @create 2023/9/13 14:39
 */
public class GroupMergeSortTest {

    public static void main(String[] args) {
        int[] array = {3, 5, 1, 2, 7, 6, 8, 9, 4, 1, 9, 17};
        int groupSize = 3;

        // 排序
        sort(array, groupSize);

        // 打印排序后的数组
        for (int i : array) {
            System.out.print(i + " ");
        }
    }


    public static void sort(int[] arr, int groupSize) {
        int[] temp = new int[arr.length];
        mergeSort(arr, 0, arr.length / groupSize - 1, temp, groupSize);
    }

    public static void mergeSort(int[] arr, int left, int right, int[] temp, int groupSize) {
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid, temp, groupSize);
            mergeSort(arr, mid + 1, right, temp, groupSize);
            merge(arr, left, mid, right, temp, groupSize);
        }
    }

    public static void merge(int[] arr, int left, int mid, int right, int[] temp, int groupSize) {
        int i = left;
        int j = mid + 1;
        int cur = 0;

        while (i <= mid && j <= right) {
            if (compare(arr[groupSize * i], arr[groupSize * j])) {
                setValueFromSendToReceive(temp, cur, arr, i, groupSize);
                cur += 1;
                i += 1;
            } else { 
                setValueFromSendToReceive(temp, cur, arr, j, groupSize);
                cur += 1;
                j += 1;
            }
        }

        while (i <= mid) {
            setValueFromSendToReceive(temp, cur, arr, i, groupSize);
            cur += 1;
            i += 1;
        }

        while (j <= right) {
            setValueFromSendToReceive(temp, cur, arr, j, groupSize);
            cur += 1;
            j += 1;
        }

        cur = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            setValueFromSendToReceive(arr, tempLeft, temp, cur, groupSize);
            cur += 1;
            tempLeft += 1;
        }
    }

    public static void setValueFromSendToReceive(int[] receiptArr, int receiveIndex, int[] sendArr, int sendIndex, int groupSize) {
        for (int i = 0; i < groupSize; i++) {
            receiptArr[groupSize * receiveIndex + i] = sendArr[groupSize * sendIndex + i];
        }
    }

    public static boolean compare(Integer num1, Integer num2) {
        if (num1 < num2) {
            return true;
        }
        return false;
    }

}

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

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

相关文章

upload-labs文件上传靶场实操

文章目录 1.Pass-012.Pass-023.Pass-034.Pass-045.Pass-056.Pass-067.Pass-078.Pass-089.Pass-0910.Pass-1011.Pass-1112.Pass-1213.Pass-1314.Pass-1415.Pass-1516.Pass-16 1.Pass-01 改后缀名绕过 只能上传图片&#xff0c;先上传一个jpg格式的图片&#xff0c;然后抓包改格…

如何在 Excel 中进行加,减,乘,除

在本教程中&#xff0c;我们将执行基本的算术运算&#xff0c;即加法&#xff0c;减法&#xff0c;除法和乘法。 下表显示了我们将使用的数据以及预期的结果。 | **S / N** | **算术运算符** | **第一个号码** | **第二个号码** | **结果** | | 1 | 加法&#xff08;&#xff…

企业形象片宣传片策划要从哪里展开

企业形象片宣传片是一种有效的营销工具&#xff0c;能够向潜在客户传达企业的核心价值观、品牌形象和产品服务。对于企业来说&#xff0c;一个成功的宣传片可以增加品牌知名度&#xff0c;提高销售额&#xff0c;并建立与客户的良好关系。然而&#xff0c;要想策划一部成功的企…

org.apache.hadoop.hbase.PleaseHoldException: Master is initializing

背景 CDH集群切换数据盘&#xff0c;导致服务无法启动&#xff0c;卸载重装了 hbase、hdfs、yarn、oozie、spark等服务&#xff0c;未卸载重装的zookeeper、kafka。 重装hbase后无法创建表。 报错 hbase(main):001:0> create test,cf1 ERROR: org.apache.hadoop.hbase.Pl…

【计算机网络】传输层协议——TCP(上)

文章目录 TCPTCP协议段格式报头和有效载荷如何分离&#xff1f;4位首部长度 TCP可靠性确认应答机制的提出序号和确认序号为什么序号和确认序号在不同的字段&#xff1f; 16位窗口大小 6个标志位标志位本质具体标志位PSHRSTURG 超时重传机制 文章目录 TCPTCP协议段格式报头和有效…

SAP SD之定义装运点OVL2

什么是装运点&#xff1f; 装运点是一个独立的组织实体&#xff0c;其中进行货物的发行和交付处理。 可以为每个订单商品确定一个装运点。 确定装运点取决于以下三个因素&#xff1a; 客户主记录中的运输条款和条件&#xff08;运输屏幕&#xff09;。 例如&#xff0c;公司与…

为什么选择C/C++内存检测工具AddressSanitizer?如何使用AddressSanitizer?

目录 1、C程序中的内存问题 2、AddressSanitizer是什么&#xff1f; 3、AddressSanitizer内存检测原理简述 3.1、内存映射 3.2、插桩 4、为什么选择AddressSanitizer&#xff1f; 4.1、Valgrind介绍 4.2、AddressSanitizer在速度和内存方面为什么明显优于Valgrind 4.3…

安卓最强LSPosed框架v1.9.1正式版下载-API变更-支持安卓14新系统+刷入教程

LSPosed框架自1.86以后比较稳定&#xff0c;LSPosed官方更新的也变慢了很多&#xff0c;上周开始LSP框架又开始了大版本更新&#xff0c;直接迭代到V19.1版本。单从更新日志上来看&#xff0c;这两次的更新幅度比较大&#xff0c;也修复了很多我们常见的问题。从我们正常刷入体…

C语言——字符函数和字符串函数_学习笔记

本文目录 一、字符函数1.1 字符分类函数常见的字符分类函数介绍应用举例 1.2 字符转换函数函数介绍toupper 函数举例 二、字符串函数2.1 常用的字符串函数介绍2.2 应用举例① strlen② strcpy③ strcat④ strcmp⑤ strncpy⑥ strncat⑦ strncmp⑧ strstr⑨ strtok 关于一些字符…

【新版vscode配置自动补全括号】

vscode新版配置自动补全括号方法 新版配置方法(Pylance) ①设置 -> 扩展 -> Pylance -> 将 python.analysis.completeFunctionParens 下方的选项打勾 ②直接在settings.json中添加"python.analysis.completeFunctionParens": true

书单背景图和视频制作方法分享

如今&#xff0c;在社交媒体上发布一张书单背景图或宣传视频已成为推广阅读和书籍的流行方式。这些视觉内容能够吸引读者的眼球并提供一些简单易懂的信息&#xff0c;如书名、作者、简介等。下面是一些简单的方法&#xff0c;可以帮助你创建出与众不同的书单背景图和视频。 创意…

kubernetes安全检测工具-kube-bench

一、kube-bench基础介绍 kube-bench是基于go语言开发、一款针对kubernetes进行安全检测的工具&#xff0c;主要是检测kubernetes集群的各个组件的配置&#xff0c;确认配置文件是否符合安全基线标准&#xff0c;输出检测报告&#xff0c;并给出修复建议&#xff0c;从而使kuber…

Jetson nano嵌入式平台配置ip记录

背景 Jetson nano平台使用千兆网和PC连接时没有ip地址&#xff0c;在ubuntu的终端输入ifconfig显示eh0未设置ip&#xff0c;需要先在nano平台上配置ip地址&#xff0c;然后PC通过千兆网远程控制该平台。 配置ip 使用终端进入到network文件夹中&#xff0c; cd /etc/network…

C++之list

目录 一、关于list 二、list相关函数 三、相关函数的使用 1、构造函数 2、push_back 3、迭代器 4、push_front 5、pop_back 6、insert 7、erase 关于迭代器失效问题 8、splice 9、remove 10、sort 一、关于list list和string、vector一样&#xff0c;都是容器&am…

领域驱动设计:微服务的各种边界

文章目录 演进式架构微服务还是小单体&#xff1f;微服务边界的作用 在用 DDD 进行微服务设计时&#xff0c;我们可以通过事件风暴来确定领域模型边界&#xff0c;划定微服务边界&#xff0c;定义业务和系统运行边界&#xff0c;从而保证微服务的单一职责和随需而变的架构演进能…

【Python】简记操作:Centos安装Python3虚拟环境-virtualenvwrapper

安装 pip3 install virtualenvwrapper 安装时报错&#xff1a;ERROR: Can not execute setup.py since setuptools is not available in the build environment. 原因&#xff1a; setuptools版本过低&#xff1b; 解决&#xff1a;升级setuptools # 升级setuptools版本 pi…

创邻科技,位居IDC MarketScape中国图数据库市场领导者类别

图数据库&#xff0c;正进入市场发展的新阶段。 随着中国经济社会数字化转型加速&#xff0c;数据成为新型生产要素。如何存储并管理海量数据&#xff0c;挖掘数据价值&#xff0c;打破原有增长天花板&#xff0c;成为企业重塑商业价值的关键。存量经济时代更需要深层关系挖掘&…

【深度学习】- NLP系列文章之一文本表示

系列文章目录 文本分类与词嵌入表示RNN、LSTM、GRU三种方式处理文本分类问题评论情绪分类 还是得开个坑&#xff0c;最近搞论文&#xff0c;使用lstm做的ssd的cache prefetching&#xff0c;意味着我不能再划水了。 文章目录 系列文章目录1. 文本数据表示法与词嵌入1.1 文本是…

蓝牙技术|8月公共充电桩环比增加6.1万台,蓝牙充电桩持续增长

中国充电联盟发布 2023 年 8 月全国电动汽车充换电基础设施运行情况。公共充电基础设施运行情况&#xff1a;2023 年 8 月比 7 月公共充电桩增加 6.1 万台&#xff0c;8 月同比增长 39.9%。截至 2023 年 8 月&#xff0c;联盟内成员单位总计上报公共充电桩 227.2 万台&#xff…

23062C++QTday5

将之前定义的栈类和队列类都实现成模板类 栈&#xff1a; #include <iostream> #define MAX 128using namespace std;template<typename T,typename C> class Stack { private:T top; //栈顶元素的下标C *data; //指向堆区空间public:Sta…