1. 栈和队列
1.1 栈
栈是一种后进先出(LIFO)的数据结构,可以在栈顶进行插入和删除元素。
栈的具体实现有多种方式,其中最常见的是使用数组或链表来存储元素。
我们先来看一个使用数组实现的简单例子:
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def is_empty(self):
return len(self.items) == 0
def peek(self):
return self.items[-1]
def size(self):
return len(self.items)
通过上面的代码,我们可以实现一个栈的基本功能:
push(item)方法:将元素添加到栈顶。
pop()方法:将栈顶元素删除并返回。
is_empty()方法:判断栈是否为空。
peek()方法:返回栈顶元素,但不删除。
size()方法:返回栈的大小。
我们可以使用上面的例子来进行一些简单的栈操作。
例如,我们可以使用栈来实现表达式求解:
def evaluate_expression(expression):
stack = Stack()
for char in expression:
if char.isdigit():
stack.push(int(char))
else:
a = stack.pop()
b = stack.pop()
result = calculate(a, b, char)
stack.push(result)
return stack.pop()
def calculate(a, b, operator):
if operator == '+':
return a + b
elif operator == '-':
return b - a
elif operator == '*':
return a * b
elif operator == '/':
return b / a
在上面的程序中,我们首先定义了一个栈。我们遍历整个表达式,当遇到数字时,我们将其压入栈中;当遇到操作符时,我们从栈中取出两个数,并进行计算,计算结果再压入栈中。当遍历完整个表达式后,栈中只剩下一个元素,即表达式的最终结果。
1.2 队列
队列是一种先进先出(FIFO)的数据结构,可以在队尾添加元素,在队头删除元素。
队列的具体实现也有多种方式,其中最常见的是使用数组或链表来存储元素。下面是一个使用链表实现队列的例子:
class Node:
def __init__(self, value):
self.value = value
self.next = None
class Queue:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def is_empty(self):
return self.size == 0
def enqueue(self, value):
new_node = Node(value)
if self.size == 0:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.size += 1
def dequeue(self):
if self.size == 0:
raise Exception("Queue is empty.")
value = self.head.value
self.head = self.head.next
self.size -= 1
if self.size == 0:
self.tail = None
return value
def peek(self):
if self.size == 0:
raise Exception("Queue is empty.")
return self.head.value
def __len__(self):
return self.size
通过上面的代码,我们可以实现一个队列的基本功能:
enqueue(item)方法:将元素添加到队尾。
dequeue()方法:将队头元素删除并返回。
is_empty()方法:判断队列是否为空。
peek()方法:返回队头元素,但不删除。
__len__()方法:返回队列的大小。
我们可以使用上面的例子来进行一些简单的队列操作。
例如,我们可以使用队列来实现广度优先搜索(BFS):
def bfs(graph, start):
visited = [False] * len(graph)
queue = Queue()
queue.enqueue(start)
visited[start] = True
while not queue.is_empty():
node = queue.dequeue()
print(node)
for neighbor in graph[node]:
if not visited[neighbor]:
queue.enqueue(neighbor)
visited[neighbor] = True
在上面的程序中,我们首先将起始节点加入队列中,并将它标记为已访问。然后,我们使用while循环从队列中取出一个节点,并将其打印出来。然后,我们遍历该节点的所有邻居节点,如果邻居节点还没有被访问,就将它加入队列中,并标记为已访问。
2. 树
2.1 二叉树
树是一种非线性的数据结构,可以用来表示具有层次关系的数据。树的结构非常重要,在计算机科学中有广泛的应用,例如二叉搜索树和红黑树。
二叉树是一种最简单的树形结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。
我们可以使用以下代码来实现一个二叉树的节点:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
通过上面的代码,我们定义了一个名为TreeNode的类,该类的实例具有三个属性:
value:节点的值。
left:左子节点。
right:右子节点。
我们可以使用上面的例子来进行一些简单的二叉树操作。
例如,我们可以使用二叉树来实现二叉搜索树:
class BST:
def __init__(self):
self.root = None
def insert(self, value):
if self.root is None:
self.root = TreeNode(value)
else:
self._insert(value, self.root)
def _insert(self, value, node):
if value < node.value:
if node.left is None:
node.left = TreeNode(value)
else:
self._insert(value, node.left)
elif value > node.value:
if node.right is None:
node.right = TreeNode(value)
else:
self._insert(value, node.right)
def search(self, value):
if self.root is None:
return False
else:
return self._search(value, self.root)
def _search(self, value, node):
if node is None:
return False
elif value == node.value:
return True
elif value < node.value:
return self._search(value, node.left)
else:
return self._search(value, node.right)
在上面的程序中,我们首先定义了一个BST类,通过插入节点来建立二叉搜索树。对于每个节点,如果它的值小于当前节点的值,则在左子树中插入该节点,否则在右子树中插入该节点。
我们还可以使用递归来实现二叉树的遍历操作,包括前序遍历、中序遍历和后序遍历:
class BST:
# ...
def preorder(self, node):
if node is None:
return
print(node.value)
self.preorder(node.left)
self.preorder(node.right)
def inorder(self, node):
if node is None:
return
self.inorder(node.left)
print(node.value)
self.inorder(node.right)
def postorder(self, node):
if node is None:
return
self.postorder(node.left)
self.postorder(node.right)
print(node.value)
在上面的程序中,我们分别定义了前序、中序和后序遍历的方法。其中,前序遍历的顺序是根节点→左子节点→右子节点;中序遍历的顺序是左子节点→根节点→右子节点;后序遍历的顺序是左子节点→右子节点→根节点。
2.2 堆
堆是一种可以迅速找到最大值或最小值的数据结构,常常用于实现优先队列。
堆分为两种类型,最大堆和最小堆。最大堆要求每个节点的值都大于等于其子节点的值,而最小堆要求每个节点的值都小于等于其子节点的值。
下面是一个使用数组实现最小堆的例子:
class MinHeap:
def __init__(self):
self.items = []
def push(self, value):
self.items.append(value)
self._up(len(self.items) - 1)
def pop(self):
value = self.items[0]
self.items[0] = self.items[-1]
self.items.pop()
if len(self.items) > 0:
self._down(0)
return value
def _up(self, index):
parent_index = (index - 1) // 2
if parent_index >= 0 and self.items[parent_index] > self.items[index]:
self.items[parent_index], self.items[index] = self.items[index], self.items[parent_index]
self._up(parent_index)
def _down(self, index):
child_index = 2 * index + 1
if child_index >= len(self.items):
return
if child_index + 1 < len(self.items) and self.items[child_index + 1] < self.items[child_index]:
child_index += 1
if self.items[index] > self.items[child_index]:
self.items[index], self.items[child_index] = self.items[child_index], self.items[index]
self._down(child_index)
通过上面的代码,我们定义了一个名为MinHeap的类,该类的实例具有三个方法:
push(value)方法:将元素添加到堆中。
pop()方法:将堆顶元素删除并返回。
_up(index)方法:上移操作,对于给定的索引,将其与其父节点进行比较,如果它的值小于父节点,则交换两者的位置,并继续向上比较。
_down(index)方法:下移操作,对于给定的索引,将其与其较小的子节点进行比较,如果它的值大于子节点,则交换两者的位置,并继续向下比较。
我们可以使用上面的例子来进行一些简单的堆操作。
例如,我们可以使用堆来实现Top k问题:
def top_k(items, k):
heap = MinHeap()
for item in items:
heap.push(item)
if len(heap.items) > k:
heap.pop()
return heap.items
在上面的程序中,我们首先定义了一个MinHeap类,然后使用该类来实现Top k问题。我们遍历整个列表,并将列表中的每个元素加入堆中。当堆的大小超过k时,我们将堆顶元素弹出,并继续遍历剩下的元素。遍历完整个列表后,堆中的元素即为前k大的元素。
3. 字典和集合
3.1 字典
字典是一种键值对的数据结构,可以用于存储非序列化的数据。字典中的键必须是不可变的类型,如字符串、数字或元组等。
我们可以使用以下代码来创建一个字典:
person = {'name': 'Tom', 'age': 20, 'gender': 'male'}
通过上面的代码,我们定义了一个名为person的字典,它包含三个键值对,分别是'name'、'age'和'gender'。
我们可以使用以下代码来访问字典中的元素:
print(person['name']) # 输出'Tom'
通过上面的代码,我们访问了字典中键为'name'的元素,并将其打印出来。
我们还可以使用以下代码来遍历字典:
for key in person:
print(key, person[key])
通过上面的代码,我们遍历了字典中的所有键并将它们打印出来。
3.2 集合
集合是一种无序、唯一元素的数据结构,可以用于去重和集合运算等操作。
我们可以使用以下代码来创建一个集合:
colors = {'red', 'green', 'blue'}
通过上面的代码,我们定义了一个名为colors的集合,它包含三个元素,分别是'red'、'green'和'blue'。
我们可以使用以下代码来访问集合中的元素:
if 'red' in colors:
print('red in colors')
通过上面的代码,我们判断了'red'是否在集合colors中,如果是,则打印出'red in colors'。
我们还可以使用以下代码来对集合进行基本的集合运算:
s1 = {1, 2, 3}
s2 = {2, 3, 4}
print(s1 | s2) # 输出'{1, 2, 3, 4}'
print(s1 & s2) # 输出'{2, 3}'
print(s1 - s2) # 输出'{1}'
通过上面的代码,我们分别对集合s1和s2进行了并集、交集和差集操作,并将结果打印出来。
4. 总结
本文介绍了Python中常用的数据结构,包括栈、队列、二叉树、堆、字典和集合。这些数据结构是计算机科学