【LeetCode】对链表进行插入排序

118 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第22天,点击查看活动详情

对链表进行插入排序

原题:leetcode-cn.com/problems/in…

描述

从第一个元素开始,该链表可以被认为已经部分排序。每次迭代时,从输入数据中移除一个元素,并原地将其插入到已排好序的链表中。 插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

难度

中等

示例

输入: 4->2->1->3
输出: 1->2->3->4
输入: -1->5->3->4->0
输出: -1->0->3->4->5

思路

根据插入排序算法,将待插入的元素和左边有序序列依次从后往前比较,但是链表不能从后向前移动,所以这里选择从头节点向后移动依次比较。

遍历链表,将当前节点 current 的下一个节点 next 依次和之前的所有节点比较,找到合适的插入位置,在插入前,先将当前节点 current 的下一个节点指向 next 的下一个节点,然后再插入节点,继续下一次循环。如果比较节点时没有发生插入,将 current 后移一个节点。

代码

Go

type ListNode struct {
    Val int
    Next *ListNode
}
​
func insertionSortList(head *ListNode) *ListNode {
    newHead := &ListNode{Val: math.MinInt32}
    newHead.Next = head
    current := newHead
    for current != nil && current.Next != nil {
        // 用来插入的节点
        next := current.Next
        temp := newHead
        // 从头节点开始循环到 next 的前一个节点
        for temp != next {
            // 将用来插入节点一次和每个节点比较
            if next.Val < temp.Next.Val {
                // 在节点插入到有序的子链表前, 先将 current 节点指向用来插入的节点的下一个节点
                current.Next = next.Next
​
                // 将节点插入到合适位置
                next.Next = temp.Next
                temp.Next = next
                break
            }
            temp = temp.Next
        }
        // 表示没有节点插入, 继续从下一个节点开始走
        // 如果有节点插入, current 节点已经正确指向了下一个节点
        if temp == next {
            current = current.Next
        }
    }
    return newHead.Next
}
​
func printListNode(node *ListNode) {
    var str = ""
    for node != nil {
        str += fmt.Sprintf("%d->", node.Val)
        node = node.Next
    }
    str = strings.TrimSuffix(str, "->")
    fmt.Println(str)
}
func TestInsertionSortList(t *testing.T) {
    node1 := &ListNode{Val: 4}
    node2 := &ListNode{Val: 2}
    node3 := &ListNode{Val: 1}
    node4 := &ListNode{Val: 3}
    node1.Next = node2
    node2.Next = node3
    node3.Next = node4
​
    printListNode(node1)
​
    node := insertionSortList(node1)
​
    printListNode(node)
​
    node1 = &ListNode{Val: -1}
    node2 = &ListNode{Val: 5}
    node3 = &ListNode{Val: 3}
    node4 = &ListNode{Val: 4}
    node5 := &ListNode{Val: 0}
    node1.Next = node2
    node2.Next = node3
    node3.Next = node4
    node4.Next = node5
​
    printListNode(node1)
​
    node = insertionSortList(node1)
​
    printListNode(node)
}

运行结果:

4->2->1->3
1->2->3->4
-1->5->3->4->0
-1->0->3->4->5

Java

public class Main {
    
    public static class ListNode {
        public int val;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
​
    public static ListNode insertionSortList(ListNode head) {
        ListNode newHead = new ListNode(Integer.MIN_VALUE);
        newHead.next = head;
        ListNode current = newHead;
        while (current != null && current.next != null) {
            // 用来插入的节点
            ListNode next = current.next;
            ListNode temp = newHead;
            // 从头节点开始循环到 next 的前一个节点
            while (temp != next) {
                // 将用来插入节点一次和每个节点比较
                if (next.val < temp.next.val) {
                    // 在节点插入到有序的子链表前, 先将 current 节点指向用来插入的节点的下一个节点
                    current.next = next.next;
​
                    // 将节点插入到合适位置
                    next.next = temp.next;
                    temp.next = next;
                    break;
                }
                temp = temp.next;
            }
            // 表示没有节点插入, 继续从下一个节点开始走
            // 如果有节点插入, current 节点已经正确指向了下一个节点
            if (temp == next) {
                current = current.next;
            }
        }
        return newHead.next;
    }
​
    private static void printListNode(ListNode node) {
        StringBuilder sb = new StringBuilder();
        while (node != null) {
            sb.append(node.val).append("->");
            node = node.next;
        }
        sb.deleteCharAt(sb.length() - 1);
        sb.deleteCharAt(sb.length() - 1);
        System.out.println(sb.toString());
    }
​
    public static void main(String[] args) {
        ListNode node1 = new ListNode(4);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(1);
        ListNode node4 = new ListNode(3);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
​
        printListNode(node1);
​
        ListNode node = insertionSortList(node1);
​
        printListNode(node);
​
        node1 = new ListNode(-1);
        node2 = new ListNode(5);
        node3 = new ListNode(3);
        node4 = new ListNode(4);
        ListNode node5 = new ListNode(0);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
​
        printListNode(node1);
​
        node = insertionSortList(node1);
​
        printListNode(node);
    }
}

运行结果:

4->2->1->3
1->2->3->4
-1->5->3->4->0
-1->0->3->4->5