算法漫游指北(第四篇):python中实现链表、单链表的实现、单向循环链表、双向链表
一、python中实现链表(二)
python中实现链表(一)见https://www.cnblogs.com/Nicholas0707/p/12730944.html
0、定义节点
class Node: """单链表的结点""" def __init__(self,item): # _item存放数据元素 self.item = item # _next是下一个节点的标识 self.next = None
1、定义链表
class SingleLinked(object): """定义单向链表""" # 初始化链表 def __init__(self, node=None): self._head = node # 默认头节点为空
2、判断空:
# 判断链表为空 def is_empty(self): # 头节点为空则链表为空 return self._head is None
分析:如果链表的self._head为空,则说明链表的首节点就是空的,表示为空链表。
3、尾部添加元素
def append(self, item): """尾部添加元素""" node = SingleNode(item) # 先判断链表是否为空,若是空链表,则将_head指向新节点 if self.is_empty(): self._head = node # 若不为空,则找到尾部,将尾节点的next指向新节点 else: cur = self._head while cur.next != None: cur = cur.next cur.next = node
示例
class Node: def __init__(self,item): self.item = item self.next = None class SingleLink: def __init__(self,node=None): self._head = node def is_empty(self): # 头节点为空则链表为空 return self._head is None def append(self, item): """尾部添加元素""" node = Node(item) # 先判断链表是否为空,若是空链表,则将_head指向新节点 if self.is_empty(): self._head = node # 若不为空,则找到尾部,将尾节点的next指向新节点 else: cur = self._head while cur.next != None: cur = cur.next cur.next = node sl1 = SingleLink() sl1.append('张三') sl1.append('李四') sl1.append('王五')
添加节点过程分析:
(1)如果是空链表的话:
创建新的节点node对象
node = Node('张三'),
这里的node.item = '张三', node.next=None,
并将self._head =node
,此时 self._head
不再为空
(2)再次添加新的节点:
创建第二个节点node对象
node = Node('李四'),
cur为当前游标,将_head的值赋值给cur,
此时是添加第二个节点,cur = self._head 即第一个节点的node.next=None,还是无法进入while循环
直接执行 cur.next = node语句,
cur.next = Node('李四')
即SingleLink对象._head=Node('张三')
SingleLink对象._head.next = Node('李四')
(3)添加第三个节点
创建第三个节点node对象
node = Node('王五'),
cur为当前游标,将_head的值赋值给cur,
此时是添加第三个节点,cur = self._head 即第一个节点的node.next= Node('李四'),
进入while循环
执行 cur.next = node语句,
cur = cur.next
从头节点寻找下一个节点,直到cur.next==None,即一直找到尾节点,即next指向为空的节点,这里是第二个节点
最后执行
cur.next = node
即cur.next = Node('王五')
即SingleLink对象._head=Node('张三')
SingleLink对象._head.next = Node('李四')
SingleLink对象._head.next.next = Node('王五')
4、返回链表长度
def length(self): """链表长度""" if self.is_empty(): return 0 else: # cur初始时指向头节点 cur = self._head count = 0 # 尾节点指向None,当未到达尾部时 while cur != None: count += 1 print('执行了') # 将cur后移一个节点 cur = cur.next return count
分析:使用游标(cur)从链表的头节点找到尾部。
执行过程动图
5、头部添加元素:
def add(self, item): """头部添加元素""" node = Node(item) if self.empty(): # 空链表添加新节点 self.__head = node else: # 注意这两句的顺序不能换 # 将新节点的链接域next指向之前的头节点,即_head指向的位置 node.next = self.__head # 将链表新的头_head指向刚刚添加的新节点 self.__head = node
示例
class Node: def __init__(self,item): self.item = item self.next = None class SingleLink: def __init__(self,node=None): self._head = node def is_empty(self): # 头节点为空则链表为空 return self._head is None def append(self, item): """尾部添加元素""" node = Node(item) # 先判断链表是否为空,若是空链表,则将_head指向新节点 if self.is_empty(): self._head = node # 若不为空,则找到尾部,将尾节点的next指向新节点 else: cur = self._head print(cur) while cur.next != None: cur = cur.next cur.next = node def length(self): """链表长度""" if self.is_empty(): return 0 else: # cur初始时指向头节点 cur = self._head count = 0 # 尾节点指向None,当未到达尾部时 while cur != None: count += 1 # 将cur后移一个节点 cur = cur.next return count # 头部添加元素 def add(self, item): """头部添加元素""" node = Node(item) if self.empty(): # 空链表添加新节点 self.__head = node else: # 注意这两句的顺序不能换 # 将新节点的链接域next指向之前的头节点,即_head指向的位置 node.next = self.__head # 将链表新的头_head指向刚刚添加的新节点 self.__head = node sl1 = SingleLink() sl1.add('张三') sl1.add('李四')
分析执行过程动图
6、指定位置添加元素
def insert(self, pos, item): """指定位置添加元素""" # 若指定位置pos为第一个元素之前,则执行头部插入 if pos <= 0: self.add(item) # 若指定位置超过链表尾部,则执行尾部插入 elif pos > (self.length()-1): self.append(item) # 找到指定位置 else: node = Node(item) count = 0 # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置 pre = self._head while count < (pos-1): #通过循环找到要插入节点的前一个节点 count += 1 pre = pre.next # 先将新节点node的next指向插入位置的节点 node.next = pre.next # 将插入位置的前一个节点的next指向新节点 pre.next = node
7、删除节点
def remove(self, item): """删除节点""" if self.is_empty(): return False cur = self._head # 定义cur游标 pre = None # 定义pre游标,为cur的前一个位置 while cur is not None: # 找到了指定元素 if cur.item == item: # # 如果第一个就是删除的节点 if cur == self._head: # 将头节点的下一个节点赋给头节点 self._head = cur.next return True # 非头节点情况 else: # 删除操作,将删除位置前一个节点的next指向删除位置的后一个节点 pre.next = cur.next return True # 移动游标 else: # 这两句顺序不能反,继续按链表后移节点 pre = cur cur = cur.next return False
8、查找节点是否存在
def search(self, item): """链表查找节点是否存在,并返回True或者False""" if self.is_empty(): return False else: cur = self._head # 定义游标 while cur is not None: if cur.item == item: return True else: cur = cur.next # 游标后移 return False
9、遍历链表:
def travel(self): # 遍历链表 if self.is_empty(): return None else: item_list = [] # 元素列表 cur = self._head # 如果游标不为空,则打印游标对应的元素,游标向后移动 while cur is not None: item_list.append(cur.item) cur = cur.next # 游标下移 return item_list
10、整体代码示例
class Node: """单链表的结点""" def __init__(self,item): # _item存放数据元素 self.item = item # _next是下一个节点的标识 self.next = None class SingleLink: def __init__(self,node=None): self._head = node def is_empty(self): # 头节点为空则链表为空 return self._head is None def append(self, item): """尾部添加元素""" node = Node(item) # 先判断链表是否为空,若是空链表,则将_head指向新节点 if self.is_empty(): self._head = node # 若不为空,则找到尾部,将尾节点的next指向新节点 else: cur = self._head print(cur) while cur.next != None: cur = cur.next cur.next = node def length(self): """链表长度""" if self.is_empty(): return 0 else: # cur初始时指向头节点 cur = self._head count = 0 # 尾节点指向None,当未到达尾部时 while cur != None: count += 1 # 将cur后移一个节点 cur = cur.next return count # 头部添加元素 def add(self, item): """头部添加元素""" node = Node(item) if self.empty(): # 空链表添加新节点 self.__head = node else: # 注意这两句的顺序不能换 # 将新节点的链接域next指向之前的头节点,即_head指向的位置 node.next = self.__head # 将链表新的头_head指向刚刚添加的新节点 self.__head = node def insert(self, pos, item): """指定位置添加元素""" # 若指定位置pos为第一个元素之前,则执行头部插入 if pos <= 0: self.add(item) # 若指定位置超过链表尾部,则执行尾部插入 elif pos > (self.length()-1): self.append(item) # 找到指定位置 else: node = Node(item) count = 0 # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置 pre = self._head while count < (pos-1): count += 1 pre = pre.next # 先将新节点node的next指向插入位置的节点 node.next = pre.next # 将插入位置的前一个节点的next指向新节点 pre.next = node def remove(self, item): """删除节点""" if self.is_empty(): return False cur = self._head # 定义cur游标 pre = None # 定义pre游标,为cur的前一个位置 while cur is not None: # 找到了指定元素 if cur.item == item: # # 如果第一个就是删除的节点 if cur == self._head: # 将头节点的下一个节点赋给头节点 self._head = cur.next return True # 非头节点情况 else: # 删除操作,将删除位置前一个节点的next指向删除位置的后一个节点 pre.next = cur.next return True # 移动游标 else: # 这两句顺序不能反,继续按链表后移节点 pre = cur cur = cur.next return False # 查找节点是否存在 def search(self, item): """链表查找节点是否存在,并返回True或者False""" if self.is_empty(): return False else: cur = self._head # 定义游标 while cur is not None: if cur.item == item: return True else: cur = cur.next # 游标后移 return False def travel(self): # 遍历链表 if self.is_empty(): return None else: item_list = [] # 元素列表 cur = self._head # 如果游标不为空,则打印游标对应的元素,游标向后移动 while cur is not None: item_list.append(cur.item) cur = cur.next # 游标下移 return item_list sl1 = SingleLink() sl1.append('张三') sl1.append('李四') sl1.insert(1,'王五') print(sl1._head.item) print(sl1._head.next.item) print(sl1._head.next.next.item) sl1.remove('王五') print(sl1._head.item) print(sl1._head.next.item) print(sl1.search('张三')) print(sl1.travel())
单向循环链表
所谓单向循环链表,不过是在单向链表的基础上,如响尾蛇般将其首尾相连,也因此有诸多类似之处与务必留心之点。尤其是可能涉及到头尾节点的操作,不可疏忽。
单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
示例
class Node(object): """节点""" def __init__(self, item): self.item = item self.next = None class SinCycLinkedlist(object): """单向循环链表""" def __init__(self): self._head = None def is_empty(self): """判断链表是否为空""" return self._head == None def length(self): """返回链表的长度""" # 如果链表为空,返回长度0 if self.is_empty(): return 0 count = 1 cur = self._head while cur.next != self._head: count += 1 cur = cur.next return count def travel(self): """遍历链表""" if self.is_empty(): return cur = self._head print cur.item, while cur.next != self._head: cur = cur.next print cur.item, print "" def add(self, item): """头部添加节点""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: #添加的节点指向_head node.next = self._head # 移到链表尾部,将尾部节点的next指向node cur = self._head while cur.next != self._head: cur = cur.next cur.next = node #_head指向添加node的,这里是与单链表不同的地方 self._head = node def append(self, item): """尾部添加节点""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: # 移到链表尾部 cur = self._head while cur.next != self._head: cur = cur.next # 将尾节点指向node cur.next = node # 将node指向头节点_head,这里是与单链表不同的地方 node.next = self._head 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.next = cur.next cur.next = node def remove(self, item): """删除一个节点""" # 若链表为空,则直接返回 if self.is_empty(): return # 将cur指向头节点 cur = self._head pre = None # 若头节点的元素就是要查找的元素item if cur.item == item: # 如果链表不止一个节点 if cur.next != self._head: # 先找到尾节点,将尾节点的next指向第二个节点 while cur.next != self._head: cur = cur.next # cur指向了尾节点 cur.next = self._head.next self._head = self._head.next else: # 链表只有一个节点 self._head = None else: pre = self._head # 第一个节点不是要删除的 while cur.next != self._head: # 找到了要删除的元素 if cur.item == item: # 删除 pre.next = cur.next return else: pre = cur cur = cur.next # cur 指向尾节点 if cur.item == item: # 尾部删除 pre.next = cur.next def search(self, item): """查找节点是否存在""" if self.is_empty(): return False cur = self._head if cur.item == item: return True while cur.next != self._head: cur = cur.next if cur.item == item: return True return False if __name__ == "__main__": ll = SinCycLinkedlist() 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(7) ll.remove(1) print "length:",ll.length() ll.travel()
双向链表
一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
链表实现
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
posted on 2020-02-29 21:43 Nicholas-- 阅读(225) 评论(0) 编辑 收藏 举报