文章目录
前言
本文为7月11日Python数据结构与算法学习笔记,分为五个章节:
- 双向链表;
- 单向循环链表;
- 栈(stack);
- 队列(queue);
- 双端队列(double-ended queue)。
一、双向链表
- 每个节点有两个链接:一个指向前一个节点,另一个指向下一个节点;
- 当此节点为第一个节点时,前一个链接指向空值;
- 当此节点为最后一个节点时,后一个链接指向空值。
1、双向链表代码实现
- 创建节点:
class Node(object):
''' 定义节点 '''
def __init__(self, elem):
self.elem = elem
self.next = None
self.prev = None
- 创建双向链表:
class DoubleLinkList(object):
''' 定义双向链表 '''
def __init__(self, node=None):
self.__head = node
- 判断链表是否为空:
def is_empty(self):
''' 链表是否为空 '''
return self.__head is 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 != 0:
print(cur.elem, end=" ")
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 移动到链表尾部
cur = self.__head
while cur.next != None:
cur = cur.next
# 将尾节点的 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
2、在指定位置添加元素
def insert(self, pos, item):
''' 指定位置添加元素 '''
if pos <= 0:
self.add(item)
elif pos > (self.length()-1):
self.append(item)
else:
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
# 循环推出后,cur 指向 pos 的位置
node = Node(item)
node.next = cur
node.prev = cur.prev
cur.prev.next = node
cur.prev = node
3、删除元素
def remove(self, item):
''' 删除节点 '''
cur = self.__head
while cur != None:
if cur.elem == item:
# 判断此节点是否为头节点
# 若是
if cur == self.__head:
self.__head = cur.next
if cur.next:
# 判断链表是否只有一个节点
cur.next.prev = None
else:
cur.prev.next = cur.next
if cur.next:
cur.next.prev = cur.prev
break
else:
cur = cur.next
4、测试
if __name__ == "__main__":
ll = DoubleLinkList()
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()
二、单向循环链表
- 单向循环链表的变形;
- 链表中最后一个节点的next域不再为None,而是指向链表的头节点。
1、单向循环链表代码实现
- 创建节点:
class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem
self.next = None # next:下一个节点的标识
- 创建单向循环链表:
class SingleCycleList(object):
"""单向循环链表"""
def __init__(self, node=None):
self.__head = node
if node:
node.next = node
- 判断链表是否为空:
def is_empty(self):
"""链表是否为空"""
return self.__head == None
- 返回链表的长度:
def length(self):
"""链表长度"""
if self.is_empty():
return 0
# cur游标,用来移动遍历节点
cur = self.__head
# count记录数量
count = 1
while cur.next != self.__head:
count += 1
cur = cur.next
return count
- 遍历链表:
def travel(self):
"""遍历整个链表"""
if self.is_empty():
return
cur = self.__head
while cur.next != self.__head:
print(cur.elem, end=" ")
cur = cur.next
# 退出循环时,cur 指向尾节点,但尾节点的元素未打印
print(cur.elem, end="\n")
- 头部添加节点:
def add(self, item):
"""链表头部添加元素,头插法"""
# 先找到尾节点
node = Node(item)
if self.is_empty():
self.__head = node
node.next = node
else:
cur = self.__head
while cur.next != self.__head:
cur = cur.next
# 退出循环时,cur 指向尾节点,
node.next = self.__head
self.__head = node
cur.next = node
- 尾部添加节点:
def append(self, item):
"""链表尾部添加元素, 尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
node.next = node
else:
cur = self.__head
while cur.next != self.__head:
cur = cur.next
node.next = cur.next
cur.next = node
- 在指定位置添加节点:
def insert(self, pos, item):
"""指定位置添加元素
:param pos 从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length()-1):
self.append(item)
else:
pre = self.__head
count = 0
while count < (pos-1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1位置
node = Node(item)
node.next = pre.next
pre.next = node
- 删除一个节点:
def remove(self, item):
"""删除节点"""
if self.is_empty():
return
cur = self.__head
pre = None
while cur.next != self.__head:
if cur.elem == item:
# 先判断此结点是否是头节点
# 头节点
if cur == self.__head:
# 先找到尾节点
rear = self.__head
while rear.next != self.__head:
rear = rear.next
self.__head = cur.next
rear.next = self.__head
else:
# 中间节点
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
# 退出循环时,cur 指向尾节点
if cur.elem == item:
if cur == self.__head:
# 链表中只有一个节点
self.__head = None
else:
pre.next = cur.next
- 查找节点是否存在:
def search(self, item):
"""查找节点是否存在"""
if self.is_empty():
return False
cur = self.__head
while cur.next != self.__head:
if cur.elem == item:
return True
else:
cur = cur.next
# 退出循环时,cur 指向尾节点
if cur.elem == item:
return True
return False
- 测试:
if __name__ == "__main__":
ll = SingleCycleList()
print(ll.is_empty())
print(ll.length())
ll.append(1)
print(ll.is_empty())
print(ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
# 8 1 2 3 4 5 6
ll.insert(-1, 9) # 9 8 1 23456
ll.travel()
ll.insert(3, 100) # 9 8 1 100 2 3456
ll.travel()
ll.insert(10, 200) # 9 8 1 100 23456 200
ll.travel()
ll.remove(100)
ll.travel()
ll.remove(9)
ll.travel()
ll.remove(200)
ll.travel()
>>> 9 8 1 2 3 4 5 6
>>> 9 8 1 100 2 3 4 5 6
>>> 9 8 1 100 2 3 4 5 6 200
>>> 9 8 1 2 3 4 5 6 200
>>> 8 1 2 3 4 5 6 200
>>> 8 1 2 3 4 5 6
三、栈(stack)
- 一种容器;
- 只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算;
- 后进先出(LIFO: Last In First Out)。
栈结构的实现:
class Stack(object):
''' 栈 '''
def __init__(self):
self.__list = []
def push(self, item):
''' 添加新元素 item 到栈顶 '''
self.__list.append(item)
def pop(self):
''' 弹出栈顶元素 '''
return self.__list.pop()
def peek(self):
''' 返回栈顶元素 '''
if self.__list:
return self.__list[-1]
else:
return None
def is_empty(self):
''' 判断栈是否为空 '''
return self.__list is []
def size(self):
''' 返回栈的元素个数 '''
return len(self.__list)
if __name__ == "__main__":
s = Stack()
s.push(1)
s.push(2)
s.push(3)
s.push(4)
print(s.pop())
print(s.pop())
print(s.pop())
print(s.pop())
>>> 4
>>> 3
>>> 2
>>> 1
四、队列(queue)
- 只允许在一端进行插入操作,而在另一端进行删除操作的线性表;
- 先进先出的(FIFO: First In First Out)。
队列的实现:
class Queue(object):
''' 队列 '''
def __init__(self):
self.__list = []
def enqueue(self, item):
''' 添加 item 元素 '''
self.__list.append(item)
def dequeue(self):
''' 从队列头部删除一个元素 '''
return self.__list.pop(0)
def is_empty(self):
''' 判断队列是否为空 '''
return self.__list is []
def size(self):
''' 返回队列的大小 '''
return len(self.__list)
if __name__ == "__main__":
s = Queue()
s.enqueue(1)
s.enqueue(2)
s.enqueue(3)
s.enqueue(4)
print(s.dequeue())
print(s.dequeue())
print(s.dequeue())
print(s.dequeue())
>>> 1
>>> 2
>>> 3
>>> 4
五、双端队列(double-ended queue)
- 元素可以从两端弹出;
- 其限定插入和删除操作在表的两端进行。
双端队列的实现:
class Deque(object):
''' 双端队列 '''
def __init__(self):
self.__list = []
def add_front(self, item):
''' 添加 item 元素 '''
self.__list.insert(0, item)
def add_rear(self, item):
''' 添加 item 元素 '''
self.__list.append(item)
def pop_front(self):
''' 从队列头部删除一个元素 '''
return self.__list.pop(0)
def pop_rear(self):
''' 从队列头部删除一个元素 '''
return self.__list.pop()
def is_empty(self):
''' 判断队列是否为空 '''
return self.__list is []
def size(self):
''' 返回队列的大小 '''
return len(self.__list)
if __name__ == "__main__":
s = Deque()
s.add_front(1)
s.add_front(2)
s.add_rear(3)
s.add_rear(4)
print(s.size())
print(s.pop_front())
print(s.pop_front())
print(s.pop_rear())
print(s.pop_rear())
>>> 4
>>> 2
>>> 1
>>> 4
>>> 3