DFS深度优先搜索(前序、中序、后序遍历)非递归标准模板

本文提供了使用Java实现DFS深度优先搜索的非递归模板,涵盖前序、中序和后序遍历。通过一个TreeNode类构建二叉树结构,并利用栈进行遍历。在测试类中,给出了具体示例代码,对给定的二叉树进行遍历操作,展示各遍历顺序的结果。

DFS深度优先搜索(前序、中序、后序遍历)非递归标准模板(JAVA)

本文展示了DFS深度优先搜索下,前中后序遍历模板;如果要使用前序遍历,可注释掉中后序遍历的输出代码;使用中序与后序遍历同理

TreeNode类
代码如下

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val){
        this.val = val;
    }
    public TreeNode(TreeNode left, int val, TreeNode right){
        this.val = val;
        this.left = left;
        this.right = right;
    }
    public String toString(){
        return String.valueOf(this.val);
    }
}

测试类

测试类使用到的树形

[1, 2, 3, 4, null, 5, 6]

代码

import java.util.LinkedList;
import java.util.Stack;

public class Test {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(new TreeNode(new TreeNode(4), 2, null),
                        1,
                        new TreeNode(new TreeNode(5), 3, new TreeNode(6))
        );

        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode pop = null;
        while(cur != null || !stack.isEmpty()){
            if(cur != null){
                stack.push(cur);
                System.out.println("前序遍历:"+ cur);
                cur = cur.left;
            }else{
                TreeNode peek = stack.peek();
                if(peek.right == null){
                    System.out.println("中序遍历:"+ peek);
                    pop = stack.pop();
                    System.out.println("后序遍历:"+ pop);
                }
                else if(peek.right == pop){
                    pop = stack.pop();
                    System.out.println("后序遍历:"+ pop);
                }
                else{
                    System.out.println("中序遍历:"+ peek);
                    cur = peek.right;
                }
            }
        }
    }
}

希望有所帮助!

