JAVA 分成块块的归并排序

庭前落尽芙蓉,水边开彻芙蓉。—朱庭玉(元) 天净沙·秋思

目录:

归并排序

归并排序是数据结构中比较重要对同一种排序方法,属于必须掌握的范畴。

分析

主要分为两大步:
1.分割,将数据(节点)一分为二,依次递归,递归…
2.合并,将一个个数据(节点)合二为一;

定义一个Node类用来装元素

/**
 * 节点
 */
 class ListNode {
     int val;
     ListNode next;
     ListNode(int x) {
         val = x;
         next = null;
     }
 }

分割

这里是用两个快慢指针,差半找中间值的。

/**
 *   1.从中间分开,分啊分成一块块的
 *   2.合并,怎么合并?当然是比较1.分开之后的两端啊然后合并啊
*/
    }
    public static ListNode sortList(ListNode head){
        /**
         * if语句,递归出口,当前为空或者下一步为空就没必要再递归了,使用短路||
         */
        if (null == head || null ==head.next){
            return head;
        }
        ListNode fast = head;
        ListNode slow = head;
        /**
         * 找中点啊,找啊找
         */
        while (null != fast.next && null != fast.next.next){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode tmp = slow.next;
        slow.next = null;
        ListNode preHead = sortList(head);
        ListNode tailHead = sortList(tmp);
        /**
         * 合并之后,返回递归上层
         */
        return mergerList(preHead,tailHead);
    }

合并

和并的头尾的判断很重要,很容易在写的时候忽略掉。

 public static ListNode mergerList(ListNode preHead,ListNode tailHead){
        /**
         * 分割到一个时,有一个传过来就是null,没必要再排序,直接返回非空即可
         */
        if (null == preHead) {
            return  tailHead;
        }
        if (null == tailHead){
            return  preHead;
        }
        /**
         * retuNode用来迭代;实际上是一个带有节点的单链表;
         * tmp用来保存retuNode的头指针,用来返回
         */
        ListNode retuNode = new ListNode(0);
        ListNode tmp = retuNode;
        /**
         * 1.其中一个为空就退出循环,需要注意的是最后把没循环的要追加上
         * 2.每次只比较一个
         * 3.返回tmp的下一个节点,因为这是一个带头节点
         */
        while (null != preHead && null != tailHead){
            if (preHead.val > tailHead.val){
                retuNode.next = tailHead;
                tailHead = tailHead.next;

            } else{
                retuNode.next = preHead;
                preHead = preHead.next;
            }
            retuNode = retuNode.next;
        }
        if (null != tailHead){
            retuNode.next = tailHead;
        }
        if (null != preHead) {
            retuNode.next = preHead;

        }
        return tmp.next;
    }
}

测试代码

测试代码是必不可少的,能跑过不一定就是对的。

public class MergeSort {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        /**
        *创建测试链表,偷懒
        */
        head.next = new ListNode(5);
        head.next.next = new ListNode(3);
        head.next .next.next= new ListNode(2);
        head.next .next.next.next= new ListNode(4);
        sortList(head);
        /**
        *打印结果
        */
        while (null != head){
            System.out.print(head.val + " ");
            head = head.next;
        }
        // 结果:1 2 3 4 5 

全部代码

package practice;


/**
 * 节点
 */
 class ListNode {
     int val;
     ListNode next;
     ListNode(int x) {
         val = x;
         next = null;
     }
 }

/**
 * 归并排序
 */
public class MergeSort {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(5);
        head.next.next = new ListNode(3);
        head.next .next.next= new ListNode(2);
        head.next .next.next.next= new ListNode(4);
        sortList(head);
        while (null != head){
            System.out.print(head.val + " ");
            head = head.next;
        }
/**
 *   1.从中间分开,分啊分
 *   2.合并,怎么合并?当然是比较1.分开之后的两端啊然后合并啊
*/
    }
    public static ListNode sortList(ListNode head){
        /**
         * if语句,递归出口,当前为空或者下一步为空就没必要再递归了,使用短路||
         */
        if (null == head || null ==head.next){
            return head;
        }
        ListNode fast = head;
        ListNode slow = head;
        /**
         * 找中点啊,找啊找
         */
        while (null != fast.next && null != fast.next.next){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode tmp = slow.next;
        slow.next = null;
        ListNode preHead = sortList(head);
        ListNode tailHead = sortList(tmp);
        /**
         * 合并之后,返回递归上层
         */
        return mergerList(preHead,tailHead);
    }
    public static ListNode mergerList(ListNode preHead,ListNode tailHead){
        /**
         * 分割到一个时,有一个传过来就是null,没必要再排序,直接返回非空即可
         */
        if (null == preHead) {
            return  tailHead;
        }
        if (null == tailHead){
            return  preHead;
        }
        /**
         * retuNode用来迭代;实际上是一个带有节点的单链表;
         * tmp用来保存retuNode的头指针,用来返回
         */
        ListNode retuNode = new ListNode(0);
        ListNode tmp = retuNode;
        /**
         * 1.其中一个为空就退出循环,需要注意的是最后把没循环的要追加上
         * 2.每次只比较一个
         * 3.返回tmp的下一个节点,因为这是一个带头节点
         */
        while (null != preHead && null != tailHead){
            if (preHead.val > tailHead.val){
                retuNode.next = tailHead;
                tailHead = tailHead.next;

            } else{
                retuNode.next = preHead;
                preHead = preHead.next;
            }
            retuNode = retuNode.next;
        }
        if (null != tailHead){
            retuNode.next = tailHead;
        }
        if (null != preHead) {
            retuNode.next = preHead;

        }
        return tmp.next;
    }
}

小结

归并排序很重要,一定要经常复习。
源码:>GitHub<

猜你喜欢

转载自blog.csdn.net/logicr/article/details/80700090