📅  最后修改于: 2023-12-03 15:10:20.372000             🧑  作者: Mango
数据结构和算法是程序员必备的基础知识,也是衡量程序员能力的标准之一。本篇文章将介绍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算法是一种高效的字符串匹配算法,它在匹配过程中,通过维护一个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算法、背包问题和最长公共子序列。程序员在实际工作中可以根据具体的需求和场景,灵活使用这些数据结构和算法,提升自己的技能和能力。