<think>我们正在讨论的是答题卡图像处理中的匈牙利匹配和深度优先遍历算法。用户要求解释这两种算法在计算机视觉中的应用,特别是在答题卡图像处理中的原理与实现方式。 根据用户描述的项目流程: 1. 使用OpenCV进行图像矫正(四边检测和矫正) 2. 运用匈牙利匹配将矫正后的答题卡与模板进行匹配 3. 通过DFS深度优先遍历算法获取所有检测框的信息 4. 根据涂点区域的灰度值判断选项答案 我们需要重点解释匈牙利匹配和DFS在其中的作用。 匈牙利匹配(Hungarian Algorithm): 在答题卡处理中,通常有一个模板(包含所有题目的标准位置)和一个待检测的答题卡图像(经过矫正后)。我们需要将检测到的涂点区域(可能是多个候选框)与模板中的标准位置进行匹配。这就是一个指派问题:每个检测框应该对应模板中的哪个位置?匈牙利算法可以解决这种二分图最小权匹配问题。 深度优先遍历DFS): 在获取检测框信息时,用户提到使用DFS。这里可能是用于在图像中搜索连通区域(比如涂点区域)或者是在某种数据结构(如图或树)中遍历所有可能的检测框。在答题卡中,涂点区域通常是孤立的,但可能由于噪声或其他原因,检测到的框可能形成某种结构(比如网格),DFS可以用来遍历所有检测到的框。 具体实现步骤可能如下: 1. 图像矫正后,使用模板匹配或者目标检测方法(如Rtdetr)得到答题卡上的所有候选框(可能包括题目选项框)。 2. 模板中每个题目选项的位置是已知的(标准位置),我们需要将检测到的候选框与这些标准位置进行匹配。由于检测到的框可能有多余(噪声)或者缺失,所以这是一个最优匹配问题。 3. 匈牙利算法可以解决这个匹配问题:将每个检测框分配给模板位置,使得总距离(或其他代价)最小。通常,我们计算检测框中心与模板位置中心的欧氏距离作为代价。 4. 匹配完成后,我们得到每个模板位置对应的检测框(如果有的话),然后根据该检测框内的灰度值判断是否涂卡。 至于DFS,在用户描述中用于“获取所有检测框的信息”。这里可能是指从图像中提取连通区域(涂点区域)的过程。传统的连通区域标记算法(如两遍扫描法)也可以使用DFS(或BFS)来实现。具体来说: - 对二值化后的图像(涂点区域为前景)进行扫描。 - 遇到前景像素时,使用DFS(或BFS)遍历其相邻的前景像素,从而标记整个连通区域。 - 然后根据连通区域的外接矩形得到检测框。 另一种可能是:答题卡通常是一个网格结构(行和列),而DFS用于遍历这个网格结构中的每个单元格(即每个选项框)。但这种情况DFS用得不多,通常用嵌套循环即可。所以更可能是用于连通区域标记。 下面我们详细解释两种算法。 一、匈牙利匹配算法: 原理:匈牙利算法基于二分图匹配。在二分图中,我们有两组节点:一组是模板中的标准位置(设为集合A),另一组是检测到的候选框(集合B)。我们构建一个代价矩阵C,其中C[i][j]表示将模板位置i与候选框j匹配的代价(如欧氏距离)。匈牙利算法的目标是为A中的每个位置在B中找到一个匹配,使得总代价最小。 实现步骤: 1. 初始化代价矩阵(大小为m×n,m为模板位置数,n为候选框数)。 2. 对矩阵进行变换,使每行每列至少有一个0。 3. 用最少的直线覆盖所有0元素。如果直线数等于矩阵的行数(或列数,取决于m和n的关系),则找到最优匹配;否则调整矩阵,重复步骤3。 4. 从0元素中选择独立匹配(即每行每列只有一个被选中)。 在答题卡匹配中,我们可能希望每个模板位置最多匹配一个候选框,而每个候选框也最多匹配一个模板位置。如果候选框数量多于模板位置,则有些候选框会被忽略(可能是噪声);如果少于,则有些模板位置没有匹配(表示该题未涂)。 二、深度优先遍历DFS): 原理:DFS是一种用于遍历或搜索树或图的算法。在图像处理中,我们可以将图像看作一个图,每个像素是一个节点,相邻像素(8邻域或4邻域)有边连接。DFS从一个起始节点开始,尽可能深地搜索图的分支,直到该分支的所有节点都被访问,然后回溯。 在连通区域标记中的应用: 1. 初始化一个与图像同尺寸的标记矩阵,初始值为0(未访问)。 2. 遍历图像的每个像素: - 如果该像素是前景且未访问,则开始DFS。 - 在DFS中,访问当前像素,标记为当前标签,然后递归访问其相邻的前景像素(8邻域或4邻域)。 3. 当DFS完成,一个连通区域就被标记了。然后标签加一,继续寻找下一个未标记的前景像素。 这样,我们就可以得到每个连通区域的像素集合,进而计算外接矩形作为检测框。 注意:在实际应用中,由于递归深度可能很大(尤其是大图像),可能会造成栈溢出。因此,有时会使用非递归DFS(用栈)或者使用BFS(队列)来实现。 在答题卡处理中,DFS用于连通区域标记,从而得到涂点的位置和范围,生成候选框。 结合引用[1]中提到的匈牙利算法(用于任务分配)和用户项目描述,我们可以这样总结: 1. 通过DFS(连通区域标记)得到候选框(涂点区域)的集合。 2. 使用匈牙利算法将候选框与模板中的标准位置进行匹配。 3. 匹配后,对每个匹配的候选框计算灰度值,判断涂卡情况。 代码实现方面,匈牙利算法有成熟的实现(如引用[1]中的Matlab代码),而DFS在图像连通区域标记中也是标准方法。 下面我们用伪代码简要说明: 连通区域标记(DFS)伪代码: ``` function find_connected_components(image): visited = matrix of zeros with same size as image labels = 0 for each pixel (i, j) in image: if image[i][j] is foreground and not visited[i][j]: labels += 1 stack = [(i, j)] visited[i][j] = True while stack is not empty: current = stack.pop() mark current with label = labels for each neighbor in 8-neighbors of current: if neighbor is foreground and not visited: push neighbor to stack visited[neighbor] = True return labeled_image ``` 匈牙利算法伪代码(简略): 由于实现较复杂,这里只给出步骤,具体实现可参考引用[1]的Matlab源码。 1. 构建代价矩阵C(m×n,m为模板位置数,n为候选框数),其中每个元素是模板位置i和候选框j的欧氏距离。 2. 使用匈牙利算法求解最小权匹配(即找到一组匹配,使得总距离最小)。 在匹配完成后,我们得到了每个模板位置对应的候选框(如果有的话),然后就可以判断该位置是否被涂。 最后,关于引用[2]的二叉树题目,虽然与当前问题无关,但体现了深度优先遍历在树结构中的应用(前序、中后序遍历都是DFS的不同形式)。在答题卡处理中,DFS用于图(图像像素的图)的遍历,而不是树。 参考文献: [1] 匈牙利算法多无人机任务分配(Matlab源码),说明匈牙利算法在任务分配中的应用。 [2] 二叉树遍历问题,说明DFS在树遍历中的应用(虽然与当前图像处理问题无直接关系,但DFS思想相同)。 注意:在回答中,我们按照要求使用LaTeX格式表示数学公式,如代价矩阵$C_{m\times n}$,欧氏距离公式$d=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}$等。 现在,我们按照用户要求生成相关问题。</think>### 匈牙利匹配算法深度优先遍历在答题卡处理中的原理与实现 #### 一、匈牙利匹配算法原理 在答题卡图像处理中,匈牙利算法用于解决**检测框与模板位置的匹配问题**,实现最优指派: 1. **问题建模** - 定义二分图:$G=(U \cup V, E)$ - $U$:检测到的涂点框集合($|U|=m$) - $V$:模板标准位置集合($|V|=n$) - 边权重$w_{ij}$:检测框$i$与模板位置$j$的空间距离 $$ w_{ij} = \| \text{center}_i - \text{center}_j \|_2 $$ 2. **算法步骤** ```python def hungarian(cost_matrix): # 初始化行列标记 row_min = np.min(cost_matrix, axis=1) col_min = np.min(cost_matrix - row_min[:, None], axis=0) while True: # 找到覆盖所有零的最小直线数 zero_mask = (cost_matrix == row_min[:, None] + col_min) line_count = min_line_cover(zero_mask) if line_count == min(m, n): break # 找到完美匹配 # 调整矩阵值 uncovered_min = np.min(cost_matrix[~covered]) row_min[~row_covered] += uncovered_min col_min[col_covered] -= uncovered_min return matching_indices # 最优匹配结果 ``` 3. **应用场景** - 将畸变矫正后的涂点区域与标准模板对齐 - 处理漏检/多检情况($m \neq n$) - 优化匹配时间复杂度至$O(n^3)$[^1] #### 二、深度优先遍历(DFS)原理 DFS用于**遍历答题卡网格结构**并提取检测框信息: 1. **网格建模** - 将答题卡建模为图$G=(V,E)$: - 顶点$V$:每个选项框 - 边$E$:相邻选项框的连接关系 $$ \begin{cases} v_{ij} & \text{表示第}i\text{行第}j\text{列选项} \\ e = (v_{ij}, v_{i(j+1)}) & \text{水平相邻} \\ e = (v_{ij}, v_{(i+1)j}) & \text{垂直相邻} \end{cases} $$ 2. **DFS实现流程** ```python def dfs(grid, i, j, visited, boxes): # 终止条件:越界或已访问 if i<0 or i>=rows or j<0 or j>=cols or visited[i][j]: return visited[i][j] = True boxes.append(grid[i][j]) # 记录当前检测框 # 递归遍历邻接位置 dfs(grid, i+1, j, visited, boxes) # 向下 dfs(grid, i, j+1, visited, boxes) # 向右 dfs(grid, i-1, j, visited, boxes) # 向上 dfs(grid, i, j-1, visited, boxes) # 向左 ``` 3. **应用场景** - 遍历所有选项框并存储坐标信息 - 处理非连续涂点(如跳过未作答题目) - 复杂度$O(mn)$($m$行$n$列网格) #### 三、系统集成流程 1. **预处理阶段** - 图像矫正:OpenCV透视变换 $$ \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = H \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} $$ - 二值化:自适应阈值分割 $$ \text{threshold} = \mu + k \cdot \sigma $$ 2. **核心处理流程** ```mermaid graph LR A[矫正图像] --> B[DFS遍历获取检测框] B --> C[匈牙利匹配模板位置] C --> D[灰度分析涂点区域] D --> E[对比标准答案] ``` 3. **涂点判定** - 计算涂点区域平均灰度: $$ \text{fill\_score} = 1 - \frac{\bar{I}_{\text{box}} - I_{\min}}{I_{\max} - I_{\min}} $$ - 判定阈值:$\text{fill\_score} > 0.7$ 视为已涂写 #### 四、实际应用挑战 1. **噪声处理** - 笔迹误判:通过形态学开运算消除小噪点 $$ A \circ B = (A \ominus B) \oplus B $$ 2. **匹配优化** - 添加约束:禁止跨题型匹配 - 代价函数改进: $$ w_{ij}' = w_{ij} + \lambda \cdot \mathbb{I}(\text{题型不匹配}) $$ 3. **性能对比** | 算法 | 时间复杂度 | 适用场景 | |---|---|---| | 匈牙利匹配 | $O(n^3)$ | 最优指派问题 | | DFS | $O(V+E)$ | 连通区域遍历 | | BFS | $O(V+E)$ | 最短路径搜索 | [^1]: 匈牙利算法在任务分配中的高效性使其成为答题卡匹配的理想选择 [^2]: DFS递归特性完美适配网格遍历需求 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值