1, 无序链表(Unordered linked list)
链表是有若干个数据节点依次链接成的数据结构,如下图所示,每一个数据节点包括包括数据和一个指向下一节点的指针。(python中的list就是由链表来实现的)
无序链表操作:
Llist = UnorderedList() #创建无序链表
add(item) #向链表中加入item(首部加入)
remove(item) #从链表中移除item
search(item) #从链表中搜索item
pop() #从链表末尾移除节点
append() #从链表末尾加入节点
pop(pos) #从链表指定位置移除节点
insert(pos, item) #从链表指定位置加入节点
index(item) #返回item在链表中的位置
size() #返回链表大小
isEmpty() #返回链表是否为空
python实现无序链表
定义了Node类和UnorderedList类,代码如下:
#coding:utf-8
classNode(object):def __init__(self,data):
self.data=data
self.next=NonedefgetData(self):returnself.datadefgetNext(self):returnself.nextdefsetData(self,newData):
self.data=newDatadefsetNext(self,newNext):
self.next=newNextclassUnorderedList(object):def __init__(self):
self.head=Nonedefadd(self,item):
temp=Node(item)
temp.setNext(self.head)
self.head=tempdefremove(self,item): #未考虑item不存在链表中的情况,考虑时参见下面有序列表中remove方法
previous=None
current=self.head
found=Falseifcurrent:while notfound:if current.getData()==item:
found=Trueelse:
previous=current
current=current.getNext()if previous==None:
self.head=current.getNext()else:
previous.setNext(current.getNext())returnfounddefsearch(self,item):
current=self.head
found=Falsewhile current!=None and (notfound):if current.getData()==item:
found=Truereturncurrentelse:
current=current.getNext()returnfounddefpop(self):
previous=None
current=self.headifcurrent:while current.getNext()!=None:
previous=current
current=current.getNext()if previous==None:
self.head=Noneelse:
previous.setNext(None)else:raise IndexError("pop from empty unorderedList")returncurrent.getData()defappend(self,item):
temp=Node(item)
current=self.head
previous=Nonewhile current!=None:
previous=current
current=current.getNext()if previous==None:
self.head=tempelse:
previous.setNext(temp)defindex(self,item):
count=0
current=self.headwhile current and (current.getData()!=item):
count= count+1current=current.getNext()if count and (count
count=0
current=self.headwhile current!=None:
count+= 1current=current.getNext()returncountdefisEmpty(self):return self.head==None
u=UnorderedList()
u.append(3)
u.append(2)
u.append(6)#print u.index(6), u.index(7)
printu.size(),u.pop()printu.size(),u.pop()print u.size(),u.pop()
链表排序
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(5,ListNode(9,ListNode(7,ListNode(10,ListNode(12)))))
利用归并排序对链表排序
def sort_list(head):if head==None or head.next==None:returnhead
left=head
mid=get_mid(head)
right=mid.next
mid.next=Nonereturnmerge(sort_list(left),sort_list(right))
def merge(left, right):
node= ListNode(0)
temp=nodewhileleft and right:if left.data>=right.data:
temp.next=right
right=right.nextelse:
temp.next=left
left=left.next
temp=temp.nextifleft:
temp.next=leftifright:
temp.next=rightreturnnode.next
def get_mid(node):if node==None:returnnode
slow=node
fast=nodewhilefast.next and fast.next.next:
slow=slow.next
fast=fast.next.nextreturnslow
l1.traverse()
sort_list(l1)
l1.traverse()
print("*"*20)
l2.traverse()
sort_list(l2)
l2.traverse()
归并排序
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(5,ListNode(9,ListNode(7,ListNode(10,ListNode(12)))))
#利用堆来排序
def sort_list2(head):if head==None:returnhead
temp=head
import heapq
hq=[]whiletemp:
heapq.heappush(hq,temp.data)
temp=temp.next
head=ListNode(heapq.heappop(hq))
prev=headwhilehq:
current=ListNode(heapq.heappop(hq))
prev.next=current
prev=prev.next
l1.traverse()
sort_list2(l1)
l1.traverse()
print("*"*20)
l2.traverse()
sort_list2(l2)
l2.traverse()
堆排序
链表倒转
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(5,ListNode(9,ListNode(7,ListNode(10,ListNode(12)))))
def reverse(head):
prev=head
cur=head.next
prev.next=Nonewhilecur:
temp=cur.next
cur.next=prev
prev=cur
cur=tempreturnprev
l1.traverse()
r=reverse(l1)
print("="*30)
r.traverse()
单链表倒转
#链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
def reverse(head):
prev=head
cur=head.next
prev.next=Nonewhilecur:
temp=cur.next
cur.next=prev
prev=cur
cur=tempreturnprev,head
def reverse_linkedlist(head,k):
temp=headfor i in range(k-1):
temp=temp.nextif temp==None:returnNone
mid=temp.next
temp.next=None
head1,end1=reverse(head)
head2,end2=reverse(mid)
end1.next=head2returnhead1
l2= reverse_linkedlist(l1,3)
l2.traverse()
复杂链表倒转
判断链表是否有环,并返回环入口点,计算环长度
(1)题目描述:输入一个单向链表,判断链表是否有环?
分析:通过两个指针,分别从链表的头节点出发,一个每次向后移动一步,另一个移动两步,两个指针移动速度不一样,如果存在环,那么两个指针一定会在环里相遇。
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(31,ListNode(26,ListNode(18,ListNode(32))))
#在链表中构造环路
def cycle_list(l1):
first=l1
temp=firstfor i in range(3): #向后移动三次,即将20作为入环节点
temp=temp.nextwhilefirst.next:
first=first.next
first.next=tempreturnl1
l3=cycle_list(l1)
#l3.traverse()
#检查是否存在环路
def check_cycle(head):
slow= fast =headwhile fast!=None and fast.next!=None:
fast=fast.next.next
slow=slow.nextif slow isfast:returnTruereturnFalse
print(check_cycle(l2)) #False
print(check_cycle(l3)) #True
判断是否有环
(2)题目描述:输入一个单向链表,判断链表是否有环。如果链表存在环,如何找到环的入口点?
解题思路: 由上题可知,按照 p2 每次两步,p1 每次一步的方式走,发现 p2 和 p1 重合,确定了单向链表有环路了。接下来,让p2回到链表的头部,重新走,每次步长不是走2了,而是走1,那么当 p1 和 p2 再次相遇的时候,就是环路的入口了。
为什么?:假定起点到环入口点的距离为 a,p1 和 p2 的相交点M与环入口点的距离为b,环路的周长为L,当 p1 和 p2 第一次相遇的时候,假定 p1 走了 n 步。那么有:
p1走的路径: a+b = n;
p2走的路径: a+b+k*L = 2*n; p2 比 p1 多走了k圈环路,总路程是p1的2倍
根据上述公式可以得到 k*L=a+b=n显然,如果从相遇点M开始,p1 再走 n 步的话,还可以再回到相遇点,同时p2从头开始走的话,经过n步,也会达到相遇点M。显然在这个步骤当中 p1 和 p2 只有前 a 步走的路径不同,所以当 p1 和 p2 再次重合的时候,必然是在链表的环路入口点上。因为p1和p2点同时到达相遇点M,若都往后倒退b步则为环入口点,则第一次重合点必然是环路入口点。
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(31,ListNode(26,ListNode(18,ListNode(32))))
#在链表中构造环路
def cycle_list(l1):
first=l1
temp=firstfor i in range(3): #向后移动三次,即将20作为入环节点
temp=temp.nextwhilefirst.next:
first=first.next
first.next=tempreturnl1
l3=cycle_list(l1)
#l3.traverse()
#返回入环点
def check_cycle_entrance(head):
slow= fast =head
found_cycle=Falsewhile fast!=None and fast.next!=None and not found_cycle:
fast=fast.next.next
slow=slow.nextif slow isfast: #链表有环路
found_cycle=Trueiffound_cycle:
fast=head #快指针从头结点开始,一次走一步while fast!=slow:
fast=fast.next
slow=slow.nextreturnfastelse:returnNone
cycle_node=check_cycle_entrance(l3)
print(cycle_node.data)
cycle_node=check_cycle_entrance(l2)
print(cycle_node)
返回入环点
(3)题目描述:输入一个单向链表,判断链表是否有环。如果链表存在环,计算环的长度?
解题思路: 由上题可知,按照 p2 每次两步,p1 每次一步的方式走,发现 p2 和 p1 重合,确定了单向链表有环路了。接下来,从相遇点继续走,那么当 p1 和 p2 再次相遇的时候,p1走过的长度即为环长度。
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(31,ListNode(26,ListNode(18,ListNode(32))))
#在链表中构造环路
def cycle_list(l1):
first=l1
temp=firstfor i in range(3): #向后移动三次,即将20作为入环节点
temp=temp.nextwhilefirst.next:
first=first.next
first.next=tempreturnl1
l3=cycle_list(l1)
#l3.traverse()
#计算环路长度
def count_cycle_length(head):
slow= fast =head
found_cycle=Falsewhile fast!=None and fast.next!=None and not found_cycle:
fast=fast.next.next
slow=slow.nextif slow isfast: #链表有环路
found_cycle=Trueiffound_cycle:
count= 1fast=fast.next.next
slow=slow.nextwhile fast!=slow: #第二次相遇
fast=fast.next.next
slow=slow.next
count= count+1
returncountelse:returnNone
cycle_length=count_cycle_length(l3)
print(cycle_length)
计算环长度
(4)题目描述:输入一个单向链表,判断链表是否有环。如果链表存在环,计算链表长度?
解题思路:计算出第(2)题中a和第(3)题中的环路长,两者之和即为链表长度
判断链表的公共交点
题目描述:给出两个单向链表的头指针(如下图所示),求链表的交点
解题思路:求出两链表的长度,长链表先走,然后逐个比较两个链表的值,第一个相等的值即为交点。(若只要判断是否相交,只需判断尾节点是否相等)
class ListNode(object):
def __init__(self,data,next=None):
self.data=data
self.next=next
def traverse(self):
temp=selfwhile temp!=None:
print temp.data
temp=temp.next
l1= ListNode(1,ListNode(56,ListNode(8,ListNode(20,ListNode(10,ListNode(12))))))
l2= ListNode(31,ListNode(25,ListNode(10,ListNode(12))))
#判断链表交点
def linkedlist_node(l1,l2):
head1=l1
head2=l2
length1=length2=0
whilehead1:
length1= length1+1head1=head1.nextwhilehead2:
length2= length2+1head2=head2.nextif length1>length2: #长链表先走for i in range(length1-length2):
l1=l1.nextelse:for i in range(length2-length1):
l2=l2.nextwhile l1!=None and l2!=None:if l1.data = l2.data: #应该是l1==l2(或l1 isl2),这里使用值代替了,方便看执行结果returnl1.data
l1=l1.next
l2=l2.nextreturnNone
print(linkedlist_node(l1,l2))
链表交点
2,有序列表(Ordered List)
有序列表和无序列表结构相同,只是列表中的数据按顺序排列(升序或降序),其常用操作也基本相同。
常用操作
Llist =OrderedList()
add(item)
remove(item)
search(item)
pop()
pop(pos)
index(item)
size()
isEmpty()
python 实现有序列表
pop(), index(item), size()和isEmpty()方法和UnorderedList相同,add(item), search(item)和remove(item)代码如下所示:
classOrderedList(object):def __init__(self):
self.head=Nonedefadd(self,item):
previous=None
current=self.headwhile current and (item >current.getData()):
previous=current
current=current.getNext()
temp=Node(item)if previous ==None:
temp.setNext(self.head)
self.head=tempelse:
previous.setNext(temp)
temp.setNext(current)defsearch(self,item):
current=self.head
found=False
stop=Falsewhile current!=None and (not found) and (notstop):if current.getNext()==item:
found=Trueelse:if current.getData()
current=current.getNext()else:
stop=Truereturnfounddefremove(self,item):
previous=None
current=self.headwhile current and (item!=current.getData()):
previous=current
current=current.getNext()if current!=None:if previous ==None:
self.head=current.getNext()else:
previous.setNext(current.getNext())else: #self.head=None或者item不存在链表中
raise ValueError('%s item is not in the OrderedList'%item)