归并排序——数组和链表实现

387 阅读2分钟

原理

分治思想,二叉树思想,n/2到元素分到个体(个体有序),然后再往上走,到n/2,一开始创建一个空数组,比较左一和右一大小,小的放入然后右移。最后实现拷贝。

3.gif

image.png image.png 上面两张图片图片来自 www.cnblogs.com/chengxiao/p…

复杂度

时间复杂度:O(log2n) 空间复杂度:O (n)

数组代码实现

class Solution {
    public int[] mergeSort(int[] arry) {
        return sort(arry,0,length-1);
    }
    // "分" 把数组分到一个子元素,然后排序,再 归
    public int[] sort(int[] arry,int L,int R){
        if (L==R){
            return arry;
        }
        // 防止溢出,(R - L)>>1右移一位,相当于除以2
        int mid = L +((R - L)>>1);
        sort(arry,L,mid);
        sort(arry,mid+1,R);
        return merge(arry,L,mid,R);
    }
    // “治”对分完的数组进行排序
    public int[] merge(int[] arry,int L ,int mid,int R){
        int[] temp =new int[R-L+1];
        int i = 0;
        int p1 = L;
        int p2 = mid+1;
        // 比较左右,在临时数组中填入小的
        while(p1 <= mid && p2 <= R){
            temp[i++] = arry[p1] < arry[p2] ? arry[p1++]:arry[p2++];
        } 
        // 循环退出,一边走完了,将没有走完的那边(剩下的都是大的),拷贝到临时数组
        while(p1 <= mid){
            temp[i++] = array[p1++];
        }
        while(p2 <= R){
            temp[i++] = array[p2++];
        }
        // 将排序结果拷贝到原数组
        for(i = 0;i<temp.length;i++){
            arry[L+i]=temp[i];
        }
        return arry;
    }

}

链表代码实现

  1. 排序链表 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶:

你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

class Solution {
    public ListNode sortList(ListNode head) {
        return merge(head);
    }
    // 实现 “分” 利用快慢指针找中点,然后递归,实现分
    public ListNode merge(ListNode head){
        if(head == null || head.next == null){
            return head;
        }
        ListNode slow = head, fast = head,pre = null;
        while(fast != null && fast.next != null){
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode r=merge(slow);
         // pre比slow慢一步,pre.next置为null用来得到独立的前半部分,
        pre.next = null;
        // ListNode l = merge(pre);
        ListNode l = merge(head);
        return Listmerge(l,r);
    }
    // 实现 “治” 比较左右的大小:左右头结点比较,记录小的并++
    public ListNode Listmerge(ListNode l, ListNode r){
        // dummyHead 返回next
        ListNode dummyHead =new ListNode(0);
        ListNode head = dummyHead;
        while(l != null && r != null){
            if(l.val <= r.val){
                head.next = l;
                l = l.next;
                head =  head.next;
            }else{
                head.next = r;
                r = r.next;
                head =  head.next;
            }
        }
        // 直到一边为空,拷贝另一边
        if(l != null){
            head.next = l;
        }
        if(r != null){
            head.next = r;
        }
        // head.next = l != null?l:r;
        return dummyHead.next;
    }
}