尝试使用预购打印二叉树的顶视图

时间:2018-09-21 13:56:25

标签: c++ data-structures binary-tree

下面的两个代码

应该以相同的方式工作,但输出却不同。我试图尽我所能来调试代码,但是找不到错误。

CODE1:-

#include<iostream>
#include<stack>
#include<map>

using namespace std;

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

typedef struct label
{
    struct node* root;
    int disp;
}label;

int main() {

    struct node* n1 = (struct node*) malloc(sizeof(struct node));
    struct node* n2 = (struct node*) malloc(sizeof(struct node));
    struct node* n3 = (struct node*) malloc(sizeof(struct node));
    struct node* n4 = (struct node*) malloc(sizeof(struct node));
    struct node* n5 = (struct node*) malloc(sizeof(struct node));
    struct node* n6 = (struct node*) malloc(sizeof(struct node));
    struct node* n7 = (struct node*) malloc(sizeof(struct node));
    struct node* n8 = (struct node*) malloc(sizeof(struct node));
    struct node* n9 = (struct node*) malloc(sizeof(struct node));
    struct node* n10 = (struct node*) malloc(sizeof(struct node));
    struct node* n11 = (struct node*) malloc(sizeof(struct node));
    struct node* n12 = (struct node*) malloc(sizeof(struct node));
    struct node* n13 = (struct node*) malloc(sizeof(struct node));
    n1->data = 1;
    n2->data = 2;
    n3->data = 3;
    n4->data = 4;
    n5->data = 5;
    n6->data = 6;
    n7->data = 7;
    n8->data = 8;
    n9->data = 9;
    n10->data = 10;
    n11->data = 11;
    n12->data = 12;
    n13->data = 13;
    n1 -> left = n2;
    n1 -> right = n3;
    n2 -> left = n4;
    n2 -> right = n5;
    n4 -> left = n4 -> right = NULL;
    n5 -> left = n5 -> right = NULL;
    n3 -> left = n6;
    n3 -> right = n7;
    n6 -> left = n6 -> right = NULL;
    n7 -> left = n8;
    n7 -> right = NULL;
    n8 -> left = n9;
    n8 -> right = NULL;
    n9 -> left = n10;
    n9 -> right = NULL;
    n10 -> left = n11;
    n10 -> right = NULL;
    n11 -> left = n12;
    n11 -> right = NULL;
    n12 -> left = n13;
    n12 -> right = NULL;
    n13 -> left = NULL;
    n13 -> right = NULL;



    node* root = n1;

    stack<label*> s;
    map<int, int> m;

    label* var = new label();
    var -> root = root;
    var -> disp = 0;

    label* var1 = new label();

    s.push(var);

    while(!s.empty()) {
        m.insert( pair <int, int> ( var -> disp, var -> root -> data) );

        s.pop();
        if( var -> root -> right != NULL ) {
            var1 -> root = var -> root -> right;
            var1 -> disp = var -> disp + 1;
            s.push(var1);

        }
        if( var -> root -> left != NULL ) {
            var1 -> root = var -> root -> left;
            var1 -> disp = var -> disp - 1;
            s.push(var1);

        }
        if(!s.empty()) {

            var -> root = s.top() -> root;
            var -> disp = s.top() -> disp;
        }
    }
    map<int, int> :: iterator itr;
    for( itr = m.begin(); itr != m.end(); itr++ ) {
        cout<< itr -> second << endl;
    }

}

CODE2:-

#include<iostream>
#include<stack>
#include<map>

using namespace std;

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

typedef struct label
{
    struct node* root;
    int disp;
}label;

