📜  数据结构和算法 | 20套(1)

📅  最后修改于: 2023-12-03 15:10:20.372000             🧑  作者: Mango

数据结构和算法 | 20套

数据结构和算法是程序员必备的基础知识,也是衡量程序员能力的标准之一。本篇文章将介绍20套经典的数据结构和算法,帮助程序员提升自己的技能和能力。

数据结构
数组

数组是一种线性数据结构,它可以在内存中连续地存储多个元素。数组在数据存储和访问方面具有非常高效的性能,但它的长度是固定的。

创建数组

要创建一个数组,可以使用以下语法:

# 创建一个长度为5的整型数组
arr = [0] * 5

# 创建一个字符串数组
arr = [''] * 5

访问数组元素

要访问数组元素,可以使用索引来获取指定位置的值。

# 访问第一个元素
arr[0]

# 访问最后一个元素
arr[len(arr)-1]

添加元素

要添加元素,可以使用append()方法。

# 添加元素
arr.append(6)

栈是一种基于先进后出(FILO)原则的数据结构,它只允许在栈顶进行插入和删除操作。栈可以用于模拟递归调用、表达式求值以及括号匹配等场景。

创建栈

要创建一个栈,可以使用list来实现。

# 创建一个栈
stack = []

添加元素

要添加元素,可以使用append()方法。

# 添加元素
stack.append(1)

删除元素

要删除元素,可以使用pop()方法。

# 删除元素
stack.pop()
队列

队列是一种基于先进先出、后进后出(FIFO)原则的数据结构,它允许在队尾插入元素,在队头删除元素。队列可以用于实现广度优先搜索、任务调度、消息队列等场景。

创建队列

要创建一个队列,可以使用collections中的deque来实现。

# 创建一个队列
from collections import deque

queue = deque()

添加元素

要添加元素,可以使用append()方法。

# 添加元素
queue.append(1)

删除元素

要删除元素,可以使用popleft()方法。

# 删除元素
queue.popleft()
链表

链表是一种基于指针的数据结构,它由一系列节点组成,每个节点都包含一个数据和一个指向下一个节点的指针。链表可以用于实现栈、队列、LRU缓存等场景。

创建链表

要创建一个链表,可以定义一个节点类。

# 定义链表节点类
class Node:
    def __init__(self, val):
        self.val = val
        self.next = None

# 创建链表
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)

插入节点

要插入节点,需要找到要插入位置的前一个节点。

# 在第二个节点后插入节点
new_node = Node(4)
new_node.next = head.next.next
head.next.next = new_node

删除节点

要删除节点,需要找到要删除位置的前一个节点。

# 删除第二个节点
head.next = head.next.next
二叉树

二叉树是一种每个节点最多有两个子节点的树形数据结构,它可以用来实现字典、网络路由等场景。

创建二叉树

要创建一个二叉树,可以定义一个树节点类。

# 定义二叉树节点类
class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

# 创建二叉树
root = Node(1)
root.left = Node(2)
root.right = Node(3)

遍历二叉树

要遍历一个二叉树,可以使用深度优先搜索或广度优先搜索算法。

深度优先搜索

深度优先搜索可以分为前序遍历、中序遍历和后序遍历。

前序遍历:根节点 -> 左子树 -> 右子树

def preorder(root):
    if root is not None:
        print(root.val)
        preorder(root.left)
        preorder(root.right)

中序遍历:左子树 -> 根节点 -> 右子树

def inorder(root):
    if root is not None:
        inorder(root.left)
        print(root.val)
        inorder(root.right)

后序遍历:左子树 -> 右子树 -> 根节点

def postorder(root):
    if root is not None:
        postorder(root.left)
        postorder(root.right)
        print(root.val)
广度优先搜索

广度优先搜索从根节点开始,逐层遍历每个节点,可以使用队列来实现。

def bfs(root):
    queue = [root]
    while len(queue) > 0:
        node = queue.pop(0)
        print(node.val)
        if node.left is not None:
            queue.append(node.left)
        if node.right is not None:
            queue.append(node.right)
算法
排序算法

排序算法是对一组无序数据进行排序的一种算法。

冒泡排序

冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,一次比较两个元素,并且交换它们的位置,直到最大值被放到了最后一个位置。

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

快速排序

快速排序是一种分治的排序算法,基于一串数组,通过一趟排序将数组分成两部分,左半部分小于基准值,右半部分大于基准值,并且分别对左右两部分递归进行快速排序。

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[0]
    left = []
    right = []
    for i in range(1, len(arr)):
        if arr[i] < pivot:
            left.append(arr[i])
        else:
            right.append(arr[i])
    return quick_sort(left) + [pivot] + quick_sort(right)

归并排序

归并排序是一种分治的排序算法,把原始数组的长度折半,分为左右两个子序列,对每个子序列进行递归排序,然后将排好序的子序列进行合并,得到排好序的数组。

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):
    res = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            res.append(left[i])
            i += 1
        else:
            res.append(right[j])
            j += 1
    res += left[i:]
    res += right[j:]
    return res
查找算法

查找算法是在数据集中找到特定值的算法。

线性查找

线性查找是一种基础的查找算法,它从数据集里的第一个数开始逐个比较,直到找到所需的值。

def linear_search(arr, target):
    for i in range(len(arr)):
        if arr[i] == target:
            return i
    return -1

二分查找

二分查找是一种基于分治思想的查找算法,它利用有序数组的特性,在每一次比较之后将查找范围缩小一半。

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
字符串算法

字符串算法是处理字符串的一种算法,它可以用于字符串匹配、编辑距离计算等问题。

KMP算法

KMP算法是一种高效的字符串匹配算法,它在匹配过程中,通过维护一个next数组,来跳过已经匹配过的部分。

def KMP(pattern, text):
    m, n = len(pattern), len(text)
    next_arr = get_next(pattern)
    j = 0
    for i in range(n):
        while j > 0 and pattern[j] != text[i]:
            j = next_arr[j-1]
        if pattern[j] == text[i]:
            j += 1
        if j == m:
            return i - m + 1
    return -1

def get_next(pattern):
    n = len(pattern)
    nxt = [0] * n
    j = 0
    for i in range(1, n):
        while j > 0 and pattern[j] != pattern[i]:
            j = nxt[j-1]
        if pattern[j] == pattern[i]:
            j += 1
        nxt[i] = j
    return nxt
动态规划算法

动态规划算法是一种求解最优化问题的算法,它能够求解具有重叠子问题和最优子结构性质的问题。

背包问题

背包问题是一种可以用动态规划算法求解的问题,它将一些物品放入到一个背包中,在物品有重量和价值的情况下,最大化背包的价值。

def knapsack_weight(n, c, w, v):
    dp = [0] * (c+1)
    for i in range(n):
        for j in range(c, w[i]-1, -1):
            dp[j] = max(dp[j], dp[j-w[i]] + v[i])
    return dp[c]

最长公共子序列

最长公共子序列是一种可以用动态规划算法求解的问题,它是指在两个序列中找到一个最长的子序列,使得这个子序列同时在两个序列中出现。

def longest_common_subsequence(text1, text2):
    m, n = len(text1), len(text2)
    dp = [[0] * (n+1) for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if text1[i-1] == text2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]

总结:

本篇文章共介绍了20套经典的数据结构和算法,包括数组、栈、队列、链表、二叉树、冒泡排序、快速排序、归并排序、线性查找、二分查找、KMP算法、背包问题和最长公共子序列。程序员在实际工作中可以根据具体的需求和场景,灵活使用这些数据结构和算法,提升自己的技能和能力。