1
class ListNode {
    int val;
    ListNode next;
    public ListNode(int val) {
        this.val  = val;
    }
}

1、创建链表

(1)从头到尾建立

让当前指针 cur 指向链表的尾结点,每增加一个结点 p,都将 cur.next 指向 p, 并将当前指针 cur 前移至 p, 保证在插入新结点之前当前指针 cur 都指向链表的尾结点。
ListNode create(int[] vals) {
    ListNode result = new ListNode(-1);
    ListNode cur = result;
    for(int val: vals) {
        ListNode p = new ListNode(val);
        cur.next = p;
        cur = p;
    }
    return result.next;
}

(2)从尾到头建立

让当前指针 cur 指向链表头,每增加一个节点 p,都将 p.next 指向 cur.next,然后将 cur.next 指向 p,每次新增节点 p 插入的位置都是在头结点之后。
ListNode createReverse(int[] vals) {
    ListNode result = new ListNode(-1);
    for(int val: vals) {
        ListNode p = new ListNode(val);
        p.next = result.next;
        result.next = p;
    }
    return result.next;
}

2、链表逆序

(1)无头结点的链表

创建 next 为空的头结点,每次将要插入的节点从原链表中分离出来,插入新链表的头结点之后,要保证链表不断节。
ListNode reverse(ListNode list) {
    ListNode head = new ListNode(-1);
    while(list!=null) {
        ListNode q = list.next;
        list.next = head.next;
        head.next = list;
        list = q;
    }
    return head.next;
}

(2)带头结点的链表

将链表分成 next 为空的头结点和子链表两部分,每次将要插入的节点从子链表中分离出来,插入新链表的头结点之后,要保证链表不断节。
ListNode reverse(ListNode list) {
    ListNode p = list.next;
    list.next = null;
    while(p!=null) {
        ListNode q = p.next;
        p.next = list.next;
        list.next = p;
        list = q;
    }
}

(3)将无头结点的链表中第 m ~ n 个结点逆序

创建头结点,使其 next 指向链表;设置两个指针 cur, pre,分别指向当前结点及其前驱结点;遍历并统计结点个数,直到找到第 m 个结点 cur 为逆序起始结点,pre 为第 m-1 个结点;保存逆序起始结点,即第 m 个结点,逆序之后会成为第 n 个结点,以保证链表不断节;每次将逆序部分的结点从链表中分离出来,插到 pre 之后;最后将逆序起始结点的 next 指向第 n+1 个结点 cur。
ListNode reverseMN(ListNode list, int m, int n) {
    ListNode head = new ListNode(-1);
    head.next = list;
    int count = 0; // 结点个数,包括头结点
    ListNode cur = head, pre = cur; // cur 为逆序起始结点; pre 为 cur 的前驱结点
    for(; cur!=null && count < m; count++) {
        pre = cur;
        cur = cur.next;
    }
    ListNode last = cur; // 保存逆序起始结点
    for(; cur!=null && count<=n; count++) {
        ListNode p = cur.next;
        cur.next = pre.next;
        pre.next = cur;  // 每次都将结点插入到第 m-1 个结点之后
        cur = p;
    }
    last.next = cur; // cur 指向的是第 n+1 个结点
    return head.next;
}

(4)将带头结点的链表第 m~n 个结点逆序

设置两个指针 cur, pre 分别指向当前结点及其前驱结点,遍历链表并统计个数,直到找到第 m 个结点 cur 为逆序起始结点, pre 为第 m-1 个结点;保存逆序起始结点,以保证链表不断节;每次都将逆序部分的结点从链表中分离出来,插到 pre 之后;最后将逆序起始结点的 next 指向第 n+1 个结点 cur。
ListNode reverseMN(ListNode list, int m, int n) {
    ListNode cur = list, pre = list;
    int count = 0;
    for(; cur!=null && count
        pre = cur;
        cur = cur.next;
    }
    ListNode last = cur;
    for(; cur!=null && count<=n; count++) {
        ListNode temp = cur.next;
        cur.next = pre.next;
        pre.next = cur;
        cur = temp;
    }
    last.next = cur;
    return list;
}

3、插入排序

(1)无头结点的链表

创建一个头结点,使其 next 为空,作为新链表的头结点;每次将链表的首结点插入到新链表的正确位置:先保存剩余子链表,然后在新链表中从头查找,设置两个指针 cur, pre,分别指向当前结点及其前驱结点,直到找到一个结点的值大于待插入结点的值,即为插入的位置,再将结点插入该位置:将 pre 的 next 指向待插入结点,待插入结点的 next 指向原结点。
ListNode insertionSort(ListNode head) {
    ListNode result = new ListNode(-1);
    while(head!=null) {
        ListNode temp = head.next;
        ListNode cur = result.next, pre = result;
        while(cur!=null && head.val<cur.val) {
            pre = cur;
            cur = cur.next;
        }
        pre.next = head;
        head.next = cur;
        head = temp;
    }
    return result;
}

(2)带头结点的链表

将链表分离成头结点和子链表两部分,并将头结点的 next 设为空;每次都将子链表的首结点插到新链表的正确位置:先保存子链表的剩余部分,然后在新链表中从头查找,设置两个指针 cur, pre 分别指向新链表的当前结点及其前驱结点,直到找到一个结点的值大于首结点的值,即为插入的位置;再将结点插入该位置:将 pre 的 next 指向待插入结点,将待插入结点的 next 指向原结点。
ListNode insertionSort(ListNode list) {
    ListNode head = list.next;
    list.next = null;
    while(head!=null) {
        ListNode temp = head.next;
        ListNode cur = list.next, pre = list;
        while(cur!=null && head.val<cur.next) {
            pre = cur;
            cur = cur.next;
        }
        pre.next = head;
        head.next = cur;
        head = temp;
    }
    return list;
}

KitorinZero
7 声望1 粉丝

引用和评论

0 条评论