链表的难点是:操作列表的结点指针的能力
快慢指针找中点
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
/*这个if是为了获得纯后半段的起始结点,不包括链表的中心点,只对链表个数是奇数的起作用。*/
if(fast != null){//fast != null 说明链表个数是奇数的,此时low指向链表的中心点,需要再走一步才能指向后半段的起始结点
low = low.next;
}
反转链表
两个指针pre,cur,pre是已经反转的头结点,初始结点是null,cur是将要反转的结点,初始结点是head。
反转:cur的后继变为pre
条件:首先保存cur现有的后继,记为tmp
while的判断条件是cur不为空
- 保存好cur的后继
- cur指向pre
- 更新pre,cur
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
随机访问链表结点
链表的缺点就是不能随机存储,当我们想取末尾元素的时候,只能从头遍历一遍,很耗费时间。第二次取末尾元素的时候,又得遍历一遍。
所以先来个简单粗暴的想法,把链表存储到线性表中,然后用双指针依次从头尾取元素即可。
数组,链表,双端队列都可以使操作结点方便很多。
List<ListNode> list = new ArrayList<>();
while (head != null) {
list.add(head);
head = head.next;
}