C语言 使用树是不是浪费内存?

bvhaajcl  于 2023-02-18  发布在  其他
关注(0)|答案(3)|浏览(126)

在学习C时,我更关注内存分配,我们在大学里,基本上是用这段代码来构建一个二叉树的,每次在for循环中,都会创建一个指针,只有这样,我们才能把每个子树和它的子树的地址赋给节点,但是我们已经创建了超过10个指针了,对吗?,我们可以只拥有一个指针,然后不断更新它吗?就像递归的实现一样,主指针只被更新然后返回。

typedef struct tr {
    int data;
    struct tr *left, *right;
} btree, *btreeptr;

btree *createtree(int data) {
    btree *newtree;
    newtree = (btree *)malloc(sizeof(btree));
    newtree->left = NULL;
    newtree->right = NULL;
    newtree->data = data;// Is the same as : (*p).data, 
    return newtree;
}

int main() {
    btree *test[10];
    btreeptr baum;
    int i;

    for (i = 0; i < 10; i++) {
        test[i] = createtree(i);
    }

    baum = test[0]; 
    test[0]->left = test[1];
    test[0]->right = test[2];
    test[1]->left = test[3];
    test[1]->right = test[4];
    test[2]->right = test[5];
    test[4]->left = test[6];
    test[5]->left = test[7];
    test[5]->right = test[8];
    test[7]->left = test[9];

    printf("Size: %d\n", size(baum));
    printf("Leaves: %d\n", numberOfLeaves(baum));
    printf("Height: %d\n", height(baum));

    return 0;
}

如果我对记忆的理解是错误的,我希望能得到纠正。

ldioqlga

ldioqlga1#

也许问你的老师为什么他们选择这样做会更好;我只能猜测。我的猜测是,他们希望您编写由最后的三个printf语句调用的函数,这些函数都不依赖于树节点中存储的值。我非常肯定,稍后,您将编写在树中插入和删除节点的函数,此时分配的临时向量将消失。但是,目前,必须有某种机制来为至少一棵测试树创建树边。如果你没有树来尝试,你将如何验证你的sizeheightnumberOfLeaves的实现工作?
你的导师可能正试图教你一些非常重要的东西:当你在写一个系统时,你应该尽可能快地(在你用未测试的函数写几百行代码之前)测试所有的东西,并且尽可能不依赖于其他未测试的函数。“模拟”测试树是一种不依赖于树插入函数(还没有写)的测试技术。
最后,数据字段将变得很重要。目前,将节点号存储为数据字段的值可能会在调试过程中有所帮助,因为它可以让您看到在任何时间点正在处理哪个节点。学习调试也是一项非常重要的技能。因此,您最终可能会决定感谢设计该课程材料的人。

332nm8kg

332nm8kg2#

标题:使用树是不是浪费内存?
质疑自己的命运是件好事。
如果这个例子的目的是介绍一个被称为二叉树的数据结构(具有任意连接),那么这个例子就达到了它的目的。这样一个二叉树是一个经济的解决方案吗?
为了您的利益:

#include <stdio.h>

typedef struct tr {
    int data;
    struct tr *left, *right;
};

int main( void ) {
    unsigned char t[ 10 ] = { 0x12, 0x34, 0x05, 0x00, 0x60, 0x78, 0x00, 0x90 };

    for( size_t i = 0; i < sizeof t; i++ )
        printf( "node %d: left %d  right %d\n", i, t[i]>>4, t[i]&0xF );

    printf( "size of t[] = %ld\n", sizeof t );
    printf( "size of 10x struct tr = %ld\n", 10 * sizeof( struct tr ) );
    return 0;
}
node 0: left 1  right 2
node 1: left 3  right 4
node 2: left 0  right 5
node 3: left 0  right 0
node 4: left 6  right 0
node 5: left 7  right 8
node 6: left 0  right 0
node 7: left 9  right 0
node 8: left 0  right 0
node 9: left 0  right 0
size of t[] = 10
size of 10x struct tr = 120

(And,我的古代编译器使用4字节指针,而不是8字节指针。)
示例中的"有效载荷"限于二进制值0到9,因此一个"四位字节"(4位)满足所示的要求。
有些人可能会认为上面的初始化需要太多的工作。下面是对应于OP版本的初始化。

unsigned char t[ 10 ] = { 0 };

    t[0] = 1 << 4 | 2;
    t[1] = 3 << 4 | 4;
    t[2] = 0 << 4 | 5;
    t[4] = 6 << 4 | 0;
    t[5] = 7 << 4 | 8;
    t[7] = 9 << 4 | 0;

也许有人会用一个简单的宏重写这些语句。

1bqhqjot

1bqhqjot3#

这是浪费内存吗?嗯,在某种意义上。代码把一堆东西排列成一个指针二叉树,但不对它们做任何事情。这些代码最终可能会被用于某些事情,这可能就是为什么它被展示给你。
另一件有趣的事情是,这段代码无意中形成了一个堆,它是二叉树的一个子集,可以用一个连续的数组来表示,其中索引为i的任何节点的子节点仅仅是条目i*2+1i*2+2。这种风格的二叉树不需要指针,仅仅是因为所有的结构关系都由节点的位置暗示。尽管堆还有其他的需求和好处,但是如果初始数组中的值是随机的而不是连续的,那么这段代码就不能表示堆。
同样的,大多数二叉树不能用连续数组表示,对于那些,这可能是最有效的表示,它也有一个好处,那就是很容易递归处理。

相关问题