int main() {

    struct node* n1 = (struct node*) malloc(sizeof(struct node));
    struct node* n2 = (struct node*) malloc(sizeof(struct node));
    struct node* n3 = (struct node*) malloc(sizeof(struct node));
    struct node* n4 = (struct node*) malloc(sizeof(struct node));
    struct node* n5 = (struct node*) malloc(sizeof(struct node));
    struct node* n6 = (struct node*) malloc(sizeof(struct node));
    struct node* n7 = (struct node*) malloc(sizeof(struct node));
    struct node* n8 = (struct node*) malloc(sizeof(struct node));
    struct node* n9 = (struct node*) malloc(sizeof(struct node));
    struct node* n10 = (struct node*) malloc(sizeof(struct node));
    struct node* n11 = (struct node*) malloc(sizeof(struct node));
    struct node* n12 = (struct node*) malloc(sizeof(struct node));
    struct node* n13 = (struct node*) malloc(sizeof(struct node));
    n1->data = 1;
    n2->data = 2;
    n3->data = 3;
    n4->data = 4;
    n5->data = 5;
    n6->data = 6;
    n7->data = 7;
    n8->data = 8;
    n9->data = 9;
    n10->data = 10;
    n11->data = 11;
    n12->data = 12;
    n13->data = 13;
    n1 -> left = n2;
    n1 -> right = n3;
    n2 -> left = n4;
    n2 -> right = n5;
    n4 -> left = n4 -> right = NULL;
    n5 -> left = n5 -> right = NULL;
    n3 -> left = n6;
    n3 -> right = n7;
    n6 -> left = n6 -> right = NULL;
    n7 -> left = n8;
    n7 -> right = NULL;
    n8 -> left = n9;
    n8 -> right = NULL;
    n9 -> left = n10;
    n9 -> right = NULL;
    n10 -> left = n11;
    n10 -> right = NULL;
    n11 -> left = n12;
    n11 -> right = NULL;
    n12 -> left = n13;
    n12 -> right = NULL;
    n13 -> left = NULL;
    n13 -> right = NULL;



    node* root = n1;

    stack<label*> s;
    map<int, int> m;

    label* var = new label();
    var -> root = root;
    var -> disp = 0;


    s.push(var);

    while(!s.empty()) {
        m.insert( pair <int, int> ( var -> disp, var -> root -> data) );
        s.pop();
        if( var -> root -> right != NULL ) {
            label* var1 = new label();
            var1 -> root = var -> root -> right;
            var1 -> disp = var -> disp + 1;
            s.push(var1);   
        }
        if( var -> root -> left != NULL ) {
            label* var2 = new label();
            var2 -> root = var -> root -> left;
            var2 -> disp = var -> disp - 1;
            s.push(var2);
        }
        if(!s.empty()) {
            var -> root = s.top() -> root;
            var -> disp = s.top() -> disp;
        }
    }
    map<int, int> :: iterator itr;
    for( itr = m.begin(); itr != m.end(); itr++ ) {
        cout<< itr -> second << endl;
    }

}

代码2提供正确的输出,但代码1没有提供。 在Code2中,创建两个本地标签变量,并在 代码1创建了一个本地标签变量,并且值被覆盖。

Picture of created binary tree

2 个答案:

答案 0 :(得分:1)

您说,在CODE2中创建了2个局部变量。从技术上来说,您是对的,但我想有些误解:

查看行

label* var1 = new label();

在循环中: 您在堆(您通过new label()分配的内存)上创建一个 local 变量,数据。即使在下一次迭代中,该内存也会保留在那里。

然后,将指向已分配内存的指针推入堆栈。 您可能认为分配的内存内容已复制/推送到堆栈上。 这不是真的。 复制到堆栈上的是指向内存的指针的副本。 分配的内存不会以任何方式触及。

由于每次迭代循环都会在CODE2中分配新的内存,因此堆栈上的指针指向 distinct 存储区(label结构的不同实例)。

在CODE1中,您不会每次都创建内存,而只是分配一次并在每次迭代中重复使用相同的内存位置。

您将指针(在var1中)推到此位置到堆栈上,但是由于它始终是相同的指针,因此堆栈上的所有指针都指向相同的内存地址({ {1}}结构。

无论何时做

label

由于var1 -> root = var -> root -> right; var1 -> disp = var -> disp + 1; 始终指向相同的内存,因此您只需一遍又一遍地覆盖同一位置。

要提供一个简单的类比:

就像每次进行var1时一样,您需要一个新盒子,并用数字标记它。您删除其中的任何内容,然后将新内容放入其中。 当您将其压入堆栈时,就像将这个数字写到数字列表上一样。

在CODE2中,您在每次迭代中都使用一个 new 空框,将其标记为 new 号,将内容放入其中,然后在列表中写下新的新数字在纸上。

在CODE1中,您只有 ONE 框。 在每次迭代中,您都会再次使用此框,删除其中的内容,放一些新东西,然后将框号(每次都相同)添加到纸上的列表中。

当然,此框始终包含您在上一次迭代中输入的内容。之前迭代中放入的所有其他内容都将丢失,因为您替换了它。

另一个,尽管在这种情况下,较小的问题是您永远不会释放分配的内存。在这种情况下,这没什么大不了,因为在进程终止时,内存将以任何方式释放,但这是一个坏习惯,在更复杂的程序中会导致内存泄漏和最终进程终止。

答案 1 :(得分:0)

有点题外话,但是您可以简单地分配堆栈上的所有节点,这里不需要malloc / new。示例:

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

int main() {
    node a{1};
    node c{3};
    node b{2, &a, &c};
}