数据结构之链表(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→23456,k=2,则翻转后2→16543,若k=3,翻转后3→21654,若k=4,翻转后4→32165,用程序实现。

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)

 

    

·参考:http://interactivepython.org/runestone/static/pythonds/BasicDS/ImplementinganUnorderedListLinkedLists.html  

   http://wuchong.me/blog/2014/03/25/interview-link-questions/ 

posted @ 2018-12-02 18:14  silence_cho  阅读(1051)  评论(0编辑  收藏  举报