郭其先生利用DeepSeek实现的PostgreSQL递归CTE实现DFS写法

测试用表

sql 复制代码
CREATE TABLE tree_nodes (
    id INT PRIMARY KEY,
    parent_id INT REFERENCES tree_nodes(id),
    name VARCHAR(50)
);

INSERT INTO tree_nodes VALUES 
(1, NULL, '根节点'),
(2, 1, '子节点1'),
(3, 1, '子节点2'),
(4, 2, '孙子节点1'),
(5, 2, '孙子节点2'),
(6, 3, '孙子节点3');

使用递归 CTE 实现 DFS:

sql 复制代码
WITH RECURSIVE dfs AS (
    -- 锚点:从根节点开始
    SELECT 
        id,
        parent_id,
        name,
        1 AS depth,
        ARRAY[id] AS path,
        ARRAY[name]::text[] AS path_names,
        FALSE AS is_cycle
    FROM tree_nodes
    WHERE parent_id IS NULL
    
    UNION ALL
    
    -- 递归部分:深度优先遍历
    SELECT 
        tn.id,
        tn.parent_id,
        tn.name,
        d.depth + 1,
        d.path || tn.id,
        d.path_names || tn.name,
        tn.id = ANY(d.path) AS is_cycle
    FROM tree_nodes tn
    JOIN dfs d ON tn.parent_id = d.id
    WHERE NOT d.is_cycle  -- 防止循环
)
-- 按深度优先顺序输出
SELECT 
    id,
    parent_id,
    name,
    depth,
    path,
    path_names
FROM dfs
ORDER BY path;

使用栈模拟 DFS

sql 复制代码
WITH RECURSIVE dfs_stack AS (
    -- 初始栈:包含根节点
    SELECT 
        1 AS step,
        id AS current_node,
        name,
        ARRAY[id] AS stack,
        ARRAY[]::INT[] AS visited,
        'visit' AS action
    FROM tree_nodes
    WHERE parent_id IS NULL
    
    UNION ALL
    
    -- 模拟栈操作:弹出、压入
    SELECT 
        d.step + 1,
        CASE 
            -- 如果有未访问的子节点,访问第一个
            WHEN EXISTS (
                SELECT 1 FROM tree_nodes tn 
                WHERE tn.parent_id = d.current_node 
                AND tn.id != ALL(d.visited)
            ) THEN (
                SELECT tn.id 
                FROM tree_nodes tn 
                WHERE tn.parent_id = d.current_node 
                AND tn.id != ALL(d.visited)
                ORDER BY tn.id
                LIMIT 1
            )
            -- 否则回溯
            ELSE d.stack[array_length(d.stack, 1) - 1]
        END,
        tn.name,
        CASE 
            -- 访问新节点:压栈
            WHEN EXISTS (
                SELECT 1 FROM tree_nodes tn 
                WHERE tn.parent_id = d.current_node 
                AND tn.id != ALL(d.visited)
            ) THEN d.stack || (
                SELECT tn.id 
                FROM tree_nodes tn 
                WHERE tn.parent_id = d.current_node 
                AND tn.id != ALL(d.visited)
                ORDER BY tn.id
                LIMIT 1
            )
            -- 回溯:出栈
            ELSE d.stack[1:array_length(d.stack, 1) - 1]
        END,
        d.visited || d.current_node,
        CASE 
            WHEN EXISTS (
                SELECT 1 FROM tree_nodes tn 
                WHERE tn.parent_id = d.current_node 
                AND tn.id != ALL(d.visited)
            ) THEN 'push'
            ELSE 'pop'
        END
    FROM dfs_stack d
    LEFT JOIN tree_nodes tn ON tn.id = d.current_node
    WHERE array_length(d.stack, 1) > 0  -- 栈不为空时继续
)
SELECT 
    step,
    current_node,
    name,
    stack,
    action,
    visited
FROM dfs_stack
ORDER BY step;
相关推荐
MATLAB代码顾问1 分钟前
混合粒子群-模拟退火算法(HPSO-SA)求解作业车间调度问题——附MATLAB代码
算法·matlab·模拟退火算法
Felven6 分钟前
C. Prefix Min and Suffix Max
算法
加农炮手Jinx6 分钟前
LeetCode 26. Remove Duplicates from Sorted Array 题解
算法·leetcode·力扣
加农炮手Jinx7 分钟前
LeetCode 88. Merge Sorted Array 题解
算法·leetcode·力扣
格林威7 分钟前
线阵工业相机:如何计算线阵相机的行频(Line Rate)?公式+实例
开发语言·人工智能·数码相机·算法·计算机视觉·工业相机·线阵相机
yueyue54310 分钟前
透过现象看本质:以fast_lio架构的整套算法的局部避障改为TEB算法为例深度探讨——如何成为一个合格的算法架构师?
算法·架构
梨花爱跨境10 分钟前
红人视频×A10算法:亚马逊转化率与流量闭环实战
算法
阿Y加油吧14 分钟前
二刷 LeetCode:75. 颜色分类 & 31. 下一个排列 复盘笔记
笔记·算法·leetcode
风筝在晴天搁浅16 分钟前
LeetCode 378.有序矩阵中第K小的元素
算法·矩阵
编程之升级打怪19 分钟前
MySQL数据库SQL语句简单用法
sql·mysql