链表的一些常用操作

链表结构定义

以下的操作都是基于这种结构的。

// Definition for singly-linked list.
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) {
        this.val = val; this.next = next;
    }
}

求链表长度

// ListNode root表示链表的第一个结点
ListNode p = root;
int length = 0;
while (p != null) {
    p = p.next;
    length++;
}

逆置链表

逆置操作是使用非常多的操作,下面是头插法逆置链表的操作。必须熟练掌握

public ListNode reverseList(ListNode head) {
    ListNode newHead = new ListNode();
    while (head != null) {
        ListNode next = head.next;
        head.next = newHead.next;
        newHead.next = head;
        head = next;
    }
    return newHead.next;
}

判断两个链表是否相等

1. 要求值相等并且长度相等。这是最常见的方法

public boolean isEqual(ListNode l1, ListNode l2) {
    while (l1 != null && l2 != null) {
        if (l1.val != l2.val) {
            return false;
        }
    }

    return l1 == l2;
}

2. 要求值相等,但是两个链表的长度相差为1。这个判断方法在判断链表是否是回文链表时会用到

public boolean isEqual(ListNode l1, ListNode l2) {
    while (l1 != null && l2 != null) {
        if (l1.val != l2.val) {
            return false;
        }
    }

    return true;
}

可以看出,两者只有最后返回语句的差别。

找链表的中间节点

当链表的个数为偶数个时,将中间两个元素中索引较大的那一个认为是中间元素,比如1-2-3-4,将3所在节点认为是中间节点。

public ListNode findMidNode(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }

    ListNode slow = head;
    ListNode fast = head.next;

    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
}