在编程中,数据结构和算法是我们处理数据的基础工具。了解常用的数据结构和算法,能够帮助我们更高效地存储、操作和查找数据。本文将介绍Python中的常见数据结构(如列表、元组、字典、集合等)、常用的线性数据结构(栈、队列、链表)以及基本的排序和查找算法,帮助你掌握如何在不同场景中选择合适的数据结构和算法。
1. 列表、元组、字典、集合的应用
1.1 列表(List)
列表是Python中最常用的数据结构之一,它是一个有序的元素集合,可以包含任意类型的数据。列表是可变的,可以动态地修改。
- 创建列表 :通过
[]
或者list()
函数创建。 - 访问列表元素:可以通过索引访问列表中的元素。
- 修改列表 :可以通过索引修改列表中的元素,或者使用
append()
、extend()
、insert()
等方法。 - 删除元素 :可以使用
remove()
、pop()
或者del
。
python
# 创建列表
fruits = ["apple", "banana", "cherry"]
# 访问元素
print(fruits[0]) # 输出:apple
# 修改元素
fruits[1] = "blueberry"
# 删除元素
fruits.remove("cherry")
# 输出修改后的列表
print(fruits) # 输出:['apple', 'blueberry']
1.2 元组(Tuple)
元组是一个不可变的序列,类似于列表,但是一旦创建就不能修改。适合存储不需要更改的数据。
- 创建元组 :通过
()
创建。 - 访问元组元素:可以通过索引访问元组中的元素。
python
# 创建元组
coordinates = (10, 20, 30)
# 访问元素
print(coordinates[1]) # 输出:20
1.3 字典(Dictionary)
字典是一个无序的键值对集合,每个键对应一个值。字典是可变的,适合用来存储具有映射关系的数据。
- 创建字典 :通过
{}
或者dict()
函数创建。 - 访问元素:可以通过键来访问字典中的值。
- 添加和修改元素:可以通过键来添加或者修改字典中的值。
python
# 创建字典
person = {"name": "Alice", "age": 25}
# 访问元素
print(person["name"]) # 输出:Alice
# 修改元素
person["age"] = 26
# 添加元素
person["city"] = "New York"
# 输出修改后的字典
print(person) # 输出:{'name': 'Alice', 'age': 26, 'city': 'New York'}
1.4 集合(Set)
集合是一个无序的、不重复的元素集合。集合适用于去重、集合运算等操作。
- 创建集合 :通过
{}
或者set()
函数创建。 - 操作集合:可以进行并集、交集、差集等操作。
python
# 创建集合
fruits = {"apple", "banana", "cherry"}
# 添加元素
fruits.add("orange")
# 删除元素
fruits.remove("banana")
# 输出集合
print(fruits) # 输出:{'apple', 'cherry', 'orange'}
2. 常用数据结构:栈、队列、链表
2.1 栈(Stack)
栈是一种后进先出(LIFO,Last In First Out)结构。栈的操作主要包括:
- 压栈(push):将元素添加到栈顶。
- 弹栈(pop):移除并返回栈顶的元素。
- 查看栈顶元素(peek):获取栈顶元素,但不移除它。
python
stack = []
# 压栈
stack.append(1)
stack.append(2)
stack.append(3)
# 弹栈
top = stack.pop()
print(top) # 输出:3
# 查看栈顶元素
print(stack[-1]) # 输出:2
2.2 队列(Queue)
队列是一种先进先出(FIFO,First In First Out)结构。队列的操作主要包括:
- 入队(enqueue):将元素添加到队尾。
- 出队(dequeue):移除并返回队头的元素。
python
from collections import deque
queue = deque()
# 入队
queue.append(1)
queue.append(2)
queue.append(3)
# 出队
front = queue.popleft()
print(front) # 输出:1
2.3 链表(Linked List)
链表是一种线性数据结构,每个元素包含数据和指向下一个元素的指针。Python没有内建的链表类型,但可以通过类和节点来实现。
python
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
last_node = self.head
while last_node.next:
last_node = last_node.next
last_node.next = new_node
def print_list(self):
current_node = self.head
while current_node:
print(current_node.data, end=" -> ")
current_node = current_node.next
print("None")
# 创建链表
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.print_list() # 输出:1 -> 2 -> 3 -> None
3. 排序算法:冒泡排序、选择排序、插入排序
3.1 冒泡排序(Bubble Sort)
冒泡排序是一种简单的排序算法,它重复地遍历待排序的列表,比较相邻元素并交换它们的位置,直到没有需要交换的元素为止。
python
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
arr = [64, 34, 25, 12, 22, 11, 90]
bubble_sort(arr)
print(arr) # 输出:[11, 12, 22, 25, 34, 64, 90]
假设我们有一个列表:[64, 34, 25, 12, 22, 11, 90],我们将通过多次交换过程直观地展示如何排序。
步骤 1: 初始列表
[64, 34, 25, 12, 22, 11, 90]
步骤 2: 第一轮遍历,比较相邻元素并交换:
- 64 > 34 → 交换:[34, 64, 25, 12, 22, 11, 90]
- 64 > 25 → 交换:[34, 25, 64, 12, 22, 11, 90]
- 64 > 12 → 交换:[34, 25, 12, 64, 22, 11, 90]
- 64 > 22 → 交换:[34, 25, 12, 22, 64, 11, 90]
- 64 > 11 → 交换:[34, 25, 12, 22, 11, 64, 90]
- 64 < 90 → 不交换。
第一轮遍历后:
[34, 25, 12, 22, 11, 64, 90]
在这一轮中,最大的元素90已经被移动到了最后。
步骤 3: 第二轮遍历:
- 34 > 25 → 交换:[25, 34, 12, 22, 11, 64, 90]
- 34 > 12 → 交换:[25, 12, 34, 22, 11, 64, 90]
- 34 > 22 → 交换:[25, 12, 22, 34, 11, 64, 90]
- 34 > 11 → 交换:[25, 12, 22, 11, 34, 64, 90]
- 34 < 64 → 不交换。
第二轮遍历后:
[25, 12, 22, 11, 34, 64, 90]
这个过程会继续进行,直到列表完全有序。最终结果会是:
[11, 12, 22, 25, 34, 64, 90]
总结
冒泡排序每次遍历时都将最大的元素"冒泡"到列表的末尾,因此其最坏时间复杂度是 O(n²)。对于较大的数据集,冒泡排序效率较低。
3.2 选择排序(Selection Sort)
选择排序每次从未排序的部分中选择最小(大)元素,并将其放到已排序部分的末尾。
python
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i+1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
arr = [64, 34, 25, 12, 22, 11, 90]
selection_sort(arr)
print(arr) # 输出:[11, 12, 22, 25, 34, 64, 90]
假设我们有一个列表:[64, 34, 25, 12, 22, 11, 90],我们将通过每一轮选择最小元素并交换的位置来直观展示排序过程。
步骤 1: 初始列表
[64, 34, 25, 12, 22, 11, 90]
步骤 2: 找到最小的元素(11),并与第一个元素(64)交换:
[11, 34, 25, 12, 22, 64, 90]
步骤 3: 在剩下的部分(34, 25, 12, 22, 64, 90)中找到最小的元素(12),并与第二个元素(34)交换:
[11, 12, 25, 34, 22, 64, 90]
步骤 4: 在剩下的部分(25, 34, 22, 64, 90)中找到最小的元素(22),并与第三个元素(25)交换:
[11, 12, 22, 34, 25, 64, 90]
步骤 5: 在剩下的部分(34, 25, 64, 90)中找到最小的元素(25),并与第四个元素(34)交换:
[11, 12, 22, 25, 34, 64, 90]
步骤 6: 在剩下的部分(34, 64, 90)中找到最小的元素(34),不需要交换,因为它已经在正确的位置:
[11, 12, 22, 25, 34, 64, 90]
步骤 7: 在剩下的部分(64, 90)中找到最小的元素(64),不需要交换:
[11, 12, 22, 25, 34, 64, 90]
最终,排序完成:
[11, 12, 22, 25, 34, 64, 90]
总结
选择排序每一轮选择最小元素,因此最坏时间复杂度是 O(n²)。尽管它的实现简单,但其效率在数据量大时不高。
3.3 插入排序(Insertion Sort)
插入排序通过逐步将未排序的元素插入到已排序的部分,直到整个列表有序。
python
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
arr = [64, 34, 25, 12, 22, 11, 90]
insertion_sort(arr)
print(arr) # 输出:[11, 12, 22, 25, 34, 64, 90]
假设我们有一个列表:[64, 34, 25, 12, 22, 11, 90],我们将通过每一轮插入元素并移动的过程来直观展示排序。
步骤 1: 初始列表
[64, 34, 25, 12, 22, 11, 90]
步骤 2: 将第二个元素(34)插入到已排序部分([64]):
-
34 小于 64,所以将 64 向后移动,将 34 插入到位置 0:
[34, 64, 25, 12, 22, 11, 90]
步骤 3: 将第三个元素(25)插入到已排序部分([34, 64]):
-
25 小于 64,先将 64 向后移动,再将 25 小于 34,所以将 34 向后移动,将 25 插入到位置 0:
[25, 34, 64, 12, 22, 11, 90]
步骤 4: 将第四个元素(12)插入到已排序部分([25, 34, 64]):
-
12 小于 64,34,25,所以将它们依次向后移动,将 12 插入到位置 0:
[12, 25, 34, 64, 22, 11, 90]
步骤 5: 将第五个元素(22)插入到已排序部分([12, 25, 34, 64]):
-
22 小于 64、34、25,所以将它们依次向后移动,将 22 插入到位置 1:
[12, 22, 25, 34, 64, 11, 90]
步骤 6: 将第六个元素(11)插入到已排序部分([12, 22, 25, 34, 64]):
-
11 小于 64、34、25、22、12,所以将它们依次向后移动,将 11 插入到位置 0:
[11, 12, 22, 25, 34, 64, 90]
步骤 7: 最后一个元素(90)已经是有序的,无需插入:
[11, 12, 22, 25, 34, 64, 90]
总结
插入排序在数据量小的时候效率较高,尤其是当数据几乎有序时,插入排序能表现出接近 O(n) 的效率。最坏时间复杂度是 O(n²)。
4. 查找算法:线性查找与二分查找
4.1 线性查找(Linear Search)
线性查找是最简单的查找算法,它通过逐个遍历列表来查找目标元素。
python
def linear_search(arr, target):
for
i, value in enumerate(arr):
if value == target:
return i
return -1
arr = [64, 34, 25, 12, 22, 11, 90]
index = linear_search(arr, 22)
print(index) # 输出:4
4.2 二分查找(Binary Search)
二分查找是一种高效的查找方法,前提是数据必须是已排序的。它通过将列表分为两半来逐步缩小查找范围。
python
def binary_search(arr, target):
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
arr = [11, 12, 22, 25, 34, 64, 90]
index = binary_search(arr, 22)
print(index) # 输出:2
生活就是这样,脚长在自己身上,往前走就对了,直到向往的风景,变成走过的地方