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

归并排序

时间:2022-08-18 22:59:55浏览次数:80  
标签:归并 ListNode int mid arr next 排序 head

归并排序

  1. 整体上是递归,左边排好序+右边排好序+merge让整体有序

  2. 让其整体有序的过程里用来排外序方法

  3. 利用master公式来求解时间复杂度

  4. 当然可以用非递归实现

例:无序数组arr[L.....R]排序

master:T(N) = 2*T(N/2)+O(N),为什么是N呢,因为这个数组总长度是N,在merge方法中,排序实际上是左边走了一半N,右边走了一半N,加起来常数操作就是N

时间复杂度:O(Nlog(2,N)) 额外空间复杂度:O(N):由于每次开空间都是开了一个长度N的数组,用完就释放了

public static void process(int[] arr, int L, int R){
    if(L==R){
        return ;//如果这个数字只有1位直接返回就行
    }
    int mid = L+((R-L)>>1);//取中间下标
    process(arr, L, mid);//排序从小到大
    process(arr, mid+1, R);//排序从小到大
    merge(arr,L,mid,R);//归并方法
}
public static void merge(int[] arr, int L, int M, int R){
    int[] temp = new int[R-L+1];//临时数组,长度为l到r的元素个数,用于存储归并的答案
    int i = 0;//temp开始的下标
    int p1 = L;//第一个指针从数组最左端开始的下标
    int p2 = M+1;//第二个指针从中间的数后一个开始
    while(p1 <= M && p2 <= R){//如果指针1和指针2都没有越界
        //如果从Mid中间数分开数组,左边的第i个数比中间右边的第i个数大,那么temp的第i个数就是左边的第i个数,然后让左边的下标+1,反之就是右边,然后让右边的下标+1
        temp[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
    }
    //上述循环完后,p1如果没有越界,那么就是p2越界了,把剩下的左边数字全部加入tempt数组中,这个循环和下一个循环只会发生一个
    while(p1 <= M){
        temp[i++] = arr[p1++]
    }
    //上述大循环完后,p2数字没有越界,就是p1越界,把右边剩下的数字全部加入temp
    while(p2 <= R){
        temp[i++] = arr[p2++]
    }
    //上面两个循环的判断条件就是p1,p2两个指针一个越界一个没越界,他两个必然发生一个或者一个都不发生,所以不用管他俩是否都发生的情况,这么写就可以节省空间
    
    //将临时数组里面的内容拷贝回原数组
    for(int j = 0; j < tmp.length; j++){
        arr[L+j] = temp[j];
    }
}

例:小和问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和D

求[1, 3, 4, 2, 5]的小和 就是 1+1+3+1+1+3+4+2 = 16

也可以这么想,在第i个数右侧,有几个数比他大,那么这个数就加了几次

比如1的右侧有4个数比1大,就是4*1,3的右边有2个数比3大,就是2×3,4的右边有一个数比4大,就是1×4,5右边没数了

使用归并方法找小和

1、就上面的例子来说,首先我们找到中点,把这个数组分成[1,3,4] [2, 5]

2、[1,3,4]继续分,分成[1,3] [4],再分[1] [3] 我们先看1和3,1比右侧的3小,那么就小数加上一个1,右指针移动看1和4,1比4小,小数再加上一个1,左指针移动看3和4,3比4小,小数加一个3,指针越界,然后这左边就结束了

3、看右侧[2,5],继续分[2],[5],看2 5 ,2比5小,小数加一个2,指针越界,右边结束

4、我们继续看左边整体和右边整体,左边指针在最左侧1上,右边指针在2上,1小于2,加一个1,右边指针右移,1小于5,加一个1,左边指针右移,3大于2,右边指针右移,3小于5,加一个3,左边指针右移4小于5,加一个4,然后两边指针越界,结束。

5、最终得到小数位16

public static int process(int[] arr, int l, int r){
    if(l == r){
        return 0;
    }
    int mid = l + ((r -1) >> 1);
    return process(arr, l, mid)//左侧排序求小和的数量
        +  process(arr, mid + 1, r)//右侧排序求小和的数量
        +  merge(arr, l, mid, r);//左右排序号,然后合并求小和的数量
}
public static int merge(int[] arr, int L, int m, int r){
    int[] temp = new int[r-L+1];
    int i = 0;
    int p1 = L;
    int p2 = m + 1;
    int res = 0;
    //左组和右组都没有越界的情况下
    while(p1 <= m && p2 <= r){
        //求小和的目的
        //左组的数比右组的数组小,则小和=右组的长度-右组的指针+1乘左组的数本身,也就是排序完右组比左组那个数大的数的个数*左组的数本身。
        //如果左组没有比右组的小,增加的就是0
        res += arr[p1] < arr[p2] ? (r - p2 +1) * arr[p1] : 0;
        //如果左组的数比右组的大,那么拷贝左组,右组大拷贝右组,到新的数组中
        temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    while(p1 <= m){
        //如果左没越界,但右组越界了,就让左侧的数组全部拷贝到临时数组中。这里是不产生小和的
        temp[i++] = arr[p1++];
    }
    while(p2 <= r){
         //如果右没越界,但左组越界了,就让右侧的数组全部拷贝到临时数组中,不产生小和
        temp[i++] = arr[p2++];
    }
    //将临时数组中所有数,全都放到原数组中,达成排序的目的
    for(int j = 0; j < temp.length; i++){
        arr[L + j] = temp[i];
    }
    //返回小和
    return res;
}

例:逆序对问题

在一个数组中,左边的数比右边的大,则这两个数构成一个逆序对,请打印所有的逆序对

public static String process(int[] arr,int L,int R){
    if(L==R){
        return;
    }
    int mid = L+((R-L)>>1);
    return process(arr, L, M) +
           process(arr, M+1, R)+
           merge(arr, L, mid, R);
}
​
pubilc static String process(int[] arr, int L, int mid, int R){
    int i = 0;
    int p1 = 0;
    int p2 = 0;
    int temp = new int[R-L+1];
    String str = "";
    while(p1 <= mid && p2 <= R){
        str += arr[p1] < arr[p2] ? arr[p1]+""+arr[p2] : null;
        temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    while(p1 <= mid){
        temp[i++] = arr[p1++];
    }
    while(p2 <= R){
        temp[i++] = arr[p2++];
    }
    return str;
}

148. 排序链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        //递归停止条件
        if(head == null || head.next == null){
            return head;
        }
        ListNode mid = getMidNode(head);
        ListNode newHead = mid.next;
        mid.next = null;//制空mid后面的,让原链表断成两个
        ListNode L = sortList(head);
        ListNode R = sortList(newHead);
        return merge(L, R);
    }
    //取得中点
    public ListNode getMidNode(ListNode head){
        if(head.next == null || head.next.next == null){
            return head;
        }
        ListNode fast = head.next.next;
        ListNode slow = head;
        while(fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
    //归并两个链表
    public ListNode merge(ListNode L, ListNode R){
        ListNode dummyHead = new ListNode(-1);
        ListNode cur = dummyHead;
        while(L != null && R != null){
            if(L.val < R.val){
                cur.next = L;
                L = L.next;
            }else{
                cur.next = R;
                R = R.next;
            }
            cur = cur.next;
        }
        //如果节点数不是偶数,最后肯定会多一个出来,谁不是空就把谁放当前链表最后一个
        cur.next = L != null ? L : R;
        return dummyHead.next;
​
    }
    
}

标签:归并,ListNode,int,mid,arr,next,排序,head
From: https://www.cnblogs.com/phonk/p/16600400.html

相关文章

  • go 接口 实现sort排序接口 进行自定义排序
    packagemainimport("fmt""math/rand""sort")//学生结构体typeStudentstruct{NamestringIdstringAgeint}typeStudentA......
  • 05 - Volatile伪共享问题与Volatile重排序问题
    为什么Volatile不能保证原子性publicclassVolatileAtomThreadextendsThread{privatestaticvolatileintcount;publicstaticvoidmain(String[]arg......
  • 拓扑排序
    拓扑排序2022.8.16背景今天是LAF的生日,在被他的生日赛虐的时候,发现拓扑排序忘得差不多了,赶紧总结一下……问题设你有n个任务需要完成,一次只能完成一个任务,完成这些任......
  • 字符串大小写规则排序
    输入BadbAbB,输出AaBBbbd。因为A的ascii码比a小,所以相等的时候,直接输出a<b。不相等的时候,如果一个是大写,一个是小写,就要转换之后再比较。 #include<iostream>#include......
  • 亮点4-搜索结果的重新排序采用了本地单页排序和服务端多页排序两种可选模式-《教育行
    《教育行业核心数据流程管理平台》的设计当中,《学生基本信息》管理模块是一个最基本的模块,也是一个十分重要的平台组成部分。它的设计好坏,直接关系到业务管理人员的工作效......
  • Python快速排序
    defquicksort(array):less=[]greater=[]iflen(array)<=1:returnarraypivot=array.pop()forxinarray:ifx<=p......
  • 7-12 排序
    给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:数据1:只有1个元素;数据2:11个......
  • 经典排序之堆排序
    堆排序思路堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分......
  • Python 字典排序
    字典是“键-值对”的无序可变序列在实际运用中,对字典进行排序是一个比较常见的操作,主要用到了python内置函数sorted(),该函数可以对所有可迭代的对象进行排序操作。语法(pyth......
  • 排序算法
    1. 排序算法面试中 面试高频又快排、堆排和归并排序先说快排,快排体现的的思想是:分而治之,并且递归 怎么个分呢,选第一个数进行强行将数据分成两拨。此时需要一个函......