数据结构与算法—双向链表
双向链表
一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
操作
- is_empty() 链表是否为空
- length() 链表长度
- travel() 遍历整个链表
- add(item) 链表头部添加元素
- append(item) 链表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 删除节点
- search(item) 查找节点是否存在
实现
- 判断链表是否为空
- 计算链表长度
- 遍历链表
- 链表头部添加元素
- 链表尾部添加元素
- 查找某个节点是否存在
class SingleNode(object):
"""双向链表节点"""
def __init__(self, item):
# 定义三个属性,值,后继节点,前继节点
self.item = item
self.next = None
self.prev = None
class DLinkList(object):
"""双向链表"""
def __init__(self):
# head存放单链表首节点地址
self.head = None
def is_empty(self):
"""判断链表是否为空"""
return self.head == None
def length(self):
"""计算链表长度"""
cur = self.head
count = 0
# 当未到达尾部时
while cur:
cur = cur.next
count += 1
return count
def travel(self):
"""遍历链表"""
cur = self.head
while cur:
print(cur.item)
cur = cur.next
def add(self,item):
"""头部插入元素"""
# 先新建一个节点
node = SingleNode(item)
# 新节点的尾部指向原首节点
if self.is_empty():
self.head = node
else:
node.next = self.head
# 原首节点的前继节点 为新节点
self.head.prev = node
# 新首节点为新建节点
self.head = node
def append(self,item):
"""尾部插入元素"""
# 新建节点
node = SingleNode(item)
# 先判断链表是否为空,若是空链表,则将_head指向新节点
if self.is_empty():
self.head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.head
while cur.next:
cur = cur.next
# 找到最后一个节点,最后一个节点的next为新节点
cur.next = node
# 新节点的prev为原尾节点
node.prev = cur
def search(self,item):
"""查找某个节点是否存在"""
cur = self.head
while cur:
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():
self.append(item)
# 在中间插入
else:
# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
pre = self.head
count = 0
node = SingleNode(item)
while count < pos-1:
pre = pre.next
count += 1
# 先将新节点node的next指向插入位置的节点
node.next = pre.next
pre.next.prev = node
# 将插入位置的前一个节点的next指向新节点
pre.next = node
node.prev = pre
- 删除节点
def remove(self,item):
"""删除节点"""
# pre 存着指定item的前一个节点
pre = None
cur = self.head
while cur:
if cur.item != item:
pre = cur
cur = cur.next
else:
# 如果item是首节点,则将头指针指向头节点的后一个节点
if pre == None:
self.head = cur.next
cur.next.prev = None
# 否则item是中间节点,将删除位置前一个节点的next指向删除位置的后一个节点
else:
pre.next = cur.next
cur.next.prev = pre
break
测试
# import pdb
# pdb.set_trace()
class SingleNode(object):
"""双向链表节点"""
def __init__(self, item):
# 定义三个属性,值,后继节点,前继节点
self.item = item
self.next = None
self.prev = None
class DLinkList(object):
"""双向链表"""
def __init__(self):
# head存放单链表首节点地址
self.head = None
def is_empty(self):
"""判断链表是否为空"""
return self.head == None
def length(self):
"""计算链表长度"""
cur = self.head
count = 0
# 当未到达尾部时
while cur:
cur = cur.next
count += 1
return count
def travel(self):
"""遍历链表"""
cur = self.head
while cur:
print(cur.item)
cur = cur.next
def add(self,item):
"""头部插入元素"""
# 先新建一个节点
node = SingleNode(item)
# 新节点的尾部指向原首节点
if self.is_empty():
self.head = node
else:
node.next = self.head
# 原首节点的前继节点 为新节点
self.head.prev = node
# 新首节点为新建节点
self.head = node
def append(self,item):
"""尾部插入元素"""
# 新建节点
node = SingleNode(item)
# 先判断链表是否为空,若是空链表,则将_head指向新节点
if self.is_empty():
self.head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.head
while cur.next:
cur = cur.next
# 找到最后一个节点,最后一个节点的next为新节点
cur.next = node
# 新节点的prev为原尾节点
node.prev = cur
def search(self,item):
"""查找某个节点是否存在"""
cur = self.head
while cur:
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():
self.append(item)
# 在中间插入
else:
# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
pre = self.head
count = 0
node = SingleNode(item)
while count < pos-1:
pre = pre.next
count += 1
# 先将新节点node的next指向插入位置的节点
node.next = pre.next
pre.next.prev = node
# 将插入位置的前一个节点的next指向新节点
pre.next = node
node.prev = pre
def remove(self,item):
"""删除节点"""
# pre 存着指定item的前一个节点
pre = None
cur = self.head
while cur:
if cur.item != item:
pre = cur
cur = cur.next
else:
# 如果item是首节点,则将头指针指向头节点的后一个节点
if pre == None:
self.head = cur.next
cur.next.prev = None
# 否则item是中间节点,将删除位置前一个节点的next指向删除位置的后一个节点
else:
pre.next = cur.next
cur.next.prev = pre
break
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()
length: 6
6
2
1
4
3
5
True
True
length: 5
6
2
4
3
5