文章目录
一、双向链表的定义、判断是否为空、长度&遍历
1.定义
单向链表只有一个方向,每个节点只有一个后继节点next指向下一个节点;
双向链表支持两个方向,每个节点不止有一个后继指针next指向后面的节点,还有一个前驱指针prev指向前面的节点。
双向链表占内存更大,用空间换时间
。
当前节点的前一个节点称为前驱结点,后一个节点称为后继节点。
双向链表的示意图
2.is_empty():
def is_empty(self):
'''判断是否为空'''
return self.__head == None
3.length():
count = 0开始计时,循环条件和单链表一样,即cur != None
。
def length(self):
'''链表长度'''
#判断是否为空链表
if self.is_empty():
return 0
# cur即游标,指向首节点,用来遍历
cur = self.__head
count = 0
# 当未到达尾部时
while cur != None:
count += 1
# 将游标向后移动一位
cur = cur.next
return count
4.travel():
循环条件是cur != None
。
def travel(self):
'''遍历链表'''
#链表为空时
if self.is_empty():
return
cur = self.__head
while cur != None:
print(cur.item, end=' ')
cur = cur.next
二、双向链表的插入
1.add():
新节点的next指向首节点node.next = self.__head
;
原来头节点指向新节点(实现双向)self.__head.prev = node
;
__head指向新节点self.__head = node
。
def add(self, item):
'''链表头部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
# 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
if self.is_empty():
self.__head = node
#若不为空
else:
#将node的next指向__head的头节点
node.next = self.__head
#将__head的prev指向node
self.__head.prev = node
#将__haed指向node
self.__head = node
2.append()
遍历找到尾节点
循环条件:while cur.next != None
尾节点指向新节点:cur.next = node
新节点的prev指向cur:node.prev = cur
。
def append(self, item):
'''链表尾部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
#判断是否为空链表
if self.is_empty():
self.__head = node
node.next = self.__head # 等价于node.next = node
else:
cur = self.__head
# 找到尾节点
while cur.next != None:
cur = cur.next
# 尾节点指向新节点
cur.next = node
#新节点的prev指向cur
node.prev = cur
3.insert()
双向链表不需要pre指针。
将node的prev指向cur:node.prev = cur
;
将node的nextcur的下一个节点:node.next = cur.next
;
将cur的下一个节点的prev指向node:cur.next.prev = node
;
将cur的下一个节点指向node:cur.next = node
。
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的nextcur的下一个节点(与前一步顺序可换)
node.next = cur.next
#将cur的下一个节点的prev指向node
cur.next.prev = node
#将cur的下一个节点指向node
cur.next = node
插入操作
三、双向链表的查找、删除
1.查找
def search(self, item):
'''查找节点是否存在'''
if self.is_empty():
return False
cur = self.__head
while cur != None:
# 判断第一个节点
if cur.item == item:
return True
# 未找到,继续向后移动
else:
cur = cur.next
return False
2.删除
如果首结点的元素就是要删除的元素:
链表中只有一个节点:self.__head = None
链表中有多个节点:cur.next.prev = None
,self.__head = cur.next
。
如果首结点的元素不是要删除的元素:cur.next.prev = cur.prev
,cur.prev.next = cur.next
;
def remove(self, item):
'''删除节点'''
#如果链表为空,直接返回
if self.is_empty():
return
else:
cur = self.__head
pre = None
#头节点的元素就是要删除的元素
if cur.item == item:
#链表中只有一个节点
if cur == None:
self.__head = None
#有多个节点
else:
cur.next.prev = None
self.__head = cur.next
return
#头节点不是要删除的元素
while cur != None:
if cur.item == item:
#删除
if cur.next:
cur.next.prev = cur.prev
cur.prev.next = cur.next
break
cur = cur.next
删除操作
整个双向链表的实现如下,
class Node(object):
'''节点'''
def __init__(self,item):
'''初始化'''
self.item = item
#next是下一个节点的标识
self.next = None
#prev是上一个节点的标识
self.prev = None
class DoubleLinkList(object):
'''双向链表'''
def __init__(self,node = None):
self.__head = node
def is_empty(self):
'''判断是否为空'''
return self.__head == None
def length(self):
'''链表长度'''
#判断是否为空链表
if self.is_empty():
return 0
# cur即游标,指向首节点,用来遍历
cur = self.__head
count = 0
# 当未到达尾部时
while cur != None:
count += 1
# 将游标向后移动一位
cur = cur.next
return count
def travel(self):
'''遍历链表'''
#链表为空时
if self.is_empty():
return
cur = self.__head
while cur != None:
print(cur.item, end=' ')
cur = cur.next
def add(self, item):
'''链表头部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
# 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
if self.is_empty():
self.__head = node
#若不为空
else:
#将node的next指向__head的头节点
node.next = self.__head
#将__head的prev指向node
self.__head.prev = node
#将__haed指向node
self.__head = node
def append(self, item):
'''链表尾部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
#判断是否为空链表
if self.is_empty():
self.__head = node
node.next = self.__head # 等价于node.next = node
else:
cur = self.__head
# 找到尾节点
while cur.next != None:
cur = cur.next
# 尾节点指向新节点
cur.next = node
#新节点的prev指向cur
node.prev = cur
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的nextcur的下一个节点(与前一步顺序可换)
node.next = cur.next
#将cur的下一个节点的prev指向node
cur.next.prev = node
#将cur的下一个节点指向node
cur.next = node
def remove(self, item):
'''删除节点'''
#如果链表为空,直接返回
if self.is_empty():
return
else:
cur = self.__head
pre = None
#头节点的元素就是要删除的元素
if cur.item == item:
#链表中只有一个节点
if cur == None:
self.__head = None
#有多个节点
else:
cur.next.prev = None
self.__head = cur.next
return
#头节点不是要删除的元素
while cur != None:
if cur.item == item:
#删除
if cur.next:
cur.next.prev = cur.prev
cur.prev.next = cur.next
break
cur = cur.next
def search(self, item):
'''查找节点是否存在'''
if self.is_empty():
return False
cur = self.__head
while cur != None:
# 判断第一个节点
if cur.item == item:
return True
# 未找到,继续向后移动
else:
cur = cur.next
return False
if __name__ == '__main__':
d = DoubleLinkList()
print(d.is_empty())
print(d.length())
d.travel()
d.add(1)
d.add(2)
d.add(3)
d.append(4)
d.append(5)
d.append(6)
d.travel()
d.insert(-1,7)
d.insert(3,8)
d.insert(10,9)
d.travel()
print(d.search(3))
print(d.search(10))
d.remove(2)
d.remove(100)
d.travel()
进行测试,结果如下,
True
0
3 2 1 3 2 1 4 5 6 7 3 2 8 1 4 5 6 9 True
False
7 3 8 1 4 5 6 9
四、栈的实现
1.定义
栈:后进先出,先进后出,只能在栈顶入或者出。
栈是一种“操作受限”的线性表,只允许在一端插入和删除数据,在满足先进后出、后进先出的特性时,应该使用栈。
如图,
2.实现
用顺序表实现的栈成为顺序栈,用链表实现的栈叫做链式栈。
顺序栈的实现相对简单,因为对于栈的操作可以通过对顺序表的操作方法实现,不用自己定义,直接调用即可,相对简单。
整个栈的实现如下,
class Stack(object):
'''栈,用列表的方法实现'''
def __init__(self):
self.__items = []
def is_empty(self):
'''判断栈是否为空'''
return self.__items == []
def push(self,item):
'''添加一个新的元素item到栈顶'''
self.__items.append(item)
def pop(self):
'''弹出栈顶元素'''
return self.__items.pop()
def peek(self):
'''返回栈顶元素'''
#判断是否为空
if self.is_empty():
return None
else:
return self.__items[-1]
def size(self):
'''返回栈的元素个数'''
return len(self.__items)
def travel(self):
'''遍历'''
for item in self.__items:
print(item)
if __name__ == '__main__':
s = Stack()
s.push(1)
s.push(2)
s.push(3)
s.pop()
print(s.size())
print(s.is_empty())
print(s.peek())
s.travel()
并进行测试,结果如下,
2
False
2
1
2
3.简单应用:
浏览器的前进后退:
当你依次访问完一串页面a-b-c之后,点击浏览器的后退按钮,就可以查看之前浏览过的页面b和a。当你后退到页面a,点击前进按钮,就可以重新查看页面b和c。但是,如果你后退到页面b后,点击了新的页面d,那就无法再通过前进、后退功能查看页面c了。
如图,
大家也可以关注我的公众号:Python极客社区,在我的公众号里,经常会分享很多Python的文章,而且也分享了很多工具、学习资源等。另外回复“电子书”还可以获取十本我精心收集的Python电子书。