前言
作者主页:涛哥聊Python
个人网站:涛哥聊Python
大家好,我是涛哥。
今天为大家分享Python常用算法合集,以及各算法的代码示例!还会给大家赠送荣获CSDN“程序员IT好书评选”奖的《labuladong 算法小抄》,记得领取哦!
一、排序算法
1,冒泡排序
该算法从列表的第一个元素开始,比较相邻的两个元素,如果它们顺序不正确就交换它们,然后继续比较下一对相邻元素,直到遍历整个列表。重复这个过程,直到没有任何元素需要交换,列表就被排序完成。
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, 25, 12, 22, 11]
bubble_sort(arr)
print("冒泡排序结果:", arr)
2,插入排序
该算法从第二个元素开始,将其与已排序的部分进行比较,将它插入到正确的位置。然后,继续处理下一个未排序的元素,重复这个过程,直到所有元素都被排序。
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, 25, 12, 22, 11]
insertion_sort(arr)
print("插入排序结果:", arr)
3,选择排序
该算法首先找到未排序部分的最小元素,然后将其与未排序部分的第一个元素交换,将这个最小元素放入已排序部分的末尾。然后,继续处理未排序部分的剩余元素,重复这个过程,直到所有元素都被排序。
def selection_sort(arr):
for i in range(len(arr)):
min_idx = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
# 使用示例
arr = [64, 25, 12, 22, 11]
selection_sort(arr)
print("选择排序结果:", arr)
4,快速排序
该算法首先选择一个基准元素,然后将列表中小于基准的元素放在基准的左边,大于基准的元素放在右边。接着,递归地对左右子列表进行相同的操作,直到子列表只包含一个元素,然后将它们合并起来。
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
# 使用示例
arr = [64, 25, 12, 22, 11]
arr = quick_sort(arr)
print("快速排序结果:", arr)
5,归并排序
该算法首先将列表拆分成较小的子列表,然后对每个子列表进行排序,这可以通过递归实现。然后,它将排好序的子列表合并成一个更大的有序列表,重复这个过程,直到整个列表被排序。
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
merge_sort(left_half)
merge_sort(right_half)
i = j = k = 0
while i < len(left_half) and j < len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1
while i < len(left_half):
arr[k] = left_half[i]
i += 1
k += 1
while j < len(right_half):
arr[k] = right_half[j]
j += 1
k += 1
# 使用示例
arr = [64, 25, 12, 22, 11]
merge_sort(arr)
print("归并排序结果:", arr)
6,堆排序
该算法首先构建一个最大堆(或最小堆),其中最大堆的根节点是未排序部分的最大值。然后,它将根节点与堆的最后一个元素交换,从堆中移除根节点(最大值),将堆的大小减小1,然后通过调整堆的操作,恢复最大堆的性质。重复这个过程,直到堆的大小为1,整个列表就被排序。
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heap_sort(arr):
n = len(arr)
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
for i in range(n - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
# 使用示例
arr = [64, 25, 12, 22, 11]
heap_sort(arr)
print("堆排序结果:", arr)
二、搜索算法
1,线性搜索
算法从列表的第一个元素开始,逐一比较每个元素与目标元素,如果找到匹配的元素,则返回其位置,否则继续比较直到找到或遍历完整个列表。
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
2,二分搜索
算法首先将待搜索区间的中间元素与目标元素比较,如果匹配,则返回位置。如果目标元素小于中间元素,搜索范围被缩小到左半部分,否则缩小到右半部分。重复这个过程,直到找到目标元素或搜索范围为空。
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
3,深度优先搜索(DFS)
算法从起始节点开始,遍历它的邻居节点,并递归地重复这个过程,直到到达叶子节点。然后,它回溯到上一个节点,继续探索未探索的邻居节点,直到整个图或树都被遍历。
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, node, neighbors):
self.graph[node] = neighbors
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
print(start, end=' ')
for neighbor in graph[start]:
if neighbor not in visited:
dfs(graph, neighbor, visited)
# 使用示例
graph = Graph()
graph.add_edge(0, [1, 2])
graph.add_edge(1, [2])
graph.add_edge(2, [0, 3])
graph.add_edge(3, [3])
print("深度优先搜索结果:")
dfs(graph.graph, 2)
4,广度优先搜索(BFS)
算法从起始节点开始,遍历其所有邻居节点,然后将这些邻居节点加入队列。然后,它从队列中取出下一个节点,继续遍历其邻居节点,并将未访问的邻居节点加入队列。这个过程重复进行,直到队列为空。
from collections import deque
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, node, neighbors):
self.graph[node] = neighbors
def bfs(graph, start):
visited = set()
queue = deque([start])
visited.add(start)
while queue:
node = queue.popleft()
print(node, end=' ')
for neighbor in graph[node]:
if neighbor not in visited:
queue.append(neighbor)
visited.add(neighbor)
# 使用示例
graph = Graph()
graph.add_edge(0, [1, 2])
graph.add_edge(1, [2])
graph.add_edge(2, [0, 3])
graph.add_edge(3, [3])
print("广度优先搜索结果:")
bfs(graph.graph, 2)
5,A*搜索算法
算法从起始节点开始,维护一个开放列表和一个关闭列表,根据评估函数计算每个节点的代价。它首先选择评估代价最低的节点,并将其加入关闭列表。然后,它扩展这个节点的邻居节点,并计算它们的代价,将它们加入开放列表。这个过程重复进行,直到找到目标节点或开放列表为空。
import heapq
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, node, neighbors):
self.graph[node] = neighbors
def astar(graph, start, goal, heuristic):
open_list = [(0, start)]
came_from = {}
g_score = {node: float('inf') for node in graph}
g_score[start] = 0
while open_list:
current_g, current_node = heapq.heappop(open_list)
if current_node == goal:
path = [current_node]
while current_node in came_from:
current_node = came_from[current_node]
path.append(current_node)
return path[::-1]
for neighbor in graph[current_node]:
tentative_g = g_score[current_node] + 1 # Assuming edge weight is 1
if tentative_g < g
三、动态规划
1,斐波那契数列
- 含义:斐波那契数列是一个数列,其中每个数字是前两个数字的和,通常以0和1开始。即F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2)(n > 1)。
- 工作原理:动态规划的方法是使用一个列表来存储已计算的斐波那契数,从0和1开始,依次计算下一个数,直到计算到目标位置的斐波那契数。
def fibonacci(n):
fib = [0, 1]
for i in range(2, n + 1):
fib.append(fib[i - 1] + fib[i - 2])
return fib[n]
2,背包问题
- 含义:背包问题是一种优化问题,通常有一个背包容量和一组物品,每个物品有自己的重量和价值,目标是在不超过背包容量的情况下,选择一些物品放入背包,以使得放入背包的物品总价值最大。
- 工作原理:动态规划的方法是创建一个二维数组,其中dp[i][j]表示在前i个物品中,容量为j的背包所能达到的最大价值。然后,通过填充这个二维数组,计算出最大价值。
def knapsack(weights, values, capacity):
n = len(weights)
dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(capacity + 1):
if weights[i - 1] <= j:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])
else:
dp[i][j] = dp[i - 1][j]
return dp[n][capacity]
3,最长公共子序列
- 含义:最长公共子序列问题是在两个序列中找到一个最长的公共子序列,子序列不需要连续,只需要保持相对顺序。
- 工作原理:动态规划的方法是创建一个二维数组,其中dp[i][j]表示第一个序列的前i个字符与第二个序列的前j个字符之间的最长公共子序列的长度。通过填充这个二维数组,可以找到最长公共子序列的长度。
def longest_common_subsequence(X, Y):
m, n = len(X), len(Y)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if X[i - 1] == Y[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
lcs_length = dp[m][n]
return lcs_length
4,最短路径问题
- 含义:最短路径问题是在图或网络中找到从一个起始节点到目标节点的最短路径,路径的长度可以通过边的权重累加得到。
- 工作原理:动态规划的方法通常使用一个二维数组来存储从起始节点到每个节点的最短路径长度。通过迭代填充这个数组,可以找到最短路径。
import heapq
def dijkstra(graph, start):
distances = {vertex: float('infinity') for vertex in graph}
distances[start] = 0
priority_queue = [(0, start)]
while priority_queue:
current_distance, current_vertex = heapq.heappop(priority_queue)
if current_distance > distances[current_vertex]:
continue
for neighbor, weight in graph[current_vertex].items():
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
5,最长递增子序列
- 含义:最长递增子序列问题是在给定序列中找到一个最长的子序列,使得子序列中的元素按顺序递增。
- 工作原理:动态规划的方法是创建一个一维数组,其中dp[i]表示以第i个元素为结尾的最长递增子序列的长度。通过迭代填充这个数组,可以找到最长递增子序列的长度。
def longest_increasing_subsequence(nums):
if not nums:
return 0
n = len(nums)
dp = [1] * n
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
【赠书啦~~~】
为了让各位小伙伴更加全面的学习算法,现在为大家赠送荣获CSDN“程序员IT好书评选”奖的《labuladong 算法小抄》,应对算法的学习与实战练习,你值得拥有哦!
- ✨本次送书 1~5 本【取决于阅读量,阅读量越多,送的越多】👈
- 🤩活动时间:截止到2023-9月25号
- 🤔参与方式:关注博主+三连(点赞、收藏、评论)
- 评论 :算法小抄
- 也可以在文末名片联系我领取更多学习资料