二分查找、冒泡排序…10个经典算法Python实现

2024-08-2515:08:02数据结构与算法Comments411 views字数 6056阅读模式

算法是编程世界的基石,对于Python初学者来说,掌握一些经典算法不仅能够提升编程技能,还能帮助理解问题解决的逻辑。下面,我们将一步步探索并用Python实现这些算法,从基础到进阶,让你的编程之旅更加精彩。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

1. 二分查找

概念:在有序数组中查找目标值,每次比较中间元素,缩小搜索范围。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [2341040]
target = 10
print("Element is present at index", binary_search(arr, target))

解释:通过不断将搜索区间分为两半,直到找到目标或区间为空。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


2. 冒泡排序

概念:重复遍历要排序的数列,比较相邻元素,如果顺序错误就交换它们。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [64342512221190]
sorted_arr = bubble_sort(arr)
print("Sorted array is:", sorted_arr)

解释:每一轮遍历让最大的元素“冒泡”到最后。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


3. 快速排序

概念:选择一个基准值,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [1078915]
sorted_arr = quick_sort(arr)
print("Sorted array is:", sorted_arr)

解释:递归地把小于基准值的元素和大于基准值的元素分开。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


4. 插入排序

概念:将未排序序列中的数据依次插入到已排序序列中的适当位置。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [12111356]
sorted_arr = insertion_sort(arr)
print("Sorted array is:", sorted_arr)

解释:逐步构建有序序列,适合小数据量排序。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

5. 选择排序

概念:每次从未排序的序列中找到最小(大)的元素,存放到排序序列的起始(末尾)位置。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [6425122211]
sorted_arr = selection_sort(arr)
print("Sorted array is:", sorted_arr)

解释:每轮寻找最小值并移动到序列前端。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


6. 链表反转

概念:将链表的指向反向,头节点变成尾节点,尾节点变成头节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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指针来实现反转。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


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

概念:找到两个字符串中最长的相同子序列。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

def lcs(X, Y):
    m, n = len(X), len(Y)
    L = [[None]*(n+1for 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))

解释:利用二维数组记录子问题的解,自底向上计算最长公共子序列长度。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


8. 深度优先搜索(DFS)

概念:访问图或树中的节点,尽可能深地搜索,访问完当前节点的所有邻接节点后回溯。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码(图的DFS):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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')

解释:递归地访问节点及其邻居,用集合记录已访问节点避免循环。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


9. 广度优先搜索(BFS)

概念:从根节点开始,访问最近的邻接节点,然后访问下一层的节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码(图的BFS):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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')

解释:使用队列保证按层次访问节点。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

10. 斐波那契数列

概念:每一项都是前两项之和,通常从0和1开始。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码(递归与迭代):文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

# 递归
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 = 01
    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))

解释:递归直观但效率低,迭代效率高且内存占用少。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html


优化与应用场景

1. 二分查找的扩展

  • 应用场景:适用于有序列表的快速查找,常见于数据库索引、文件系统搜索等。
  • 优化:可以设计为迭代或递归形式,考虑边界条件的优化,如在链表中的实现需要额外的辅助结构。

2. 排序算法的性能对比

  • 快速排序通常在平均情况下最快,但在最坏情况下的时间复杂度为O(n^2)。
  • 归并排序虽然稳定,但需要额外的存储空间,时间复杂度始终为O(n log n)。
  • 插入排序在小数据集或几乎有序的数据集中表现良好,适合局部排序的优化场景。

3. 动态规划与记忆化

  • LCS问题展示了动态规划的核心思想,通过表格记录子问题的解来避免重复计算。
  • 优化:对于递归实现,可以通过缓存(记忆化)避免重复计算,减少时间复杂度。

4. 图搜索算法的比较

  • DFS适用于寻找路径、拓扑排序、连通性检查。
  • BFS更适合寻找最短路径问题,如在无权图中寻找两节点间的最短路径。
  • 优化:在大规模图中,考虑使用并行处理或A*搜索等高级算法以提高效率。

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

  • 矩阵快速幂:对于大数字的斐波那契数,可以利用数学中的矩阵乘法进行指数级优化。
  • 空间优化:迭代方法已经很高效,但可以进一步优化,比如仅用两个变量替换数组,节省内存。

实战案例分析

案例:旅行商问题(TSP)的启发式解决方案文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

旅行商问题是一个经典的组合优化问题,目标是找到访问每个城市一次并返回起点的最短路径。虽然这是一个NP难问题,但可以使用启发式算法如遗传算法、模拟退火或贪心算法找到近似解。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

示例代码(简化版贪心算法)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

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 = [[0201525], [2003035], [1530030], [2535300]]
shortest_path, shortest_distance = tsp_greedy(cities)
print("Shortest Path:", shortest_path)
print("Distance:", shortest_distance)

分析:虽然贪心算法在TSP中可能不会得到最优解,但它简单且快速,适合快速生成可行解,对于教学和理解启发式算法非常有用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/suanfa/65004.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/suanfa/65004.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定