簡體   English   中英

如何檢查兩個二叉樹是否包含相同的節點?

[英]How can I check if two binary trees contain the same nodes?

我正在嘗試實現一個檢查兩個二叉搜索樹是否相等的函數,節點的順序無關緊要。 但是我的實現不起作用。

我不允許將樹木展平成陣列。

這就是我到目前為止所擁有的:

int isIdentical(struct Node* root1, struct Node* root2)
{
    
    if (root1 == NULL && root2 == NULL)
        return 1;
    
    else if (root1 == NULL || root2 == NULL)
        return 0;
    else { 
        if (root1->data == root2->data && isIdentical(root1->left, root2->left)
            && isIdentical(root1->right, root2->right))
            return 1;
        else
            return 0;
    }
}

當提供包含節點tree A = 2 4 5 6Tree B = 2 5 4 6的樹時,輸出應為:

1 ,表示它們相等,但我得到的是0 我不確定我哪里出錯了。

這就是 Node 的實現方式:

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

創建一個遍歷treeA並檢查每個項目是否存在於treeB中的遞歸函數。 失敗時放棄搜索並返回0表示失敗。 它可以是你的功能

int isIdentical(struct Node* root1, struct Node* root2)

如果成功,再次調用該函數,將treeAtreeB的參數顛倒過來。 “檢查是否存在”操作可以是迭代和內聯的,因為它不需要回溯。

示例未嘗試過的代碼,以給出想法。

int isAllFound(struct Node* root1, struct Node* root2)
{
    // recursive parse of tree 1
    if (root1 == NULL)
        return 1;
    
    // iterative search of tree 2
    int found = 0;
    struct Node *root = root2;
    while(root != NULL) {
        if(root1->data == root->data) {
            found = 1;
            break;
        }
        if(root1->data < root->data)
            root = root->left;
        else
            root = root->right;
    }
    if(!found)
        return 0;
    
    // continue recursive parse of tree 1
    if(!isAllFound(root1->left, root2))
        return 0;
    if(!isAllFound(root1->right, root2))
        return 0;
    return 1;
}

然后像這樣打電話

if(isAllFound(treeA, treeB) && isAllFound(treeB, treeA))
    puts("Success!");

如果treeA的每個項目都可以在treeB中找到,並且treeA treeB找到,那么它們包含相同的數據。 前提是密鑰是唯一的。

您的函數只會比較具有完全相同結構的 2 棵樹。 如果樹的平衡不同,即使值相同,比較也會返回0

執行此比較並非易事,因為如果樹不平衡,它們可以具有任意深度。

您可以按深度第一順序遍歷第一棵樹以填充數組,然后按深度第一順序遍歷第二棵樹,檢查值是否與數組中的值相同。

這是一個簡單的實現:

#include <stdlib.h>

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

size_t tree_length(const struct Node *root) {
    return root ? 1 + tree_length(root->left) + tree_length(root->right) : 0;
}

void tree_store(int *array, size_t *pos, struct Node *node) {
    if (node) {
        tree_store(array, pos, node->left);
        array[++*pos - 1] = node->data;
        tree_store(array, pos, node->right);
    }
}

int tree_check(int *array, size_t *pos, struct Node *node) {
    if (node) {
        return tree_check(array, pos, node->left)
        &&     array[++*pos - 1] == node->data
        &&     tree_check(array, pos, node->right);
    } else {
        return 1;
    }
}

/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
    size_t len1 = tree_length(root1);
    size_t len2 = tree_length(root2);
    size_t pos;
    if (len1 != len2)
        return 0;

    if (len1 == 0)
        return 1;

    int *array = malloc(sizeof(*array) * len1);
    if (!array)
        return -1;
    pos = 0;
    tree_store(array, &pos, root1);
    pos = 0;
    int res = tree_check(array, &pos, root2);
    free(array);
    return res;
}

如果不允許將樹轉換為數組,則可以:

  • 標准化兩棵樹,然后使用簡單的比較器,但這會修改​​樹並且很困難。
  • 實現基於堆棧的迭代器並並行迭代兩棵樹。

這是后者的簡單實現:

#include <stddef.h>

struct Node {
    int data;
    struct Node *left;
    struct Node *right;
};

size_t max_size(size_t a, size_t b) {
    return a < b ? b : a;
}

size_t tree_depth(const struct Node *root) {
    return root ? 1 + max_size(tree_depth(root->left), tree_depth(root->right)) : 0;
}

int tree_next(const struct Node **stack, size_t *ppos, int *value) {
    size_t pos = *ppos;
    if (stack[pos] == NULL) {
        if (pos == 0)
            return 0;  // no more values
        pos--;
    } else {
        while (stack[pos]->left) {
            stack[pos + 1] = stack[pos]->left;
            pos++;
        }
    }
    *value = stack[pos]->data;
    stack[pos] = stack[pos]->right;
    *ppos = pos;
    return 1;
}

/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
    if (root1 == NULL || root2 == NULL)
        return root1 == root2;
    size_t depth1 = tree_depth(root1);
    size_t depth2 = tree_depth(root2);
    const struct Node *stack1[depth1];
    const struct Node *stack2[depth2];
    size_t pos1 = 0;
    size_t pos2 = 0;
    stack1[pos1++] = root1;
    stack2[pos2++] = root2;
    for (;;) {
        int value1, value2;
        int has1 = tree_next(stack1, &pos1, &value1);
        int has2 = tree_next(stack2, &pos2, &value2);
        if (!has1 && !has2)
            return 1;
        if (!has1 || !has2 || value1 != value2)
            return 0;
    }
}

為什么你認為他們是平等的? 他們不是。

tree A表示為2 4 5 6 ,我猜你是通過某種預排序或級別排序遍歷獲得的。 如果您的tree B (2, 5, 4, 6) 相等,那么通過相同類型的遍歷,您將獲得相同的順序。 如果遍歷相同,則它們不相等。

節點的順序無關緊要:

如果節點的順序無關緊要。 您可以做的一件事是對兩棵樹進行中序遍歷,然后從兩者中得到一個排序數組。 然后逐個元素比較兩個數組並聲明是否相等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM