数据结构之链表(Linked list)
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 class Node(object): def __init__(self,data): self.data = data self.next = None def getData(self): return self.data def getNext(self): return self.next def setData(self,newData): self.data=newData def setNext(self,newNext): self.next = newNext class UnorderedList(object): def __init__(self): self.head=None def add(self,item): temp = Node(item) temp.setNext(self.head) self.head=temp def remove(self,item): #未考虑item不存在链表中的情况,考虑时参见下面有序列表中remove方法 previous = None current = self.head found = False if current: while not found: if current.getData()==item: found = True else: previous = current current = current.getNext() if previous==None: self.head = current.getNext() else: previous.setNext(current.getNext()) return found def search(self,item): current = self.head found = False while current!=None and (not found): if current.getData()==item: found = True return current else: current = current.getNext() return found def pop(self): previous = None current = self.head if current: while current.getNext()!=None: previous = current current = current.getNext() if previous==None: self.head=None else: previous.setNext(None) else: raise IndexError("pop from empty unorderedList") return current.getData() def append(self,item): temp = Node(item) current = self.head previous = None while current!=None: previous = current current = current.getNext() if previous==None: self.head=temp else: previous.setNext(temp) def index(self,item): count = 0 current =self.head while current and (current.getData()!=item): count = count+1 current = current.getNext() if count and (count<self.size()): return count else: raise ValueError("%s is not in UnorderedList"%item) def size(self): count = 0 current = self.head while current!=None: count += 1 current = current.getNext() return count def isEmpty(self): return self.head==None u = UnorderedList() u.append(3) u.append(2) u.append(6) #print u.index(6), u.index(7) print u.size(),u.pop() print u.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 = self while 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: return head left = head mid = get_mid(head) right = mid.next mid.next=None return merge(sort_list(left),sort_list(right)) def merge(left, right): node = ListNode(0) temp = node while left and right: if left.data>=right.data: temp.next = right right = right.next else: temp.next = left left = left.next temp = temp.next if left: temp.next = left if right: temp.next = right return node.next def get_mid(node): if node==None: return node slow = node fast = node while fast.next and fast.next.next: slow = slow.next fast = fast.next.next return slow 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 = self while 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: return head temp = head import heapq hq = [] while temp: heapq.heappush(hq,temp.data) temp = temp.next head = ListNode(heapq.heappop(hq)) prev = head while hq: 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 = self while 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 = None while cur: temp = cur.next cur.next = prev prev = cur cur = temp return prev 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 = self while 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 = None while cur: temp = cur.next cur.next = prev prev = cur cur = temp return prev,head def reverse_linkedlist(head,k): temp = head for i in range(k-1): temp = temp.next if temp==None: return None mid = temp.next temp.next=None head1,end1 = reverse(head) head2,end2 = reverse(mid) end1.next = head2 return head1 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 = self while 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 = first for i in range(3): #向后移动三次,即将20作为入环节点 temp = temp.next while first.next: first = first.next first.next = temp return l1 l3 = cycle_list(l1) #l3.traverse() #检查是否存在环路 def check_cycle(head): slow = fast = head while fast!=None and fast.next!=None: fast = fast.next.next slow = slow.next if slow is fast: return True return False 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 = self while 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 = first for i in range(3): #向后移动三次,即将20作为入环节点 temp = temp.next while first.next: first = first.next first.next = temp return l1 l3 = cycle_list(l1) #l3.traverse() #返回入环点 def check_cycle_entrance(head): slow = fast = head found_cycle = False while fast!=None and fast.next!=None and not found_cycle: fast = fast.next.next slow = slow.next if slow is fast: #链表有环路 found_cycle=True if found_cycle: fast = head #快指针从头结点开始,一次走一步 while fast!=slow: fast = fast.next slow = slow.next return fast else: return None 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 = self while 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 = first for i in range(3): #向后移动三次,即将20作为入环节点 temp = temp.next while first.next: first = first.next first.next = temp return l1 l3 = cycle_list(l1) #l3.traverse() #计算环路长度 def count_cycle_length(head): slow = fast = head found_cycle = False while fast!=None and fast.next!=None and not found_cycle: fast = fast.next.next slow = slow.next if slow is fast: #链表有环路 found_cycle=True if found_cycle: count = 1 fast = fast.next.next slow = slow.next while fast!=slow: #第二次相遇 fast = fast.next.next slow = slow.next count = count+1 return count else: return None 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 = self while 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 while head1: length1 = length1+1 head1 = head1.next while head2: length2 = length2+1 head2 = head2.next if length1>length2: #长链表先走 for i in range(length1-length2): l1 = l1.next else: for i in range(length2-length1): l2 = l2.next while l1!=None and l2!=None: if l1.data = l2.data: #应该是l1==l2(或l1 is l2),这里使用值代替了,方便看执行结果 return l1.data l1 = l1.next l2 = l2.next return None 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)代码如下所示:
class OrderedList(object): def __init__(self): self.head = None def add(self,item): previous = None current = self.head while current and (item > current.getData()): previous = current current = current.getNext() temp = Node(item) if previous == None: temp.setNext(self.head) self.head=temp else: previous.setNext(temp) temp.setNext(current) def search(self,item): current = self.head found = False stop = False while current!=None and (not found) and (not stop): if current.getNext()==item: found =True else: if current.getData()<item: current = current.getNext() else: stop = True return found def remove(self,item): previous = None current = self.head while 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)