1. 网格遍历算法概述
网格遍历是计算机科学中处理二维或三维网格数据结构的基础算法技术。想象一下你站在一个巨大的棋盘上,每个格子可能有不同的属性或状态,如何系统地访问每一个格子就是网格遍历要解决的问题。
在实际开发中,网格遍历算法广泛应用于:
- 游戏开发中的地图探索
- 图像处理中的像素分析
- 机器人路径规划
- 科学计算中的数值模拟
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础遍历方法
2.1 方向数组定义
方向数组是网格遍历的核心技术之一。它定义了当前格子可以移动的所有可能方向。以二维网格为例:
python复制# 四方向移动
directions = [(0,1), (1,0), (0,-1), (-1,0)]
# 八方向移动(包含对角线)
directions = [(0,1), (1,1), (1,0), (1,-1),
(0,-1), (-1,-1), (-1,0), (-1,1)]
2.2 深度优先搜索(DFS)实现
DFS采用递归或栈的方式实现网格遍历:
python复制def dfs(grid, i, j, visited):
if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]):
return
if visited[i][j]:
return
visited[i][j] = True
print(f"访问格子({i},{j})")
# 四方向遍历
for di, dj in [(0,1), (1,0), (0,-1), (-1,0)]:
dfs(grid, i+di, j+dj, visited)
注意:递归实现的DFS在网格较大时可能导致栈溢出,可以考虑使用显式栈的迭代实现。
3. 进阶遍历技巧
3.1 层序遍历(BFS)
BFS使用队列实现,适合寻找最短路径:
python复制from collections import deque
def bfs(grid, start_i, start_j):
queue = deque()
queue.append((start_i, start_j))
visited = [[False]*len(grid[0]) for _ in range(len(grid))]
visited[start_i][start_j] = True
while queue:
i, j = queue.popleft()
print(f"访问格子({i},{j})")
for di, dj in [(0,1), (1,0), (0,-1), (-1,0)]:
ni, nj = i+di, j+dj
if 0 <= ni < len(grid) and 0 <= nj < len(grid[0]) and not visited[ni][nj]:
visited[ni][nj] = True
queue.append((ni, nj))
3.2 螺旋遍历
螺旋遍历从外向内按顺时针方向访问网格:
python复制def spiral_order(matrix):
if not matrix:
return []
res = []
top, bottom = 0, len(matrix)-1
left, right = 0, len(matrix[0])-1
while True:
# 从左到右
for i in range(left, right+1):
res.append(matrix[top][i])
top += 1
if top > bottom: break
# 从上到下
for i in range(top, bottom+1):
res.append(matrix[i][right])
right -= 1
if left > right: break
# 从右到左
for i in range(right, left-1, -1):
res.append(matrix[bottom][i])
bottom -= 1
if top > bottom: break
# 从下到上
for i in range(bottom, top-1, -1):
res.append(matrix[i][left])
left += 1
if left > right: break
return res
4. 实际应用案例
4.1 岛屿数量问题
经典算法题,统计网格中岛屿的数量:
python复制def num_islands(grid):
if not grid:
return 0
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
dfs(grid, i, j)
count += 1
return count
def dfs(grid, i, j):
if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] != '1':
return
grid[i][j] = '0' # 标记为已访问
dfs(grid, i+1, j)
dfs(grid, i-1, j)
dfs(grid, i, j+1)
dfs(grid, i, j-1)
4.2 最短路径搜索
结合BFS实现网格中的最短路径查找:
python复制def shortest_path(grid, start, end):
if grid[start[0]][start[1]] == 0 or grid[end[0]][end[1]] == 0:
return -1
rows = len(grid)
cols = len(grid[0])
queue = deque()
queue.append((start[0], start[1], 0))
visited = [[False]*cols for _ in range(rows)]
visited[start[0]][start[1]] = True
while queue:
i, j, dist = queue.popleft()
if (i,j) == end:
return dist
for di, dj in [(0,1),(1,0),(0,-1),(-1,0)]:
ni, nj = i+di, j+dj
if 0<=ni<rows and 0<=nj<cols and grid[ni][nj]==1 and not visited[ni][nj]:
visited[ni][nj] = True
queue.append((ni, nj, dist+1))
return -1
5. 性能优化技巧
5.1 剪枝策略
在遍历过程中提前终止不必要的搜索:
python复制def dfs_with_pruning(grid, i, j, target, visited):
if (i,j) == target:
return True
if i<0 or i>=len(grid) or j<0 or j>=len(grid[0]):
return False
if visited[i][j] or grid[i][j] == 0:
return False
visited[i][j] = True
# 尝试四个方向,任一方向找到即可返回
if (dfs_with_pruning(grid, i+1, j, target, visited) or
dfs_with_pruning(grid, i-1, j, target, visited) or
dfs_with_pruning(grid, i, j+1, target, visited) or
dfs_with_pruning(grid, i, j-1, target, visited)):
return True
return False
5.2 记忆化搜索
存储中间结果避免重复计算:
python复制def max_path_sum(grid):
memo = {}
def dfs(i, j):
if (i,j) in memo:
return memo[(i,j)]
if i == len(grid)-1 and j == len(grid[0])-1:
return grid[i][j]
if i >= len(grid) or j >= len(grid[0]):
return float('-inf')
right = dfs(i, j+1)
down = dfs(i+1, j)
memo[(i,j)] = grid[i][j] + max(right, down)
return memo[(i,j)]
return dfs(0, 0)
6. 常见问题与调试技巧
6.1 边界检查
网格遍历中最常见的错误就是数组越界。建议使用统一的边界检查函数:
python复制def is_valid(grid, i, j):
return 0 <= i < len(grid) and 0 <= j < len(grid[0])
6.2 访问标记处理
对于需要标记访问状态的算法,常见两种处理方式:
- 修改原始网格(如将访问过的格子设为0)
- 使用独立的visited数组
提示:在算法竞赛中,方法1更节省内存;在实际工程中,方法2更安全,不会破坏原始数据。
6.3 方向数组的灵活运用
根据问题特点定制方向数组:
python复制# 只允许向右和向下移动
directions = [(0,1), (1,0)]
# 国际象棋中马的移动方式
knight_moves = [(2,1), (1,2), (-1,2), (-2,1),
(-2,-1), (-1,-2), (1,-2), (2,-1)]
7. 高级应用:多算法结合
7.1 A*算法实现
结合启发式搜索的网格路径查找:
python复制import heapq
def a_star(grid, start, end):
def heuristic(a, b):
return abs(a[0]-b[0]) + abs(a[1]-b[1])
rows = len(grid)
cols = len(grid[0])
open_set = []
heapq.heappush(open_set, (0, start[0], start[1]))
came_from = {}
g_score = { (i,j): float('inf') for i in range(rows) for j in range(cols) }
g_score[(start[0], start[1])] = 0
f_score = { (i,j): float('inf') for i in range(rows) for j in range(cols) }
f_score[(start[0], start[1])] = heuristic(start, end)
while open_set:
current = heapq.heappop(open_set)[1:]
if current == end:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return path
for di, dj in [(0,1),(1,0),(0,-1),(-1,0)]:
ni, nj = current[0]+di, current[1]+dj
if 0<=ni<rows and 0<=nj<cols and grid[ni][nj] == 1:
tentative_g = g_score[current] + 1
if tentative_g < g_score[(ni,nj)]:
came_from[(ni,nj)] = current
g_score[(ni,nj)] = tentative_g
f_score[(ni,nj)] = tentative_g + heuristic((ni,nj), end)
heapq.heappush(open_set, (f_score[(ni,nj)], ni, nj))
return None # 没有找到路径
7.2 动态规划结合
网格中的动态规划问题,如最小路径和:
python复制def min_path_sum(grid):
if not grid or not grid[0]:
return 0
rows = len(grid)
cols = len(grid[0])
dp = [[0]*cols for _ in range(rows)]
dp[0][0] = grid[0][0]
# 初始化第一行和第一列
for j in range(1, cols):
dp[0][j] = dp[0][j-1] + grid[0][j]
for i in range(1, rows):
dp[i][0] = dp[i-1][0] + grid[i][0]
# 动态规划填充
for i in range(1, rows):
for j in range(1, cols):
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
return dp[rows-1][cols-1]
8. 工程实践建议
- 代码可读性:为方向数组和边界条件定义清晰的常量或函数
- 测试用例:包含各种边界情况(空网格、单行、单列、大网格)
- 性能分析:对于大型网格,考虑使用更高效的数据结构
- 可视化调试:实现简单的网格打印函数辅助调试
python复制def print_grid(grid, path=[]):
for i in range(len(grid)):
for j in range(len(grid[0])):
if (i,j) in path:
print("*", end=" ")
else:
print(grid[i][j], end=" ")
print()
网格遍历算法看似简单,但在实际应用中需要考虑的细节很多。掌握基础遍历方法后,可以根据具体问题灵活组合各种技巧。在算法竞赛和工程开发中,网格遍历都是必须熟练掌握的基础技能。
