十个经典算法的 Python 实现

开发
本文我们将一步步探索并用Python实现这些算法,从基础到进阶,让你的编程之旅更加精彩。

算法是编程世界的基石,对于Python初学者来说,掌握一些经典算法不仅能够提升编程技能,还能帮助理解问题解决的逻辑。下面,我们将一步步探索并用Python实现这些算法,从基础到进阶,让你的编程之旅更加精彩。

1. 二分查找

概念:在有序数组中查找目标值,每次比较中间元素,缩小搜索范围。

示例代码:

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  # 如果没找到返回-1

arr = [2, 3, 4, 10, 40]
target = 10
print("Element is present at index", binary_search(arr, target))

解释:通过不断将搜索区间分为两半,直到找到目标或区间为空。

2. 冒泡排序

概念:重复遍历要排序的数列,比较相邻元素,如果顺序错误就交换它们。

示例代码:

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]
    return arr

arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bubble_sort(arr)
print("Sorted array is:", sorted_arr)

解释:每一轮遍历让最大的元素“冒泡”到最后。

3. 快速排序

概念:选择一个基准值,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序。

示例代码:

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 = [10, 7, 8, 9, 1, 5]
sorted_arr = quick_sort(arr)
print("Sorted array is:", sorted_arr)

解释:递归地把小于基准值的元素和大于基准值的元素分开。

4. 插入排序

概念:将未排序序列中的数据依次插入到已排序序列中的适当位置。

示例代码:

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
    return arr

arr = [12, 11, 13, 5, 6]
sorted_arr = insertion_sort(arr)
print("Sorted array is:", sorted_arr)

解释:逐步构建有序序列,适合小数据量排序。

5. 选择排序

概念:每次从未排序的序列中找到最小(大)的元素,存放到排序序列的起始(末尾)位置。

示例代码:

def selection_sort(arr):
    for i in range(len(arr)):
        min_idx = i
        for j in range(i+1, len(arr)):
            if arr[min_idx] > arr[j]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

arr = [64, 25, 12, 22, 11]
sorted_arr = selection_sort(arr)
print("Sorted array is:", sorted_arr)

解释:每轮寻找最小值并移动到序列前端。

6. 链表反转

概念:将链表的指向反向,头节点变成尾节点,尾节点变成头节点。

示例代码:

class Node:
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next

def reverse_list(head):
    prev = None
    current = head
    while current:
        next_temp = current.next
        current.next = prev
        prev = current
        current = next_temp
    return prev

# 创建链表: 1->2->3
head = Node(1, Node(2, Node(3)))
reversed_head = reverse_list(head)
print("Reversed list:", end=" ")
while reversed_head:
    print(reversed_head.data, end=" -> ")
    reversed_head = reversed_head.next

解释:通过改变节点的next指针来实现反转。

7. 动态规划 - 最长公共子序列

概念:找到两个字符串中最长的相同子序列。

示例代码:

def lcs(X, Y):
    m, n = len(X), len(Y)
    L = [[None]*(n+1) for i in range(m+1)]
    
    for i in range(m+1):
        for j in range(n+1):
            if i == 0 or j == 0:
                L[i][j] = 0
            elif X[i-1] == Y[j-1]:
                L[i][j] = L[i-1][j-1]+1
            else:
                L[i][j] = max(L[i-1][j], L[i][j-1])
    return L[m][n]

X = "AGGTAB"
Y = "GXTXAYB"
print("Length of LCS is", lcs(X, Y))

解释:利用二维数组记录子问题的解,自底向上计算最长公共子序列长度。

8. 深度优先搜索(DFS)

概念:访问图或树中的节点,尽可能深地搜索,访问完当前节点的所有邻接节点后回溯。

示例代码(图的DFS):

def dfs(graph, node, visited=None):
    if visited is None:
        visited = set()
    visited.add(node)
    print(node, end=" ")
    for neighbour in graph[node]:
        if neighbour not in visited:
            dfs(graph, neighbour, visited)

graph = {'0': ['1', '2'],
         '1': ['0', '3', '4'],
         '2': ['0'],
         '3': ['1'],
         '4': ['1']}
dfs(graph, '0')

解释:递归地访问节点及其邻居,用集合记录已访问节点避免循环。

9. 广度优先搜索(BFS)

概念:从根节点开始,访问最近的邻接节点,然后访问下一层的节点。

示例代码(图的BFS):

from collections import deque

def bfs(graph, root):
    visited = set()
    queue = deque([root])

    while queue:
        vertex = queue.popleft()
        print(vertex, end=" ")

        for neighbour in graph[vertex]:
            if neighbour not in visited:
                visited.add(neighbour)
                queue.append(neighbour)

