• 数据结构和算法-单链表排序


    参考:

    https://leetcode-cn.com/problems/sort-list

    https://blog.csdn.net/Jacketinsysu/article/details/52472364?utm_source=blogkpcl7

    https://zhuanlan.zhihu.com/p/85122573 【插入排序todo】

    https://zhuanlan.zhihu.com/p/90106653

    148. 排序链表

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

    进阶:

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

    示例 1:


    输入:head = [4,2,1,3]
    输出:[1,2,3,4]

    /**
     * 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) {

        }
    }
     
     
    题解:https://leetcode-cn.com/problems/sort-list/solution/sort-list-gui-bing-pai-xu-lian-biao-by-jyd/

    解答一:归并排序(递归法)

    public class SortList148 {
    
        public static void main(String[] args) {
            ListNode listNode1 = new ListNode(4);
            ListNode listNode2 = new ListNode(2);
            ListNode listNode3 = new ListNode(1);
            ListNode listNode4 = new ListNode(3);
            listNode1.next=listNode2;
            listNode2.next=listNode3;
            listNode3.next=listNode4;
    
            ListNode result=  new SortList148().sortList(listNode1);
            while (result!=null){
                System.out.println(result.val);
                result=result.next;
            }
    
        }
    
        static class ListNode{
            int val;
            ListNode next;
    
            public ListNode(int val){
                this.val=val;
                this.next=null;
            }
    
            public ListNode(int val,ListNode listNode){
                this.val=val;
                this.next=listNode;
            }
    
            public ListNode () {
    
            }
        }
    
            public ListNode sortList(ListNode head) {
                if (head == null || head.next == null)
                    return head;
                ListNode fast = head.next, slow = head;
                while (fast != null && fast.next != null) {//我们选用的方法是双指针法,每次一个指针后移一位,另外一个后移两位。
                    slow = slow.next;
                    fast = fast.next.next;
                }
                ListNode tmp = slow.next;//将此引用指向的对象赋值给tmp引用,让tmp引用也指向此对象,如2->[4->5]
                slow.next = null;//此引用改变对象的指向,next指向null,2->null
                ListNode left = sortList(head);
                ListNode right = sortList(tmp);
                ListNode h = new ListNode(0);
                ListNode res = h;//res一直指向0节点,而h则会指向其他节点即其他对象
                while (left != null && right != null) {
                    if (left.val < right.val) {
                        h.next = left;
                        left = left.next;
                    } else {
                        h.next = right;
                        right = right.next;
                    }
                    h = h.next;
                }
                h.next = left != null ? left : right;
                return res.next;
            }
    
    }

    上述引用和对象的操作有点疑惑,故写如下代码进行测试和验证

    public class TestRefDemo {
    
        static class Dog{
            int val;
        }
    
        public static void main(String[] args) {
            int a=1;
            System.out.println("a:"+a);
            method1(a);
            System.out.println("a:"+a);
    
            Dog dog = new Dog();
            dog.val=1;
            Dog dog1=dog;//dog1和dog引用均指向dog对象,所以修改dog对象,打印两个引用的值均改变
            System.out.println("dog:"+dog.val);
            System.out.println("dog1:"+dog1.val);
    
            method(dog);
            dog=null;//dog引用不再指向dog对象,而是指向了null
            //System.out.println("dog:"+dog.val);//Exception in thread "main" java.lang.NullPointerException
            System.out.println("dog1:"+dog1.val);
            
        }
    
        private static void method1(int a) {
            a=2;//基本类型超过作用域则不起作用
        }
    
        private static void method(Dog dog) {
            dog.val=2;//修改了此引用指向的对象
        }
    
    
    }
    a:1
    a:1
    dog:1
    dog1:1
    dog1:2

    解答二:归并排序(迭代法)

    递归的时候,并没有做什么特别的事,只是从中间分成两半,每一半自己去做排序,最后合并起来,是后序遍历,从叶子节点往回看:
    1. 区间的长度都为1,直接返回,不用合并;
    2. 区间的长度为2,两个子区间都排好序了,将它们合并起来;
    3. 区间的长度为4,两个子区间都排好序了,将它们合并起来;
    4. ……

    迭代怎么写?

    从上面的分析可以看出,其实只需要枚举步长1,2,4,……,对由每个步长分开的区间,都合并一下。
    比如,一开始数组为[8 7 6 5 4 3 2 1]。
    第一遍,步长为1,将相邻的两个区间合并(注意加粗黑体):
    7 8 6 5 4 3 2 1
    7 8 5 6 4 3 2 1
    7 8 5 6 3 4 2 1
    7 8 5 6 3 4 1 2

    第二遍,步长为2,将相邻的两个区间合并(注意加粗黑体):
    5 6 7 8 3 4 1 2
    5 6 7 8 1 2 3 4

    第三遍,步长为4,将相邻的两个区间合并(注意加粗黑体):
    1 2 3 4 5 6 7 8

    链接:https://leetcode-cn.com/problems/sort-list/solution/pai-xu-lian-biao-di-gui-die-dai-xiang-jie-by-cherr/
    /**
     * 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) {
            int length = getLength(head);
            ListNode dummy = new ListNode(-1);
            dummy.next = head;
           
            for(int step = 1; step < length; step*=2){ //依次将链表分成1块,2块,4块...
                //每次变换步长,pre指针和cur指针都初始化在链表头
                ListNode pre = dummy; 
                ListNode cur = dummy.next;
                while(cur!=null){
                    ListNode h1 = cur; //第一部分头 (第二次循环之后,cur为剩余部分头,不断往后把链表按照步长step分成一块一块...)
                    ListNode h2 = split(h1,step);  //第二部分头
                    cur = split(h2,step); //剩余部分的头
                    ListNode temp = merge(h1,h2); //将一二部分排序合并
                    pre.next = temp; //将前面的部分与排序好的部分连接
                    while(pre.next!=null){
                        pre = pre.next; //把pre指针移动到排序好的部分的末尾
                    }
                }
            }
            return dummy.next;
        }
        public int getLength(ListNode head){
        //获取链表长度
            int count = 0;
            while(head!=null){
                count++;
                head=head.next;
            }
            return count;
        }
        public ListNode split(ListNode head,int step){
            //断链操作 返回第二部分链表头
            if(head==null)  return null;
            ListNode cur = head;
            for(int i=1; i<step && cur.next!=null; i++){
                cur = cur.next;
            }
            ListNode right = cur.next;
            cur.next = null; //切断连接
            return right;
        }
        public ListNode merge(ListNode h1, ListNode h2){
        //合并两个有序链表
            ListNode head = new ListNode(-1);
            ListNode p = head;
            while(h1!=null && h2!=null){
                if(h1.val < h2.val){
                    p.next = h1;
                    h1 = h1.next;
                }
                else{
                    p.next = h2;
                    h2 = h2.next;
                }
                p = p.next;           
            }
            if(h1!=null)    p.next = h1;
            if(h2!=null)    p.next = h2;
    
            return head.next;     
        }
    }
    
    作者:cherry-n1
    链接:https://leetcode-cn.com/problems/sort-list/solution/pai-xu-lian-biao-di-gui-die-dai-xiang-jie-by-cherr/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    解答三:快速排序

    public class SingleListQuickSort {
      static class Node
      {
        public int key;
        public Node next;
        public Node(int k) {
          key = k;
          next = null;
        }
        public Node(int k, Node node) {
          key = k;
          next = node;
        }
        }
        Node partition(Node begin, Node end)
        {
            if(begin == end)
                return begin;
            int key = begin.key;
            Node pNode = begin;
            Node qNode = begin.next;
            while(qNode != end)
            {
                if(qNode.key < key)
                {
                    pNode = pNode.next;
                    int tempKey = pNode.key;
                    pNode.key = qNode.key;
                    qNode.key = tempKey;
                }
                qNode = qNode.next;
            }
            int temp = begin.key;
            begin.key = pNode.key;
            pNode.key = temp;
            return pNode;
        }
        void quickSort(Node head, Node end)
        {
            if(head != end)
            {
                Node pNode = partition(head, end);
                quickSort(head, pNode);
                quickSort(pNode.next, end);
            }
        }
        void printSingleList(Node head)
        {
            while(head != null)
            {
                System.out.println(head.key);
                head = head.next;
            }
        }
        public static void main(String[] args) {
            Node head = new Node(4);
            Node node = new Node(2);
            Node node2 = new Node(5);
            Node node3 = new Node(3);
            Node node4 = new Node(7);
            Node node5 = new Node(9);
            Node node6 = new Node(0);
            Node node7 = new Node(1);
            head.next = node;
            node.next = node2;
            node2.next = node3;
            node3.next = node4;
            node4.next = node5;
            node5.next = node6;
            node6.next = node7;
            SingleListQuickSort singleListQuickSort = new SingleListQuickSort();
            singleListQuickSort.quickSort(head, null);
            singleListQuickSort.printSingleList(head);
        }
    }
     
     
     
     
     
     
     
    另附对数组归并排序的代码:
    import java.util.Arrays;
    
    public class MergeSort {
    
        public static void main(String[] args) {
             int[] arr = new int[]{4,1,3,2,7,5,8,0,100};
            System.out.println("排序前:"+Arrays.toString(arr));
    
            int[] resultArr=  mergeSort(arr);
            System.out.println("排序后:"+Arrays.toString(resultArr));
    
        }
    
        /**
         * 归并排序
         * @param arr
         * @return
         */
        private static int[] mergeSort(int[] arr) {
            int arrLength;
            if(arr==null || (arrLength=arr.length)<2 ){
                return arr;
            }
    
            int halfSize = arrLength/2;
    
            int[] left = Arrays.copyOfRange(arr,0,halfSize);
            int[] right = Arrays.copyOfRange(arr,halfSize,arrLength);
    
           return merge(mergeSort(left),mergeSort(right));
    
        }
    
        /**
         * 对两个已经排好序的子数组进行合并排序
         * @param mergeSortLeft
         * @param mergeSortRight
         * @return
         */
        private static int[] merge(int[] mergeSortLeft, int[] mergeSortRight) {
            checkArgs(mergeSortLeft,mergeSortRight);
            int[] results = new int[mergeSortLeft.length+mergeSortRight.length];//非空判断
            int m=0;//指向left的索引
            int n=0;//指向right的索引
            for (int i = 0; i < results.length; i++) {
                if(m>=mergeSortLeft.length){
                    results[i]=mergeSortRight[n];//
                    n++;
                }else if(n>=mergeSortRight.length){
                    results[i]=mergeSortLeft[m];//
                    m++;
                }else if(mergeSortLeft[m]<=mergeSortRight[n]){
                    results[i]=mergeSortLeft[m];//
                    m++;
                }else if(mergeSortLeft[m]>mergeSortRight[n]){
                    results[i]=mergeSortRight[n];//
                    n++;
                }
            }
            return results;
    
    
        }
    
        private static int[] checkArgs(int[] mergeSortLeft, int[] mergeSortRight) {
            int[] result = null;
    //        if (mergeSortLeft==null || mergeSortLeft.length==0){
    //            if(mergeSortRight==null || mergeSortRight.length==0){
    //                result= null;
    //            }else {
    //                result=mergeSortRight;
    //            }
    //        }
            return result;
        }
    
    
    }
     
     
     
     
     另附对数组快速排序的代码:
    import java.util.Arrays;
    
    public class QuickSortArray1 {
    
        public static void main(String[] args) {
            int[] arr = {8, 1, 3, 2, 7, 6, 4};
            quickSort(arr, 0, arr.length - 1);
    
            System.out.println(Arrays.toString(arr));
    
    
        }
    
        private static void quickSort(int[] arr, int start, int end) {
            if (arr == null || arr.length <= 1 || start < 0 || end >= arr.length || start >= end || end < 0) {
                return;
            }
            int mid = partion(arr, start, end);
            quickSort(arr, start, mid - 1);
            quickSort(arr, mid + 1, end);
    
        }
    
        private static int partion(int[] arr, int start, int end) {
            int key = arr[end];
            int left = start - 1;
            for (int i = start; i <= end; i++) {
                if (arr[i] <= key) {
                    left++;
                    if (i > left) {
                        int tmp = arr[left];
                        arr[left] = arr[i];
                        arr[i] = tmp;
                    }
                }
            }
            return left;
        }
    
    }
     
     
     
  • 相关阅读:
    studyframe项目总结
    js三级联动
    ajax提交,获取后台数据
    密码验证
    产生验证码
    使用泛型 ,做计算器
    web前端,css
    VS快捷键
    我的未来编码规范
    如何将CAJ文档转化为doc文档
  • 原文地址:https://www.cnblogs.com/xuwc/p/13951176.html
Copyright © 2020-2023  润新知