双向链表的知识点很多都和单向链表相同,函数实现方法也差不多,只是需要注意每个节点的prev需要指向上一个节点。
双向链表的节点实现:
'''双向链表'''
# 节点实现
class Node(object):
def __init__(self, item):
self.item = item
# 前后指向地址暂定为None
self.prev = None
self.next = None
需要注意的就是地址指向有两个prev和next,初始值都设为None
双向链表实现:
# 双向链表实现
class DoubleLinkList(object):
def __init__(self, node=None):
self.__head = node
因为双向链表中的首地址指向None,所以__init__函数中参量默认为node=None,假如传入参数node,不是空链表了,此时self.__head指向node。
双向链表的增删改查等函数实现:
1、判空函数:
def is_empty(self):
if self.__head == None:
return True
else:
return False
2、链表长度函数:
# 链表长度
def length(self):
# 考虑空链表情况
if self.is_empty():
return 0
# cur游标 指向首节点,用来遍历 相当于指针
cur = self.__head # 游标指向首地址
count = 0 # 注意此时的初始值和非空情况的判断条件的关系
# 非空情况下
while cur != None: # 初始值为0 的判断条件
count += 1
cur = cur.next
return count
# 另一种判空情况
# while cur.next != None: # 找到尾节点
# count += 1
# cur = cur.next # 继续循环
# return count
这里注意的是while虚表还条件的选择,这个与count的初始值设定有关,还关乎尾节点是否在循环内的情况。
代码中注释掉的一部分代码,就是另外一种的while循环条件,相对应的count=1,此时尾节点的数据没有进入到循环内,需要单独考虑。
3、遍历链表
# 遍历链表
def travel(self):
cur = self.__head
# 考虑空链表情况
if self.is_empty():
return None
# 非空链表的情况下:
while cur != None:
print(cur.item, end=' ')
cur = cur.next # 因为判空条件的不同,尾节点已经在循环中
# while cur.next != None:
# print(cur.item)
# cur = cur.next
#
# print(cur.next) # 输出结尾结点
和上面的函数实现相同,while循环条件的选择,和输出语句相关,注释掉的代码是另一种实现函数的方法。
4、链表头部插入元素
def add(self, item):
node = Node(item)
# 空链表
if self.is_empty():
self.__head = node
else:
# 非空链表
# 第一步:将新的节点的地址指向初始链表的第一个元素
node.next = self.__head
# 第二步:将__head的头节点的prev指向node
# cur.prev = node
self.__head.prev = node
# 第三步:将__head指向node
# node.prev = None
self.__head = node
这里需要注意的是:注释掉的代码是一种错误的思路,需要区分开。注释掉的代码是没有明确cur,prev和next代表的含义是什么,这些都是指向节点的数据地址的“指针”。如下图所示:
图中箭头代表的是指向的地址,代码编写的顺序应该是从右往左编写代码,否则会出现地址指向错误,顺序很重要!!!
5、链表尾部插入数据
# 尾部插入新节点
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指向尾部结点
cur.next = node
node.prev = cur
这里的while循环条件特殊一点:因为是在尾部插入,找到的节点需要是最后一个节点,节点的next为None。
图中箭头代表的是指向的地址,代码编写的顺序应该是从右往左编写代码,否则会出现地址指向错误,顺序很重要!!!
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)
cur = self.__head
count = 0
# 在链表长度内循环
while count < (pos - 1):
count += 1
cur = cur.next
# 循环结束
# 插入的节点next指向游标所指的下一个节点
node.next = cur.next
# 新节点的prev指向游标所指的节点
node.prev = cur
# 游标所指下一个节点的prev指向新结点
cur.next.prev = node
# 游标所在的节点的next指向新节点
cur.next = node
示意图如下:
图中箭头代表的是指向的地址,代码编写的顺序应该是从右往左编写代码,这里最主要的是两个指向需要先写:1、插入的节点next指向游标所指的下一个节点;2、新节点的prev指向游标所指的节点;这两个顺序需要在(游标所指下一个节点的prev指向新结点)(游标所在的节点的next指向新节点)之前
7、查找节点是否存在
# 查找结点是否存在
def search(self, item):
cur = self.__head
# 循环查找
while cur != None:
if cur.item == item:
return True
else:
# 游标继续执行
cur = cur.next
return False
8、删除链表节点
# 删除链表节点
def remove(self, item):
if self.is_empty():
return None
else:
cur = self.__head
# 首结点的元素就是要删除的元素
if cur.item == item:
# 如果链表只有一个结点
if cur.next == None:
self.__head = None # 首地址指向None
else: # 链表中不止一个节点数据
cur.next.prev = None # 下一个节点的prev指向None
self.__head = cur.next # 首地址只想下个节点
return None
while cur != None: # 循环到尾部节点数据之前
if cur.item == item: # 循环过程中找到需要的数据
cur.prev.next = cur.next # 当前要删除节点的prev,即上一个节点,上一个节点的next指向删除后的节点
if cur.next: # 如果删除节点的下一个节点不是尾部节点
cur.next.prev = cur.prev # 下一个节点的prev指向删除节点的前一个节点
break # 跳出循环
cur = cur.next # 继续循环
示意图如下:
代码整体的实现:
# -*- encoding: utf-8 -*-
"""
@File : double_link_list.py
@Time : 2019/11/13 15:03
@Author : chen
"""
'''双向链表'''
# 节点实现
class Node(object):
def __init__(self, item):
self.item = item
# 前后指向地址暂定为None
self.prev = None
self.next = None
# 双向链表实现
class DoubleLinkList(object):
def __init__(self, node=None):
self.__head = node #
def is_empty(self):
if self.__head == None:
return True
else:
return False
# 链表长度
def length(self):
# 考虑空链表情况
if self.is_empty():
return 0
# cur游标 指向首节点,用来遍历 相当于指针
cur = self.__head # 游标指向首地址
count = 0 # 注意此时的初始值和非空情况的判断条件的关系
# 非空情况下
while cur != None: # 初始值为0 的判断条件
count += 1
cur = cur.next
return count
# 另一种判空情况
# while cur.next != None: # 找到尾节点
# count += 1
# cur = cur.next # 继续循环
# return count
# 遍历链表
def travel(self):
cur = self.__head
# 考虑空链表情况
if self.is_empty():
return None
# 非空链表的情况下:
while cur != None:
print(cur.item, end=' ')
cur = cur.next # 因为判空条件的不同,尾节点已经在循环中
# while cur.next != None:
# print(cur.item)
# cur = cur.next
#
# print(cur.next) # 输出结尾结点
# 头部插入元素
def add(self, item):
node = Node(item)
# 空链表
if self.is_empty():
self.__head = node
else:
# 非空链表
# 第一步:将新的节点的地址指向初始链表的第一个元素
node.next = self.__head
# 第二步:将__head的头节点的prev指向node
# cur.prev = node
self.__head.prev = node
# 第三步:将__head指向node
# node.prev = None
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指向尾部结点
cur.next = node
node.prev = cur
# 任意位置插值
def insert(self, pos, item):
# pos负数,头部插入
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
# 循环结束
# 插入的节点next指向游标所指的下一个节点
node.next = cur.next
# 新节点的prev指向游标所指的节点
node.prev = cur
# 游标所指下一个节点的prev指向新结点
cur.next.prev = node
# 游标所在的节点的next指向新节点
cur.next = node
# 查找结点是否存在
def search(self, item):
cur = self.__head
# 循环查找
while cur != None:
if cur.item == item:
return True
else:
# 游标继续执行
cur = cur.next
return False
# 删除链表节点
def remove(self, item):
if self.is_empty():
return None
else:
cur = self.__head
# 首结点的元素就是要删除的元素
if cur.item == item:
# 如果链表只有一个结点
if cur.next == None:
self.__head = None # 首地址指向None
else: # 链表中不止一个节点数据
cur.next.prev = None # 下一个节点的prev指向None
self.__head = cur.next # 首地址只想下个节点
return None
while cur != None: # 循环到尾部节点数据之前
if cur.item == item: # 循环过程中找到需要的数据
cur.prev.next = cur.next # 当前要删除节点的prev,即上一个节点,上一个节点的next指向删除后的节点
if cur.next: # 如果删除节点的下一个节点不是尾部节点
cur.next.prev = cur.prev # 下一个节点的prev指向删除节点的前一个节点
break # 跳出循环
cur = cur.next # 继续循环
if __name__ == '__main__':
d = DoubleLinkList()
print(d.is_empty())
print(d.length())
d.add(1)
d.add(2)
d.append(0)
d.insert(2, 5)
d.insert(-1, 9)
d.insert(10,100)
d.travel()
print(d.is_empty())
print(d.length())