访问每个节点

时间:2012-04-20 10:18:15

标签: algorithm haskell recursion

我有一个爱好项目,关于创建一个存储标识号的树。我曾经使用过数字,存储在节点,节点可以是0 1 2 3 4 5 6 7 8 9。

创建树后,我想从树中创建列表。但是,我找不到一个算法来管理我的目标。

我想要的是什么:

      "recompose tree"  will return list of numbers. For below tree it should be 

            [ 2, 21, 243, 245, 246, 78, 789 ]  


                               Root 
                           /          \         
                        2*               7
                      /      \             \                  
                   1*         4              8*    
                            / \  \            \         
                           3*  5* 6*           9*

       my data type :  data ID x = ID ( ( x, Mark ), [ ID x ] ) 
                       data Mark = Marked | Unmarked

       EDIT:

       for convenience : * shows it is marked
                         I have stored digit as char, actually not 1, 
                            it is stored as'1' 

你有建议我怎么做吗? (建议被认为是算法)

2 个答案:

答案 0 :(得分:3)

怎么样?
recompose :: Num a => ID a -> [a]
recompose = go 0
  where
    go acc (ID ((n, Marked), ids)) =
      let acc' = 10 * acc + n
      in  acc' : concatMap (go acc') ids
    go acc (ID ((n, Unmarked), ids)) =
      let acc' = 10 * acc + n
      in  concatMap (go acc') ids

也就是说,我们遍历树,同时累积从根到节点的路径的值。在每个节点,我们通过将路径的值乘以10并将节点的值与其相加来更新累加器。遍历生成标记节点的所有累加器值的列表:因此,在标记节点处,我们将累加器值添加到列表中,对于未标记的节点,我们只传播我们为节点的子节点收集的列表。

我们如何计算节点子节点的列表?我们通过将它映射到子列表上来递归调用遍历函数(go)给所有子节点。这给了我们一个列表,我们连接这些列表以获得单个列表。 (concatMap f xs只是concat (map f xs))concat . map f。)

在属性 - 语法术语中:累加器用作继承属性,而返回的列表是合成属性。

作为一种改进,我们可以引入一个辅助函数isMarked

isMarked :: Mark -> Bool
isMarked Marked   = True
isMarked Unmarked = False

这样我们就可以简明扼要地写了

recompose :: Num a => ID a -> [a]
recompose = go 0
  where
    go acc (ID ((n, m), ids)) =
      let acc'   = 10 * acc + n
          prefix = if isMarked m then (acc' :) else id
      in  prefix (concatMap (go acc') ids)

答案 1 :(得分:2)

BTW:这甚至可以在sql中完成:

DROP SCHEMA tmp CASCADE;

CREATE SCHEMA tmp ;
SET search_path='tmp';

CREATE TABLE the_tree
        ( id CHAR(1) NOT NULL PRIMARY KEY
        , parent_id CHAR(1) REFERENCES the_tree(id)
        );
INSERT INTO the_tree(id,parent_id) VALUES
 ( '@', NULL)
,( '2', '@')
,( '7', '@')
,( '1', '2')
,( '4', '2')
,( '3', '4')
,( '5', '4')
,( '6', '4')
,( '8', '7')
,( '9', '8')
        ;

WITH RECURSIVE sub AS (
        SELECT id, parent_id, ''::text AS path
        FROM the_tree t0
        WHERE id = '@'
        UNION
        SELECT t1.id, t1.parent_id, sub.path || t1.id::text
        FROM the_tree t1
        JOIN sub ON sub.id = t1.parent_id
        )
SELECT sub.id,sub.path
FROM sub
ORDER BY path
        ;

结果:(postgresql)

NOTICE:  drop cascades to table tmp.the_tree
DROP SCHEMA
CREATE SCHEMA
SET
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "the_tree_pkey" for table "the_tree"
CREATE TABLE
INSERT 0 10
 id | path 
----+------
 @  | 
 2  | 2
 1  | 21
 4  | 24
 3  | 243
 5  | 245
 6  | 246
 7  | 7
 8  | 78
 9  | 789
(10 rows)