首页 > 其他分享 >7、归并排序

7、归并排序

时间:2023-04-10 14:58:32浏览次数:32  
标签:归并 temp int arr mid 排序 size

1、归并排序

归并排序:O(N * logN)

public class MergeSort {

    private MergeSort() {
    }

    /**
     * 归并排序
     */
    public static <E extends Comparable<E>> void sort(E[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    /**
     * 归并排序 arr[l, r]
     */
    private static <E extends Comparable<E>> void sort(E[] arr, int l, int r) {
        if (l >= r) return;

        int mid = l + (r - l) / 2;
        sort(arr, l, mid);     // arr[l, mid]
        sort(arr, mid + 1, r); // arr[mid + 1, r]

        merge(arr, l, mid, r);
    }

    /**
     * 合并两个有序数组 arr[l, mid] 和 arr[mid + 1, r], 使得 arr[l, r] 整体有序
     */
    private static <E extends Comparable<E>> void merge(E[] arr, int l, int mid, int r) {
        E[] temp = Arrays.copyOfRange(arr, l, r + 1);

        int p1 = 0;           // temp[0, mid - l]
        int p2 = mid + 1 - l; // temp[mid + 1 - l, r - l]
        int i = l;            // arr[l, r]

        while (p1 <= mid - l && p2 <= r - l) arr[i++] = temp[p1].compareTo(temp[p2]) <= 0 ? temp[p1++] : temp[p2++];
        while (p1 <= mid - l) arr[i++] = temp[p1++];
        while (p2 <= r - l) arr[i++] = temp[p2++];
    }
}

2、归并排序优化

归并排序:O(N * logN)
优化 1:merge 条件, 对完全有序的数组 O(n)
优化 2:数据量小的时候(<=16)采用插入排序
优化 3:避免频繁的在内存中开辟空间

public class MergeSortPlus {
    
    private MergeSortPlus() {
    }

    /**
     * 归并排序
     */
    public static <E extends Comparable<E>> void sort(E[] arr) {
        E[] temp = (E[]) new Comparable[arr.length]; // 优化 3: 避免频繁的在内存中开辟空间
        sort(arr, 0, arr.length - 1, temp);
    }

    /**
     * 归并排序 arr[l, r]
     */
    private static <E extends Comparable<E>> void sort(E[] arr, int l, int r, E[] temp) {
        if (r - l <= 15) {
            InsertionSort.sort(arr, l, r); // 优化 2: 数据量小的时候(<=16)采用插入排序
            return;
        }
        
        int mid = l + (r - l) / 2;
        sort(arr, l, mid, temp);     // arr[l, mid]
        sort(arr, mid + 1, r, temp); // arr[mid + 1, r]
        
        if (arr[mid].compareTo(arr[mid + 1]) > 0) merge(arr, l, mid, r, temp); // 优化 1: merge 条件
    }

    /**
     * 合并两个有序数组 arr[l, mid] 和 arr[mid + 1, r], 使得 arr[l, r] 整体有序
     */
    private static <E extends Comparable<E>> void merge(E[] arr, int l, int mid, int r, E[] temp) {
        System.arraycopy(arr, l, temp, l, r - l + 1);
        
        int p1 = l;       // temp[l, mid]
        int p2 = mid + 1; // temp[mid + 1, r]
        int i = l;        // arr[l, r]
        
        while (p1 <= mid && p2 <= r) arr[i++] = temp[p1].compareTo(temp[p2]) <= 0 ? temp[p1++] : temp[p2++];
        while (p1 <= mid) arr[i++] = temp[p1++];
        while (p2 <= r) arr[i++] = temp[p2++];
    }
}

3、自底向上归并排序

我们上面实现的归并排序,采用递归的写法,自顶向下进行归并排序
在这里我们换个方式,采用非递归的写法,自底向上实现归并排序

public class MergeSortBU {
    
    private MergeSortBU() {
    }

    /**
     * 自底向上归并排序
     */
    public static <E extends Comparable<E>> void sort(E[] arr) {
        int n = arr.length;
        E[] temp = (E[]) new Comparable[n];
        
        // 对 arr[0, n - 1] 中所有的 arr[i, i + 15], 使用插入排序法
        for (int i = 0; i < n; i += 16) {
            InsertionSort.sort(arr, i, Math.min(i + 15, n - 1));
        }
        
        // 遍历合并的区间长度(把 2 个区间合并成 1 个区间)
        for (int size = 16; size < n; size += size) {
            // 合并 arr[i, i + size - 1] 和 arr[i + size, i + size + size - 1]
            for (int i = 0; i + size < n; i += 2 * size) {
                if (arr[i + size - 1].compareTo(arr[i + size]) > 0) {
                    merge(arr, i, i + size - 1, Math.min(i + size + size - 1, n - 1), temp);
                }
            }
        }
    }

    /**
     * 合并两个有序数组 arr[l, mid] 和 arr[mid + 1, r], 使得 arr[l, r] 整体有序
     */
    private static <E extends Comparable<E>> void merge(E[] arr, int l, int mid, int r, E[] temp) {
        System.arraycopy(arr, l, temp, l, r - l + 1);
        
        int p1 = l;       // temp[l, mid]
        int p2 = mid + 1; // temp[mid + 1, r]
        int i = l;        // arr[l, r]
        
        while (p1 <= mid && p2 <= r) arr[i++] = temp[p1].compareTo(temp[p2]) <= 0 ? temp[p1++] : temp[p2++];
        while (p1 <= mid) arr[i++] = temp[p1++];
        while (p2 <= r) arr[i++] = temp[p2++];
    }
}

标签:归并,temp,int,arr,mid,排序,size
From: https://www.cnblogs.com/n139949/p/17302891.html

相关文章

  • android-RecyclerView实现拖动排序
    android:RecyclerView实现拖动排序最近项目中需要实现对某一类条目进行拖动排序功能,实现技术方案就是利用ItemTouchHelper绑定RecyclerView、ItemTouchHelper.Callback来实现UI更新,并且实现动态控制是否开启拖动功能。其中,ItemTouchHelper是Google在support-v7包中添加的,其于Rec......
  • 快递单号查询入口,批量查询快递单号,对同一天签收的快递单号进行排序或筛选
    如何快速查询多家快递的物流,并筛选出同一天签收的单号呢?今天小编给大家分享一个新的查询技巧,下面一起来试试吧。所需工具安装一个快递批量查询高手快递单号若干操作步骤步骤1:运行【快递批量查询高手】,选择“添加单号”,弹出对话框,将单号复制粘贴进去,保存一下步骤2:保存后,所有快递单号......
  • 2、排序基础
    1、选择排序选择排序是一个基础的排序算法,它的复杂度是O(n2)publicclassSelectionSort{privateSelectionSort(){}privatestatic<E>voidswap(E[]arr,inta,intb){Ek=arr[a];arr[a]=arr[b];arr[b]=k;......
  • List<Map<String, Object>> 排序
    一、代码publicclassTest{publicstaticvoidmain(String[]args){Map<String,Object>map=newHashMap<String,Object>();map.put("name","ZK");map.put("age",13);Map<Str......
  • 数组排序
    1#include<stdio.h>2voidsort1(ints[])3{4inti,j,t;5for(i=0;i<9;i++)6{7for(j=0;j<10;j++)8{9if(s[j]>s[j+1])10{11t=s[j];s[j]=s[j+1];s[j+1]=t;1......
  • * 编程:当前项目的根目录 c.txt 文件中的内容为”abddbskshlsjdhhhiw”;编写程序读取文
    1packageio.homework;23importjava.io.FileReader;4importjava.io.FileWriter;5importjava.io.Reader;6importjava.io.Writer;78publicclassq18{9publicstaticvoidmain(String[]args){10try(Readerfr=newFileReader......
  • P2824 [HEOI2016/TJOI2016]排序 题解
    题目传送门前言线段树好题!!!!咕咕了挺久的一道题目,很早之前就想写了,今天终于找了个时间A掉了。题意给定一个\(1\)到\(n\)的排列,有\(m\)次操作,分两种类型。1.0lr表示将下标在\([l,r]\)区间中的数升序排序。2.1lr表示将下标在\([l,r]\)区间中的数降序排序。给......
  • 算法学习之冒泡排序【C语言】
    冒泡排序排序规则冒泡排序的规则是相邻的两个数字依次比较,如果前面的数字比后面的数字大,则交换它们的位置,否则保持不变,直到遍历完所有的数字。这个过程会不断地进行,直到所有的数字都按照从小到大的顺序排列好。双层循环在冒泡排序的算法中,需要使用两层循环来实现排序功能。for(int......
  • 算法学习之选择排序【C语言】
    选择排序排序规则选择排序是一种简单直观的排序算法,其基本思想是每次从待排序的数据元素中选出最小(或最大)的一个元素,存放到序列的起始位置,直到全部元素排序完成。具体步骤如下:1.从第一个数开始,与其后的数一一比较,如后小前大,则交换,依次比较直至最后一组数。2.通过上述步骤,得到参加循......
  • go语言学习-冒泡排序
    冒泡排序冒泡排序属于交换类的排序算法,比如有一段乱序的数,591681464925463第一轮迭代:从第一个数开始,依次比较相邻的两个数,如果后面的一个数比前面的一个数大,那么交换位置,直接到处理最后一个数,最后这个数是最大的第二轮迭代,因为最后一个数已经是最大的了,重复第一轮操作,......