链表
为什么需要链表 顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以 使用起来并不是很灵活。 链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。 链表的定义 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是 在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)
单向链表
单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一 个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值
·表元素域elem用来存放具体的数据。 ·链接域next用来存放下一个节点的位置(python中的标识) ·变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。
节点实现
class SingleNode(object): ““单链表的结点" def_init_(self,item): #_item存放数据元素 self.item=item #_next是下一个节点的标识 self.next=None
单链表的操作(其他链表大致相同)
·is_empty0链表是否为空 ·length0链表长度 ·travel0遍历整个链表 ·add(item)链表头部添加元素 ·append(item)链表尾部添加元素 ·insert(pos,item)指定位置添加元素 ·remove(item)删除节点 ·search(item)查找节点是否存在
单链表的实现
# coding:utf-8 class Node(object): """节点Node""" def __init__(self, elem): self.elem = elem self.next = None class SingleLinkList(object): """单链表""" def __init__(self, node=None): self.__head = None def is_empty(self): '''链表是否为空''' return self.__head == None def length(self): '''链表长度''' # cur游标,用来移动遍历节点 cur = self.__head # count记录数量 count = 0 while cur != None: count += 1 cur = cur.next return count def travel(self): '''遍历整个链表''' cur = self.__head while cur != None: print(cur.elem, end=" ") cur = cur.next print('') def add(self, item): '''链表头部添加元素,头插法''' node = Node(item) node.next = self.__head self.__head = node def append(self,item): '''链表尾部添加元素,尾插法''' node = Node(item) if self.is_empty(): self.__head = node else: cur = self.__head while cur.next != None: cur = cur.next cur.next = node def insert(self, pos, item): '''指定位置添加元素 pos 从0开始 ''' if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: pre = self.__head count = 0 while count < (pos - 1): count += 1 pre = pre.next # 当循环退出后,pre指向pos-1位置 node = Node(item) node.next = pre.next pre.next = node def remove(self, item): '''删除节点''' cur = self.__head pre = None while cur != None: if cur.elem == item: # 先判断是否是头节点 # 头节点 if cur == self.__head: self.__head = cur.next else: pre.next = cur.next break else: pre = cur cur = cur.next def search(self, item): '''查找节点是否存在''' cur = self.__head while cur != None: if cur.elem == item: return True else: cur = cur.next return False if __name__ == '__main__': l1 = SingleLinkList() print(l1.is_empty()) print(l1.length()) l1.append(1) print(l1.is_empty()) print(l1.length()) l1.append(2) l1.add(8) l1.append(3) l1.append(4) l1.append(5) l1.append(6) l1.insert(-1, 9) l1.travel() l1.insert(3, 100) l1.travel() l1.insert(10, 200) l1.travel() l1.remove(100) l1.travel() l1.remove(9) l1.travel() l1.remove(200) l1.travel() ''' True 0 False 1 9 8 1 2 3 4 5 6 9 8 1 100 2 3 4 5 6 9 8 1 100 2 3 4 5 6 200 9 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 '''
单向循环链表
单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点
# coding:utf-8 class Node(object): """结点Node""" def __init__(self, elem): self.elem = elem self.next = None self.prev = None class DoubuleLinkList(object): """单向循环链表""" def __init__(self, node=None): self.__head = node if node: node.next = node def is_empty(self): '''链表是否为空''' return self.__head == None def length(self): '''链表长度''' if self.is_empty(): return 0 # cur游标,用来移动遍历节点 cur = self.__head # count记录数量 count = 1 while cur.next != self.__head: count += 1 cur = cur.next return count def travel(self): '''遍历整个链表''' if self.is_empty(): return cur = self.__head while cur.next != self.__head: print(cur.elem, end=" ") cur = cur.next # 退出循环,cur指向尾结点,但尾结点的元素未打印 print(cur.elem) def add(self, item): '''链表头部添加元素,头插法''' node = Node(item) if self.is_empty(): self.__head = node node.next = node else: cur = self.__head while cur.next != self.__head: cur = cur.next # 退出循环,cur指向尾结点 node.next = self.__head self.__head = node # cur.next = node cur.next = self.__head def append(self, item): '''链表尾部添加元素,尾插法''' node = Node(item) if self.is_empty(): self.__head = node node.next = node else: cur = self.__head while cur.next != self.__head: cur = cur.next # node.next=cur.next node.next = self.__head cur.next = node def insert(self, pos, item): '''指定位置添加元素 pos 从0开始 ''' if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: pre = self.__head count = 0 while count < (pos - 1): count += 1 pre = pre.next # 当前循环退出后,pre指向pos-1位置 node = Node(item) node.next = pre.next pre.next = node def remove(self, item): '''删除节点''' cur = self.__head pre = None while cur.next != self.__head: if cur.elem == item: # 先判断是否是头节点 if cur == self.__head: # 头结点情况 # 找尾结点 rear = self.__head while rear.next != self.__head: rear = rear.next self.__head = cur.next rear.next = self.__head else: # 中间结点 pre.next = cur.next return else: pre = cur cur = cur.next # 退出循环,cur指向尾结点 if cur.elem == item: if cur == self.__head: # 链表只有一个结点 self.__head = None else: # pre.next=cur.next pre.next = self.__head def search(self, item): '''查找节点是否存在''' if self.is_empty(): return False cur = self.__head while cur.next != self.__head: if cur.elem == item: return True else: cur = cur.next # 退出循环,cur指向尾结点 if cur.elem == item: return True return False if __name__ == '__main__': l1 = DoubuleLinkList() print(l1.is_empty()) print(l1.length()) l1.append(1) print(l1.is_empty()) print(l1.length()) l1.append(2) l1.add(8) l1.append(3) l1.append(4) l1.append(5) l1.append(6) l1.insert(-1, 9) l1.travel() l1.insert(3, 100) l1.travel() l1.insert(10, 200) l1.travel() l1.remove(100) l1.travel() l1.remove(9) l1.travel() l1.remove(200) l1.travel() ''' True 0 False 1 9 8 1 2 3 4 5 6 9 8 1 100 2 3 4 5 6 9 8 1 100 2 3 4 5 6 200 9 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 '''
双向链表
一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第
一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值
# coding:utf-8 class Node(object): """结点Node""" def __init__(self, elem): self.elem = elem self.next = None self.prev=None class DoubuleLinkList(object): """双链表""" def __init__(self, node=None): self.__head = None def is_empty(self): '''链表是否为空''' return self.__head == None def length(self): '''链表长度''' # cur游标,用来移动遍历节点 cur = self.__head # count记录数量 count = 0 while cur != None: count += 1 cur = cur.next return count def travel(self): '''遍历整个链表''' cur = self.__head while cur != None: print(cur.elem, end=" ") cur = cur.next print('') def add(self, item): '''链表头部添加元素,头插法''' node = Node(item) node.next = self.__head self.__head = node node.next.prev=node def append(self,item): '''链表尾部添加元素,尾插法''' node = Node(item) if self.is_empty(): self.__head = node else: cur = self.__head while cur.next != None: cur = cur.next cur.next = node node.prev=cur def insert(self, pos, item): '''指定位置添加元素 pos 从0开始 ''' if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: cur=self.__head count = 0 while count < pos: count += 1 cur = cur.next # 当循环退出后,cur指向pos位置 node = Node(item) node.next=cur node.prev=cur.prev cur.prev.next=node cur.prev=node def remove(self, item): '''删除节点''' cur = self.__head while cur != None: if cur.elem == item: # 先判断是否是头节点 # 头节点 if cur == self.__head: if cur.next: #判断链表是否只有一个结点 cur.next.prev=None else: cur.prev.next=cur.next if cur.next: cur.next.prev = cur.prev break else: cur = cur.next def search(self, item): '''查找节点是否存在''' cur = self.__head while cur != None: if cur.elem == item: return True else: cur = cur.next return False if __name__ == '__main__': l1 = DoubuleLinkList() print(l1.is_empty()) print(l1.length()) l1.append(1) print(l1.is_empty()) print(l1.length()) l1.append(2) l1.add(8) l1.append(3) l1.append(4) l1.append(5) l1.append(6) l1.insert(-1, 9) l1.travel() l1.insert(3, 100) l1.travel() l1.insert(10, 200) l1.travel() l1.remove(100) l1.travel() l1.remove(9) l1.travel() l1.remove(200) l1.travel() ''' True 0 False 1 9 8 1 2 3 4 5 6 9 8 1 100 2 3 4 5 6 9 8 1 100 2 3 4 5 6 200 9 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 200 8 1 2 3 4 5 6 '''
链表与顺序表的对比
链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的
使用要相对灵活。
链表与顺序表的各种操作复杂度如下所示:
注意虽然表面看起来复杂度都是O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前 后移位操作,只能通过拷贝和覆盖的方法进行。