链表
今天重温了下链表知识。链表是一种链式存储法,链表中的顺序是对象中指针所决定的,因此链表中相邻的元素在存储空间内不一定相邻,但插入删除操作相对数组方便。下面简单介绍一下双向链表:
如图所示,双链表L的每个元素都是一个对象,每个对象包含一个关键字域和两个指针域:next和prev。next[x]指向链表中x的后继元素,prev[x]指向链表x的前驱元素。如果prev[x]=NIL,则元素x没有前驱结点,即他是链表的第一个元素,也就是头(head)。如果next[x]=NIL,则元素x没有后继结点,即他是链表的最后一个元素,也就是尾(tail)。
属性head[L]指向表的第一个元素。如果head[L]=NIL,则该链表为空。****(注意:head[L]只是一个指向表头的指针,并不具有和结点一样的存储结构,例如下图中的head[L]就代表该链表存储9的结点。)
下面简单介绍双向链表的几种常用操作:
1、搜索
2、插入
3、删除
1、搜索
查找出链表L中第一个具有关键字k的元素,并返回该指针,如果没有,则返回NIL
LIST-SEARCH(L,k)
x=head[L]
while x不等于NIL且key[x]不等于k
do x=next[x]
return x
2、插入
给定一个已设置了关键字的新元素x,将其插入到链表的最前端,如上图b所示。
LIST-INSERT(L,x)
next[x]=head[L]
if head[L]不等于NIL
then prev[next[x]]=x
head[L]=x
prev[x]=NIL
3、删除
删除元素x
LIST-DELETE(L,x)
if prev[x]不等于NIL
then next[prev[x]]=next[x]
else head[L]=next[x]
if next[x]不等于NIL
then prev[next[x]]=prev[x]
哨兵 哑结点
对于插入和删除操作,如果忽视表头和表尾的边界条件,则代码会更简单。
例如:
List-Delete‘(L,x)
next[prev[x]]=next[x]
prev[next[x]]=prev[x]
哨兵是一个哑对象,可以简化边界条件。哑结点nil[L] 是一个空结点,但是包含和其他元素一样的各个域(不同于head[L],head[L]只是一个指针,而哑结点包含prev key 和next)。引入哑结点,可以将一个一般的双向链表转变成一个带哨兵的双向环形链表,如下图所示。
域next[nil[L]]指向链表头(第一个结点),而prev[nil[L]]指向表尾。同样的,表头的prev和表尾的next都指向nil[L]。因next[nil[L]]指向表头,因此可以去掉head[L]。
一个空链表仅含哨兵元素,此时next[prev[nil[L]]]和prev[next[nil[L]]]都指向nil[L]。
此时,插入的代码可以简化为:
List-Insert’(L,x)
next[x]=next[nil[L]]
prev[next[x]]=x
next[nil[L]=x]
prev[x]=nil[L]
(Delete见上,Search和原来差不多)
(参考《算法导论》10.2)
LeetCode142环形链表
思路一:
参考龟兔赛跑的思想:乌龟和兔子从同一起点出发,一个快,一个慢,如果在环形路上跑,则龟和兔始终会相遇,且此时兔子比乌龟多走了一个环的距离。因此,判断一个链表是否有环,可设置一个快指针一个慢指针,如果两个指针相遇,则有环。具体参看以下思路:
渣渣小白看到这里表示非常巧妙了,不由得鼓起小掌来~~
步骤:
1、设置一个快指针(fast)和一个慢指针(slow),fast步长为2,slow为1,若有环,则fast和slow迟早会相遇。
2、若fast==slow,则说明有环,进入第3步,否则,返回none。
3、设置一个新指针p,当p与slow相遇时,即为入口点。
代码:
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
//第一步 判断是否有环
fast=head
slow=head
hasCycle=false
while(fast.next.next!=None)&(slow.next!=None):
fast=fast.next.next
slow=slow.next
if(fast==slow):
hasCyle=true
break
//第二步 若有环,找到环开始结点
if(hasCycle):
p=head
while(p!=slow):
p=p.next
slow=slow.next
return p
else:
return none
结果:
LeetCode206 反转字符串
思路:
新建一个链表,然后遍历旧链表,每遍历出来一个,就插入到新链表的表头中,那么这个新链表就是反转过来的了。
代码:
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
first = head
newhead = None
while first!=None:
second = first.next
first.next = newhead
newhead = first
first = second
return newhead
执行结果:
(PS:在这里要感谢可爱的Deng童鞋~~)