graph = {'0': ['1', '2'],
         '1': ['0', '3', '4'],
         '2': ['0'],
         '3': ['1'],
         '4': ['1']}
bfs(graph, '0')

解释:使用队列保证按层次访问节点。

10. 斐波那契数列

概念:每一项都是前两项之和,通常从0和1开始。

示例代码(递归与迭代):

# 递归
def fib_recursive(n):
    if n <= 1:
       return n
    else:
       return (fib_recursive(n-1) + fib_recursive(n-2))

# 迭代
def fib_iterative(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a+b
    return a

print("Fibonacci at position 10 using recursion:", fib_recursive(10))
print("Fibonacci at position 10 using iteration:", fib_iterative(10))

解释:递归直观但效率低,迭代效率高且内存占用少。

优化与应用场景

1. 二分查找的扩展

应用场景:适用于有序列表的快速查找,常见于数据库索引、文件系统搜索等。

优化:可以设计为迭代或递归形式,考虑边界条件的优化,如在链表中的实现需要额外的辅助结构。

2. 排序算法的性能对比

快速排序通常在平均情况下最快,但在最坏情况下的时间复杂度为O(n^2)。

归并排序虽然稳定,但需要额外的存储空间,时间复杂度始终为O(n log n)。

插入排序在小数据集或几乎有序的数据集中表现良好,适合局部排序的优化场景。

3. 动态规划与记忆化

LCS问题展示了动态规划的核心思想,通过表格记录子问题的解来避免重复计算。

优化:对于递归实现,可以通过缓存(记忆化)避免重复计算,减少时间复杂度。

4. 图搜索算法的比较

DFS适用于寻找路径、拓扑排序、连通性检查。

BFS更适合寻找最短路径问题,如在无权图中寻找两节点间的最短路径。

优化:在大规模图中,考虑使用并行处理或A*搜索等高级算法以提高效率。

5. 斐波那契数列的高效实现

矩阵快速幂:对于大数字的斐波那契数,可以利用数学中的矩阵乘法进行指数级优化。

空间优化:迭代方法已经很高效,但可以进一步优化,比如仅用两个变量替换数组,节省内存。

实战案例分析

案例:旅行商问题(TSP)的启发式解决方案

旅行商问题是一个经典的组合优化问题,目标是找到访问每个城市一次并返回起点的最短路径。虽然这是一个NP难问题,但可以使用启发式算法如遗传算法、模拟退火或贪心算法找到近似解。

示例代码(简化版贪心算法):

def tsp_greedy(cities, start=0):
    unvisited = set(range(len(cities)))
    path = [start]
    total_distance = 0
    
    while unvisited:
        last_city = path[-1]
        nearest_city = min(unvisited, key=lambda city: cities[last_city][city])
        total_distance += cities[last_city][nearest_city]
        path.append(nearest_city)
        unvisited.remove(nearest_city)
        
    # Return to start
    total_distance += cities[path[-1]][start]
    path.append(start)
    
    return path, total_distance

# 假设cities是一个二维列表,表示城市间的距离
cities = [[0, 20, 15, 25], [20, 0, 30, 35], [15, 30, 0, 30], [25, 35, 30, 0]]
shortest_path, shortest_distance = tsp_greedy(cities)
print("Shortest Path:", shortest_path)
print("Distance:", shortest_distance)

分析:虽然贪心算法在TSP中可能不会得到最优解,但它简单且快速,适合快速生成可行解,对于教学和理解启发式算法非常有用。

责任编辑:赵宁宁 来源: PythonAI与图像处理
相关推荐

2024-11-11 07:00:00

Python图像识别

2024-05-30 12:27:42

Python代码

2010-09-08 14:35:22

CSS

2024-12-03 14:33:42

Python递归编程

2011-08-15 09:15:09

私有云云计算

2022-08-27 15:03:43

Python损失函数算法

2024-07-18 15:08:27

2022-03-10 12:03:33

Python算法代码

2022-08-26 09:38:39

Pandas数据查询

2021-12-02 14:55:44

Python项目编程语言

2024-04-28 10:00:24

Python数据可视化库图像处理库

2023-06-27 15:50:23

Python图像处理

2022-05-12 08:12:51

PythonPip技巧

2024-06-26 13:11:40

2023-12-22 15:44:43

2022-08-19 16:09:08

Python损失函数算法

2024-02-01 12:53:00

PandasPython数据

2023-06-13 06:51:09

Spark机器学习回归

2023-11-22 19:24:36

2024-01-30 00:40:10

点赞
收藏

51CTO技术栈公众号