Removing duplicate subtrees from binary tree

前端 未结 3 654
清歌不尽
清歌不尽 2021-02-15 07:55

I have to design an algorithm under the additional homework. This algorithm have to compress binary tree by transforming it into DAG by removing repetitive subtrees and redirect

3条回答
  •  爱一瞬间的悲伤
    2021-02-15 08:32

    This happens when constructing oBDDs. The Idea is: put the tree into a canonical form, and construct a hashtable with an entry for every node. Hash function is a function of the node + the hash functions for the left/right child nodes. Complexity is O(N), but only if one can rely on the hashvalues being unique. The final compare (e.g. for Resolving collisions) will still cost o(N*N) for the recursive subtree <--> subtree compare. More on BDDs or the original Bryant paper

    The hashfunction I currently use:

    #define SHUFFLE(x,n) (((x) << (n))|((x) >>(32-(n))))
    /* a node's hashvalue is based on its value
     * and (recursively) on it's children's hashvalues.
     */
    #define NODE_HASH2(l,r) ((SHUFFLE((l),5)^SHUFFLE((r),9)))
    #define NODE_HASH3(v,l,r) ((0x54321u*(v) ^ NODE_HASH2((l),(r))))
    

    Typical usage:

    void node_sethash(NodeNum num)
    {
    if (NODE_IS_NULL(num)) return;
    
    if (NODE_IS_TERMINAL(num)) switch (nodes[num].var) {
            case 0: nodes[num].hash.hash= HASH_FALSE; break;
            case 1: nodes[num].hash.hash= HASH_TRUE; break;
            case 2: nodes[num].hash.hash= HASH_FALSE^HASH_TRUE; break;
            }
    else if (NODE_IS_NAMED(num)) {
            NodeNum f,t;
            f = nodes[num].negative;
            t = nodes[num].positive;
            nodes[num].hash.hash = NODE_HASH3 (nodes[num].var, nodes[f].hash.hash, nodes[t].hash.hash);
            }
    return ;
    }
    

    Searching the hash table:

    NodeNum *hash_hnd(NodeNum num, int want_exact)
    {
    unsigned slot;
    NodeNum *ptr, this;
    if (NODE_IS_NULL(num)) return NULL;
    
    slot = nodes[num].hash.hash % COUNTOF(hash_nodes);
    
    for (ptr = &hash_nodes[slot]; !NODE_IS_NULL(this= *ptr); ptr = &nodes[this].hash.link) {
            if (this == num) break;
            if (want_exact) continue;
            if (nodes[this].hash.hash != nodes[num].hash.hash) continue;
            if (nodes[this].var != nodes[num].var) continue;
            if (node_compare( nodes[this].negative , nodes[num].negative)) continue;
            if (node_compare( nodes[this].positive , nodes[num].positive)) continue;
                    /* duplicate node := same var+same children */
            break;
            }
    return ptr;
    }
    

    The recursive compare function:

    int node_compare(NodeNum one, NodeNum two)
    {
    int rc;
    
    if (one == two) return 0;
    
    if (NODE_IS_NULL(one) && NODE_IS_NULL(two)) return 0;
    if (NODE_IS_NULL(one) && !NODE_IS_NULL(two)) return -1;
    if (!NODE_IS_NULL(one) && NODE_IS_NULL(two)) return 1;
    
    if (NODE_IS_TERMINAL(one) && !NODE_IS_TERMINAL(two)) return -1;
    if (!NODE_IS_TERMINAL(one) && NODE_IS_TERMINAL(two)) return 1;
    
    if (VAR_RANK(nodes[one].var)  < VAR_RANK(nodes[two].var) ) return -1;
    if (VAR_RANK(nodes[one].var)  > VAR_RANK(nodes[two].var) ) return 1;
    
    
    rc = node_compare(nodes[one].negative,nodes[two].negative);
    if (rc) return rc;
    rc = node_compare(nodes[one].positive,nodes[two].positive);
    if (rc) return rc;
    
    return 0;
    }
    

提交回复
热议问题