单链表:
单链表的数据结构:每个指针指向想一个结点。
头插入结点:改变自己的指针指向有一个结点
链表中间插入:改变前一个结点的指针指向自己,改变自己的指针指向后一个结点
删除列表的第一个结点:改变头指针指向第二个结点,删除自己的指针。
删除任意结点:改变前一个结点的指针指向下一个结点。
代码实现:
#/usr/bin/python #-*- coding: utf-8 -*- class LNode(object): #结点初始化函数, p 即模拟所存放的下一个结点的地址 #为了方便传参, 设置 p 的默认值为 0 def __init__(self, data, p=0): self.data = data self.next = p class LinkList(object): def __init__(self): self.head = None #链表初始化函数, 方法类似于尾插 def initList(self, data): #创建头结点 self.head = LNode(data[0]) p = self.head #逐个为 data 内的数据创建结点, 建立链表 for i in data[1:]: node = LNode(i) p.next = node p = p.next #链表判空 def isEmpty(self): if self.head.next == 0: print ("Empty List!") return 1 else: return 0 #取链表长度 def getLength(self): if self.isEmpty(): exit(0) p = self.head len = 0 while p: len += 1 p = p.next return len #遍历链表 def traveList(self): if self.isEmpty(): exit(0) print (' link list traving result: ',) p = self.head while p: print (p.data,) p = p.next #链表插入数据函数 def insertElem(self, key, index): if self.isEmpty(): exit(0) if index<0 or index>self.getLength()-1: print (" Key Error! Program Exit.") exit(0) p = self.head i = 0 while i<=index: pre = p p = p.next i += 1 #遍历找到索引值为 index 的结点后, 在其后面插入结点 node = LNode(key) pre.next = node node.next = p #链表删除数据函数 def deleteElem(self, index): if self.isEmpty(): exit(0) if index<0 or index>self.getLength()-1: print (" Value Error! Program Exit.") exit(0) i = 0 p = self.head #遍历找到索引值为 index 的结点 while p.next: pre = p p = p.next i += 1 if i==index: pre.next = p.next p = None return 1 #p的下一个结点为空说明到了最后一个结点, 删除之即可 pre.next = None if __name__ == "__main__": #初始化链表与数据 data = [1,7,3,45] l = LinkList() l.initList(data) l.traveList() #插入结点到索引值为3之后, 值为666 l.insertElem(666, 3) l.traveList() #删除索引值为4的结点 l.deleteElem(4) l.traveList()
class Node(object): def __init__(self, data, next=None): self.val = data self.next = next def fun4(head): if head == None: return None L, M, R = None, None, head while R.next != None: # 第一次循环时:找一个空节点当尾部,以后的循环中是保存前一个结点,然后将当前节点指向前一个结点 L = M # 找一个变量存储当前节点R M = R # 取出当前节点的下一个节点,R.next R = R.next #将当前结点指向前一个结点 M.next = L #R.next为空时跳出循环,此时R.next为尾结点,将此节点指向当前节点,此时就变成了头结点 R.next = M return R # 测试用例 if __name__ == '__main__': l1 = Node(3) l1.next = Node(2) l1.next.next = Node(1) l1.next.next.next = Node(9) l1.next.next.next.next = Node(6) l1.next.next.next.next.next = Node(7) l = fun4(l1) print(l.val, l.next.val, l.next.next.val, l.next.next.next.val,l.next.next.next.next.val,l.next.next.next.next.next.val)
双向链表:
双向链表的结构和操作原理:
删除一个双向链表的结点
代码实现:
#-*- encoding:utf-8 -*- class Node(object): """双向链表节点""" def __init__(self, item): self.item = item self.next = None self.prev = None class DLinkList(object): """双向链表""" def __init__(self): self._head = None def is_empty(self): """判断链表是否为空""" return self._head == None def length(self): """返回链表的长度""" cur = self._head count = 0 while cur != None: count += 1 cur = cur.next return count def travel(self): """遍历链表""" cur = self._head while cur != None: print (cur.item) cur = cur.next print ("") def add(self, item): """头部插入元素""" node = Node(item) if self.is_empty(): # 如果是空链表,将_head指向node self._head = node else: # 将node的next指向_head的头节点 node.next = self._head # 将_head的头节点的prev指向node self._head.prev = node # 将_head 指向node self._head = node def append(self, item): """尾部插入元素""" node = Node(item) if self.is_empty(): # 如果是空链表,将_head指向node self._head = node else: # 移动到链表尾部 cur = self._head while cur.next != None: cur = cur.next # 将尾节点cur的next指向node cur.next = node # 将node的prev指向cur node.prev = cur def search(self, item): """查找元素是否存在""" cur = self._head while cur != None: if cur.item == item: return True cur = cur.next return False def insert(self, pos, item): """在指定位置添加节点""" if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: node = Node(item) cur = self._head count = 0 # 移动到指定位置的前一个位置 while count < (pos - 1): count += 1 cur = cur.next # 将node的prev指向cur node.prev = cur # 将node的next指向cur的下一个节点 node.next = cur.next # 将cur的下一个节点的prev指向node cur.next.prev = node # 将cur的next指向node cur.next = node def remove(self, item): """删除元素""" if self.is_empty(): return else: cur = self._head if cur.item == item: # 如果首节点的元素即是要删除的元素 if cur.next == None: # 如果链表只有这一个节点 self._head = None else: # 将第二个节点的prev设置为None cur.next.prev = None # 将_head指向第二个节点 self._head = cur.next return while cur != None: if cur.item == item: # 将cur的前一个节点的next指向cur的后一个节点 cur.prev.next = cur.next # 将cur的后一个节点的prev指向cur的前一个节点 cur.next.prev = cur.prev break cur = cur.next if __name__ == "__main__": ll = DLinkList() ll.add(1) ll.add(2) ll.append(3) ll.insert(2, 4) ll.insert(4, 5) ll.insert(0, 6) print ("length:", ll.length()) ll.travel() print (ll.search(3)) print (ll.search(4)) ll.remove(1) print ("length:", ll.length()) ll.travel()
二、关于链表的面试题
1.判断一个链表是否成环并判断环结点:
答:定义两个变量,变量p1从头部开始一次走一个元素,p2从头部开始一次走两个元素,两个变量相等时,说明这个链表成环。
当两个变量相等时,走的快的变量p2是走的慢的变量p1的两倍。p1走的路程:环结点前的距离+结点到环内相聚点的距离。p2走的路程为:p1走的路程+环内相遇结点到换节点的距离。这时找找一个变量从头开始一次走一步,和快结点一次走一步,当两个变量相等时,这就是环的结点。
class Node(object): def __init__(self,value=None,next = None): self.value = value self.next = next #判断是否成环 def is_loop(head): if head == None: return "这个链表不是环" p1 = head p2 = head while p2.next != None and p2.next.next !=None: p1 = p1.next p2 = p2.next.next if p1 == p2: return "这个链表是环" return "这个链表不是环" #确定成环的点 def loop_point(head): if head == None: return "这个链表不是环" p1 = head p2 = head while p2.next != None and p2.next.next != None: p1 = p1.next p2 = p2.next.next if p1 == p2: fast = head while fast != p1: fast = fast.next p1 = p1.next return "这个链表是环,环结点是%s" % p1.value else: return "这个链表不是环" if __name__ == "__main__": node1 = Node(1) node2 = Node(2) node3 = Node(3) node4 = Node(4) node5 = Node(5) node1.next = node2 node2.next = node3 node3.next = node4 node4.next = node5 node5.next = node2 print(loop_point(node1)) print(is_loop(node1)) #这个链表是环,环结点是2 #这个链表是环