美文网首页
【D23】对链表进行插入排序 & 合并两个有序链表 &排序链表

【D23】对链表进行插入排序 & 合并两个有序链表 &排序链表

作者: sirenyunpan | 来源:发表于2021-03-04 21:03 被阅读0次

    今日主题:链表。

    147. 对链表进行插入排序

    问题描述

    对链表进行插入排序。

    解题思路

    • 添加虚拟头节点,保证对链表节点操作的一致性
    • 注意切断头节点与后续节点的指针,不然会形成环形链表

    代码实现

    /**
     * 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 insertionSortList(ListNode head) {
            if(head == null){
                return head;
            }
    
            //添加虚拟头节点,指向新的已排好序的链表
            ListNode dummyHead = new ListNode(0);
            //将头节点的值加入已排好序的链表;避免形成环形链表
            dummyHead.next = new ListNode(head.val);
    
            ListNode cur = head.next;
            while(cur != null){
                //temp保存当前节点的下一个节点
                ListNode temp = cur.next;
    
                //从头开始遍历已经排好序的链表,找到插入位置
                ListNode pre = dummyHead, index = dummyHead.next;;
                while(index != null && index != cur){
                    if(cur.val < index.val){
                        break;
                    }
                    pre = pre.next;
                    index = index.next;
                }
    
                //如果退出循环时,index==null,表示当前值比之前所有的值都大,不需要进行插入
                //index != null, 需要进行节点插入
                if(index != cur){
                    pre.next = cur;
                    cur.next = index;
                }
                cur = temp;   
            }
            return dummyHead.next;   
        } 
    }
    

    21. 合并两个有序链表

    问题描述

    将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

    解题思路

    应用归并排序合并数组的思想。

    代码实现

    /**
     * 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 mergeTwoLists(ListNode l1, ListNode l2) {
            ListNode head = new ListNode(0);
            ListNode tail = head;
    
            while(l1 != null && l2 != null){
                if(l1.val < l2.val){
                    tail.next = new ListNode(l1.val);
                    l1 = l1.next;
                }else {
                    tail.next = new ListNode(l2.val);
                    l2 = l2.next;
                }
                tail = tail.next;
            }
            // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
            tail.next = l1 == null ? l2 : l1;
            return head.next;
            
        }
    }
    

    148. 排序链表

    问题描述

    给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
    你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

    解题思路

    时间复杂度为O(n log n)的常见排序算法有:快排、堆排、归并。
    其中快排和堆排设计到的元素交换操作较多,而对单链表中的两个任意节点进行交换,操作比较复杂。正好,归并排序算法中合并左右有序数组的操作有用到双指针。因此,采用归并排序实现。

    代码实现

    /**
     * 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 = getMid(head);
            ListNode rightHead = mid .next;
            mid.next = null;
    
            //得到有序左、右子链表
            ListNode sortedLeft = sortList(head);
            ListNode sortRight = sortList(rightHead);
    
            //合并左右子链表
            return mergeTwoLists(sortedLeft,sortRight);
        }
    
        //采用快慢指针找到链表的中点(偶数节点返回偏左节点)
        public ListNode getMid(ListNode head){
            ListNode dummyHead = new ListNode(0,head);
            ListNode slow = dummyHead, fast = dummyHead;
            while(fast != null && fast.next != null){
                slow = slow.next;
                fast = fast.next.next;
            }
            return slow;
        }
    
        //合并两个有序链表
         public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            ListNode head = new ListNode(0);
            ListNode tail = head;
    
            while(l1 != null && l2 != null){
                if(l1.val < l2.val){
                    tail.next = new ListNode(l1.val);
                    l1 = l1.next;
                }else {
                    tail.next = new ListNode(l2.val);
                    l2 = l2.next;
                }
                tail = tail.next;
            }
            // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
            tail.next = l1 == null ? l2 : l1;
            return head.next;    
        }
    }
    

    相关文章

      网友评论

          本文标题:【D23】对链表进行插入排序 & 合并两个有序链表 &排序链表

          本文链接:https://www.haomeiwen.com/subject/irwkqltx.html