数据结构与算法

41 阅读5分钟

数组(Array):一组连续的内存空间,可以存储相同类型的数据。可以通过索引快速访问和修改元素。

链表(Linked List):由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针。可以动态地插入和删除元素,但访问元素需要遍历整个链表。

栈(Stack):一种先进后出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。常用于函数调用、表达式求值等场景。

队列(Queue):一种先进先出(FIFO)的数据结构,可以在队尾插入元素,在队头删除元素。常用于任务调度、消息传递等场景。

散列表(Hash Table):根据关键字直接访问数据的数据结构,通过散列函数将关键字映射到数组的索引上。可以实现快速的插入、删除和查找操作。

二叉树(Binary Tree):每个节点最多有两个子节点的树结构。常用于排序、搜索和表达式求值等场景。

堆(Heap):一种特殊的树结构,满足堆属性(最大堆或最小堆)。常用于优先队列、排序算法(如堆排序)等场景。

跳表(Skip List):一种有序链表的扩展结构,通过多级索引提高查询效率。常用于有序集合的实现。

图(Graph):由节点和边组成的非线性数据结构,节点之间可以有多个连接。常用于网络、社交关系等场景。

  1. Tire树(Trie Tree):一种树形结构,用于高效地存储和搜索字符串集合。常用于字典、自动补全等场景。

以下是使用Python实现常见算法的代码示例:

  1. 递归:递归是一种解决问题的方法,它将问题分解为更小的子问题,并通过递归调用来解决这些子问题,最终得到原始问题的解。递归函数通常包含一个或多个基本情况,用于终止递归的条件,以及一个或多个递归情况,用于将问题分解为更小的子问题。
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

  1. 排序(以冒泡排序为例):排序是将一组元素按照特定的顺序进行排列的过程。常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序等。排序算法的选择取决于数据规模、数据类型和性能要求等因素。
def bubble_sort(arr):
    n = len(arr)
    for i in range(n-1):
        for j in range(n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr
  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. 搜索(以深度优先搜索为例):搜索是在给定的数据集合中查找特定元素或满足特定条件的元素的过程。常见的搜索算法有线性搜索、二分搜索、深度优先搜索、广度优先搜索等。不同的搜索算法适用于不同的问题和数据结构。
def dfs(graph, start, visited):
    visited.add(start)
    print(start, end=' ')
    for neighbor in graph[start]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)
  1. 哈希算法(以MD5为例):哈希算法是一种将任意长度的数据映射为固定长度散列值的算法。哈希算法常用于数据加密、数据校验、数据索引等领域。常见的哈希算法有MD5、SHA-1、SHA-256等。
import hashlib

def md5_hash(data):
    md5 = hashlib.md5()
    md5.update(data.encode('utf-8'))
    return md5.hexdigest()
  1. 贪心算法(以找零钱为例):贪心算法是一种通过每一步的局部最优选择来达到全局最优解的算法。贪心算法通常不回溯,而是根据当前情况作出最好的选择,并希望通过这种选择能够得到最优解。
def make_change(coins, amount):
    coins.sort(reverse=True)
    change = []
    for coin in coins:
        while amount >= coin:
            amount -= coin
            change.append(coin)
    if amount == 0:
        return change
    else:
        return []
  1. 分治算法(以归并排序为例):分治算法是一种将问题分解为更小的子问题,然后将子问题的解合并起来得到原始问题解的方法。分治算法通常包含三个步骤:分解(将问题分解为更小的子问题)、解决(递归地解决子问题)、合并(将子问题的解合并起来得到原始问题的解)。
def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    merged = []
    i, j = 0, 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1
    merged.extend(left[i:])
    merged.extend(right[j:])
    return merged
  1. 回溯算法(以全排列为例):回溯算法是一种通过试错的方式搜索问题的解的算法。回溯算法通常通过递归地尝试所有可能的解,并在得到无效解时进行回溯,尝试其他可能的解。
    res = []
    backtrack(nums, [], res)
    return res

def backtrack(nums, path, res):
    if not nums:
        res.append(path)
    for i in range(len(nums)):
        backtrack(nums[:i] + nums[i+1:], path + [nums[i]], res)
  1. 动态规划(以斐波那契数列为例):动态规划是一种通过将问题分解为更小的子问题,并记录子问题的解来解决原始问题的方法。动态规划通常包含两个关键步骤:定义状态(将原始问题转化为子问题的状态)和状态转移(根据子问题的解推导出原始问题的解)。
def fibonacci(n):
    if n <= 1:
        return n
    dp = [0] * (n+1)
    dp[1] = 1
    for i in range(2, n+1):
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]
  1. 字符串匹配算法(以KMP算法为例):字符串匹配算法是一种在文本中查找特定字符串模式的算法。常见的字符串匹配算法有朴素字符串匹配、KMP算法、Boyer-Moore算法等。这些算法通过不同的方式在文本中搜索匹配的字符串模式。
def kmp_search(text, pattern):
    n, m = len(text), len(pattern)
    if m == 0:
        return 0
    next = get_next(pattern)
    i, j = 0, 0
    while i < n:
        if text[i] == pattern[j]:
            i += 1
            j += 1
            if j == m:
                return i - j
        else:
            j = next[j]
            if j == -1:
                i += 1
                j += 1
    return -1

def get_next(pattern):
    m = len(pattern)
    next = [-1] * m
    i, j = 0, -1
    while i < m - 1:
        if j == -1 or pattern[i] == pattern[j]:
            i += 1
            j += 1
            next[i] = j
        else:
            j = next[j]
    return next