Linked List 介绍
资料来源《程序员面试金典》第九章
链表是由一些列节点(node)组成的数据结构,每个节点拥有指向下一个节点的指针(双向链表中,每一个节点同时拥有指向上一个节点和下一个节点的指针)。
单链表:
双链表:
链表的好处是可以在常数的时间添加和删除元素,在特定的情况下特别有用。和数组不同的是,链表无法在常数时间复杂度内访问链表的一个特定索引,如果想要访问第N个元素,就需要迭代访问N次。
Node数据结构
1 | public class Node<T>{ |
LinkedList数据结构
1 | public class LinkedList<T>{ |
Linked List 习题
例题1
《程序员面试金典》第九章2.4
编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。
示例:
1 | 输入: head = 3->5->8->5->10->2->1, x = 5 |
思路
使用头插法,将碰到的小于x的节点直接插入到链表头的前面
1 | public ListNode Partition(ListNode head, int x) { |
例题2
《程序员面试金典》第九章2.8
给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。
有环链表的定义:在链表中某个节点的next元素指向在它前面出现过的节点,则表明该链表存在环路。
示例 1:
1 | 输入:head = [3,2,0,-4], pos = 1 |
示例 2:
1 | 输入:head = [1,2], pos = 0 |
示例 3:
1 | 输入:head = [1], pos = -1 |
思路
使用“快行指针”进行求解,假设一个慢指针一次走一步,一个快指针一次走两步,如果链表有环,那么快指针和慢指针肯定会相遇。
- x: 链表起点
- y: 环的起点
- A: 链表起点到环的起点的长度
- B: 环的起点到两个指针相遇的位置的长度
到相遇点为止,慢指针走过了距离 s1 = A + B, 快指针走过了 s2 = A + B + N * (环路长度), 也就是说快指针走了N圈和慢指针相遇了。又因为快指针一次走两步,慢指针一次走一步,所以快指针走过的距离s2是慢指针走过的距离s1的两倍:2*s1 = s2,得到 2( A + B ) = A + B + N * (环路长度)。我们需要求 y 的位置,也就是计算A的长度。简化得到 A = N * (环路长度) - B
1 | public ListNode DetectCycle(ListNode head) |