1、循环双向链表特点
- 通过当前结点直接获取上一结点
- 通过头结点的上一结点直接可以去找到尾结点
- 可以进行反向循环链表,即反转链表
2、头结点
链表头:
在数据结构中,链表是一种常见的存储结构。链表的每个节点包含数据和指向下一个节点的指针。链表头是链表的第一个节点,它在链表的操作中起着重要的作用。
链表头的意义:
链表头节点是一个特殊的节点,它通常不存储实际数据,而是指向链表的第一个实际数据节点。链表头的主要作用是简化链表的操作,特别是在插入和删除节点时。通过引入头节点,可以避免处理链表第一个节点的特殊情况,使代码更加简洁和通用。
3、代码示例
class Node(object):# 节点类def __init__(self,item):self.item = item # 记录数据self.next = None # 记录下一个节点self.pre = None # 记录前面节点class DoubleCycLinkList(object):# 双链表类def __init__(self):# 所有操作都是从头开始,需要记录头结点self.__head = Nonedef is_empty(self):"""链表是否为空"""return self.__head is Nonedef length(self):"""链表长度"""if self.is_empty():return 0# 定义计数器,遍历链表count = 1cur = self.__headwhile cur.next is not self.__head:count += 1cur = cur.nextreturn countdef travel(self):"""遍历整个链表"""if self.is_empty():return# 定义游标,从头向尾移动cur = self.__headwhile cur.next is not self.__head:print(cur.item, end=" ")# 让游标往后移动cur = cur.next# while循环会漏掉尾节点print(cur.item)def add(self,item):"""链表头部添加元素"""# 创建新的节点node = Node(item)if self.is_empty():self.__head = nodenode.next = nodereturn# 遍历找到尾节点cur = self.__headwhile cur.next is not self.__head:cur = cur.next# while 循环结束,cur指向尾节点# 新节点的next指向原来的头节点node.next = self.__head# 原来的头结点指向新节点self.__head = node# 让尾节点指向新的头cur.next = self.__head# 新的头结点指向尾节点self.__head.pre = curdef append(self,item):""""链表尾部添加元素"""# 判断链表是否为空if self.is_empty():self.add(item)return# 第一步,找尾节点cur = self.__headwhile cur.next is not self.__head:# 首节点的pre是尾节点cur = cur.next# while 循环结束,cur指向尾节点# 第二步,尾节点指向新节点node = Node(item)# 尾节点指向新的节点cur.next = node# 新的节点的pre指向原尾节点node.pre = cur# 新节点指向头节点node.next = self.__head# 头结点的pre指向新节点self.__head.pre = nodedef insert(self,pos, item):"""指定位置添加元素"""if pos <= 0:self.add(item)elif pos >= self.length():self.append(item)else:# 1 定义下标,与游标同步变化index = 0cur = self.__headwhile index < (pos - 1):index += 1cur = cur.next# 循环结束后,cur指向pos前置节点-node = Node(item)# 2、让新节点的next指向pos位置的节点node.next = cur.next# 让pos位置的节点的pre指向新节点cur.next.pre = node# 3、让pos位置的前置节点指向新节点cur.next = node# 让新节点的pre指向pos的前置节点node.pre = curdef remove(self,item):"""删除节点"""if self.is_empty():return# 定义pre记录当前节点的前置节点pre = Nonecur = self.__headwhile cur.next is not self.__head:if cur.item == item:# 删除当前节点# 如果pre为空,删掉的是头 需要让尾节点指向新的头if pre is None:# 找到尾节点temp = self.__headwhile temp.next is not self.__head:temp = temp.next# while循环结束,temp指向尾节点# 头结点指向当前的下一个节点self.__head = cur.next# 当前的下一个节点指向头结点cur.next.pre = self.__head# 让尾节点指向新的头temp.next = self.__head# 新的头接点指向尾节点self.__head.pre = tempelse:# 删除中间节点# 上一个节点的next指向当前的的next即下一个节点pre.next = cur.nextcur.next.pre = cur.prereturn# pre 一直记录cur的前置节点pre = curcur = cur.next# while循环处理不了尾节点,单独处理尾节点if cur.item == item:# 如果pre为空,证明当前只有一个节点,而且要删除这个节点if pre is None:self.__head = Noneelse:# 让尾节点的前置节点指向头pre.next = self.__headself.__head.pre = cur.predef search(self,item):"""查找节点是否存在"""if self.is_empty():return Falsecur = self.__headwhile cur.next is not self.__head:if cur.item == item:return Truecur = cur.next# 单独处理尾节点if cur.item == item:return Truereturn Falseif __name__ == '__main__':sll = DoubleCycLinkList()print(sll.length())sll.add(1)sll.add(2)sll.add(3)print("11111===========")sll.travel()sll.append(4)sll.travel()print("=====")sll.remove(1)sll.travel()sll.remove(4)sll.travel()sll.remove(3)sll.travel()sll.insert(-10,0)sll.travel()sll.insert(10, 10)sll.travel()sll.insert(1, 1)sll.travel()print(sll.length())print("======")print(sll.search(0))print(sll.search(2))print(sll.search(10))print(sll.search(7))sll.travel()
参考:
https://blog.csdn.net/qq_33465047/article/details/104642601
https://blog.csdn.net/Winnie_boy/article/details/116163996
https://www.cnblogs.com/Lin-Yi/p/7326713.html