郭其先生利用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;
相关推荐
paeamecium32 分钟前
【PAT甲级真题】- Rational Sum (20)
数据结构·c++·python·算法·pat考试·pat
Lucifer三思而后行9 小时前
Veeam 备份 Oracle RAC 失败,是归档删除脚本的锅!
sql
拳里剑气10 小时前
C++算法:BFS解决FloodFill算法
c++·算法·bfs·宽度优先
wanderist.11 小时前
Lambda表达式在算法竞赛中的应用
java·开发语言·算法
稚南城才子,乌衣巷风流12 小时前
支配树(Dominator Tree)详解:概念、算法与应用
算法
稚南城才子,乌衣巷风流13 小时前
动态开点:原理、实现与应用场景
数据结构·算法
yyds_yyd_1008613 小时前
1464. 数组中两元素的最大乘积(2026.07.27)
数据结构·c++·算法·leetcode
互联网中的一颗神经元13 小时前
小白python入门 - 25. SQL 与表设计入门
数据库·python·sql
KaMeidebaby14 小时前
卡梅德生物技术快报 | 核酸适配体文库测序:核酸适配体文库测序的技术原理、实验流程与数据解析
前端·网络·数据库·人工智能·算法