147. 對鏈表進(jìn)行插入排序

對鏈表進(jìn)行插入排序。

image

插入排序的動畫演示如上。從第一個元素開始,該鏈表可以被認(rèn)為已經(jīng)部分排序(用黑色表示)。
每次迭代時,從輸入數(shù)據(jù)中移除一個元素(用紅色表示),并原地將其插入到已排好序的鏈表中。

插入排序算法:

  1. 插入排序是迭代的,每次只移動一個元素,直到所有元素可以形成一個有序的輸出列表。
  2. 每次迭代中,插入排序只從輸入數(shù)據(jù)中移除一個待排序的元素,找到它在序列中適當(dāng)?shù)奈恢?,并將其插入?/li>
  3. 重復(fù)直到所有輸入數(shù)據(jù)插入完為止。

示例 1:

輸入: 4->2->1->3
輸出: 1->2->3->4

示例 2:

輸入: -1->5->3->4->0
輸出: -1->0->3->4->5

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode insertionSortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        
        // 插入排序是迭代的,每次只移動一個元素,直到所有元素可以形成一個有序的輸出列表。
        // 每次迭代中,插入排序只從輸入數(shù)據(jù)中移除一個待排序的元素,找到它在序列中適當(dāng)?shù)奈恢?,并將其插入?        // 每次迭代完成,從插入元素為止,該鏈表可以被認(rèn)為已經(jīng)部分排序
        // 重復(fù)直到所有輸入數(shù)據(jù)插入完為止
        
         // 1.遍歷并與前面已經(jīng)有序的序列向前逐一比較排序,找到合適為止插入
        
        // 定義三個指針 pre, cur, lat
        //pre    cur    lat
        // h  ->  4  ->  2  ->  5  ->  3  ->  null
        
        // 創(chuàng)建 h 節(jié)點,用于遍歷鏈表
        ListNode h = new ListNode(-1);
        h.next = head;
        ListNode pre = h;
        ListNode cur = head;
        ListNode lat;
        
        while (cur != null) {
            lat = cur.next; // 記錄下一個要插入排序的值
            
            if (lat != null && lat.val < cur.val) { // 只有 cur.next 比 cur 小才需要向前尋找插入點
                // 尋找插入點,從 pre 開始遍歷 (每次都是頭節(jié)點 h 開始向后遍歷,因為單向鏈表是無法從后往前遍)
                while (pre.next != null && pre.next.val < lat.val) { // 如果當(dāng)前節(jié)點的值小于要插入排序的值
                    pre = pre.next; // 繼續(xù)向后移動
                }
                
                // 找到要插入的位置,此時 pre 節(jié)點后面的位置就是 lat 要插入的位置
                // 交換 pre 跟 lat 節(jié)點需要一個 temp 節(jié)點來臨時保存下插入位置 node 后 next
                ListNode tmp = pre.next;
                // 在 pre 節(jié)點后面插入
                pre.next = lat;
                // 此時 cur 節(jié)點還是 pre 所在的節(jié)點,所以其 next 要指向插入節(jié)點 lat 指向的 next
                cur.next = lat.next;
                // 插入let節(jié)點后,把記錄的原先插入位置后續(xù)的 next 節(jié)點傳給它
                lat.next = tmp;
                // 由于每次都是從前往后找插入位置,但是單向鏈表是無法從后往前遍歷,所以需要每次插入完成后要讓 pre 復(fù)位
                pre = h;
            } else {
                // 都這直接把 cur 指針指向到下一個
                cur = lat;
            }
        }
        
       return h.next;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容