概念介绍
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
以“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。
结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域–存放结点值的数据域
next域–存放结点的直接后继的地址(位置)的指针域(链域)
链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表(Single Linked List)。
头指针head和终端结点
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
单链表
每个结点只有一个链域的链表称为单链表(Single Linked List)。
leetcode
142.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
- 解法一:
用集合保存循环过的节点,每次访问一个节点首先都判断集合中是否存在同一个节点,如果存在则链表存在环,否则持续加入到集合中。当指针遍历到NULL的时候仍然没有找到环,证明链表不存在环。
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
#
class Solution(object):
def detectCycle(self, head):
nodeList = set()
while head:
if head in nodeList:
return head
nodeList.add(head)
head = head.next
return None
- 解法二:
分为三步:
- 首先判断是否存在环,利用快慢指针法,从头节点开始快指针每次走两步,慢指针每次走一步,如果存在环则两指针必定会相遇,如果没有再次相遇则不存在环
- 然后找到环中节点的个数,此时快指针已经处在环内,所以让其每次向前走一步,记录再次和慢指针相遇时走的步数即为环中节点个数
- 找环入口节点时还是利用快慢指针,从头节点开始先让快指针走环中节点个数的步数,然后快慢指针同时向前移动,这样相遇时快指针恰好比满指针多走了一个环的长度,即指向了环入口节点
class Solution(object):
def detectCycle(self, head):
p1, p2, cycleFlag = head, head, 0
while p2 and p2.next and p2.next.next:
p2 = p2.next.next
p1 = p1.next
if p1 == p2:
cycleFlag = 1
break
if cycleFlag == 0:
return None
while p2.next != p1:
p2 = p2.next
cycleFlag += 1
p1, p2 = head, head
while cycleFlag > 0:
p2 = p2.next
cycleFlag -= 1
while p2 != p1:
p2 = p2.next
p1 = p1.next
return p2
206.反转一个单链表。
- 解法一:利用三个指针逐个翻转
def func1(head):
p = head
q = head.next
p.next = None
while q:
r = q.next
q.next = p
p = q
q = r
return p
- 解法二:尾插法翻转
def func2(head):
p = head.next
while p.next:
q = p.next
p.next = q.next
head.next = q
q.next = p
p.next = head
head = head.next
p.next.next = None
return head
- 解法三:递归
def func3(head):
if head.next == None:
return head
new_head = func3(head.next)
head.next.next = head
head.next = None
return new_head