栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Leetcode95.不同的二叉搜索树——如何真正实现动态分配内存

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Leetcode95.不同的二叉搜索树——如何真正实现动态分配内存

题目简述

生成并返回所有由n个节点组成的节点值从1~n互不相同的二叉搜索树,可以按任意顺序返回答案
示例:

什么是二叉搜索树?(我看到题目的第一反应…)

简单解释就是:
左子树节点值<根节点值 且 右子树节点值>根节点值
并且左子树和右子树也是二叉搜索树
(听这个解释就有种浓浓的递归味)(二叉树题解皆可递归)

我的first通过答案(又臭又长,可跳过)



 //函数声明
struct TreeNode** T(int* array, int size, int* returnSize);

struct TreeNode** generateTrees(int n, int* returnSize){
    int *array = (int *)malloc(sizeof(int) * n);	//1~n的数组
    int *returnNum = (int *)malloc(sizeof(int));	//返回值forest的大小
    *returnNum = 0;
    for(int i=0;ival = array[i];
            forest[num]->left = NULL;
            forest[num++]->right = NULL;
        }else if(leftForest == NULL && rightForest != NULL){
            for(int j=0;j<*rightnum;j++){
                forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
                forest[num]->val = array[i];
                forest[num]->left = NULL;
                forest[num++]->right = rightForest[j];
            }
        }else if(leftForest != NULL && rightForest == NULL){
            for(int j=0;j<*leftnum;j++){
                forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
                forest[num]->val = array[i];
                forest[num]->left = leftForest[j];
                forest[num++]->right = NULL;
            }
        }else{
            for(int j=0;j<*leftnum;j++){
                for(int k=0;k<*rightnum;k++){
                    forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
                    forest[num]->val = array[i];
                    forest[num]->left = leftForest[j];
                    forest[num++]->right = rightForest[k];
                }
            }
        }
    }
	//好多忘记free的地方,内存泄露危机
    *returnNum = num;
    return forest;
}
官方优秀解法:
struct TreeNode** buildTree(int start, int end, int* returnSize) {
    if (start > end) {
        (*returnSize) = 1;
        struct TreeNode** ret = malloc(sizeof(struct TreeNode*));
        ret[0] = NULL;
        return ret;
    }
    *returnSize = 0;
    struct TreeNode** allTrees = malloc(0);
    // 枚举可行根节点
    for (int i = start; i <= end; i++) {
        // 获得所有可行的左子树集合
        int leftTreesSize;
        struct TreeNode** leftTrees = buildTree(start, i - 1, &leftTreesSize);

        // 获得所有可行的右子树集合
        int rightTreesSize;
        struct TreeNode** rightTrees = buildTree(i + 1, end, &rightTreesSize);

        // 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
        for (int left = 0; left < leftTreesSize; left++) {
            for (int right = 0; right < rightTreesSize; right++) {
                struct TreeNode* currTree = malloc(sizeof(struct TreeNode));
                currTree->val = i;
                currTree->left = leftTrees[left];
                currTree->right = rightTrees[right];

                (*returnSize)++;
                allTrees = realloc(allTrees, sizeof(struct TreeNode*) * (*returnSize));
                allTrees[(*returnSize) - 1] = currTree;
            }
        }
        free(rightTrees);
        free(leftTrees);
    }
    return allTrees;
}

struct TreeNode** generateTrees(int n, int* returnSize) {
    if (!n) {
        (*returnSize) = 0;
        return NULL;
    }
    return buildTree(1, n, returnSize);
}

直观打击:

二者对比——改进之处: 递归函数的参数列表设计

我选择传递数组,而官方解法是传递两个端点值start和end
前者需要数组初始化,时间受n影响,而后者不受n影响,明显后者更优

if-else的去除

我和官方都选择了递归解法,但是代码长度有很明显的区别,关键就在于递归获得左子树集和右子树集之后,官方直接两层for循环嵌套,枚举结果。而我则是做了if-else判断,有四种可能走向
直观对比:

//我的解法:
 if(leftForest == NULL && rightForest == NULL){
    forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
     forest[num]->val = array[i];
     forest[num]->left = NULL;
     forest[num++]->right = NULL;
 }else if(leftForest == NULL && rightForest != NULL){
     for(int j=0;j<*rightnum;j++){
         forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
         forest[num]->val = array[i];
         forest[num]->left = NULL;
         forest[num++]->right = rightForest[j];
     }
 }else if(leftForest != NULL && rightForest == NULL){
     for(int j=0;j<*leftnum;j++){
         forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
         forest[num]->val = array[i];
         forest[num]->left = leftForest[j];
         forest[num++]->right = NULL;
     }
 }else{
     for(int j=0;j<*leftnum;j++){
         for(int k=0;k<*rightnum;k++){
             forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
             forest[num]->val = array[i];
             forest[num]->left = leftForest[j];
             forest[num++]->right = rightForest[k];
         }
     }
 }
//官方解法:
for(int j=0;j<*leftnum;j++){
    for(int k=0;k<*rightnum;k++){
        forest[num] = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        forest[num]->val = array[i];
        forest[num]->left = leftForest[j];
        forest[num++]->right = rightForest[k];
    }
}

官方解法就是我的if-else中的第四种情况,泪奔了
为什么会有这种区别?
我使用if-else结构进行判断,是因为存在子树集为空,长度为0的情况,这种情况对于for循环来说不满足循环条件
而官方的解决方案很简单:创建一个长度为1/存在一棵树的forest,而这棵树为NULL(这样就可以参与for循环了)

动态分配forest内存(malloc和realloc函数使用)

我对于动态分配内存的认知仅限于malloc函数
malloc函数对于空间大小已知的情况非常适用,例如我要创建一个大小为**n(变量)**的int类型数组

int *p = (int *)malloc(sizeof(int) * n);

但是对于这道题目,我并不知道解的个数,只能蒙一个比较大的数字,确保空间足够使用(一开始猜了100,不够——>1000——>10000)
但是这样对于n的值较小的情况就会造成空间大量浪费,完全不算动态分配空间了。
官方解法给我指了条明路——realloc函数,使得空间在需要的时候动态+1+1+1…
来看具体使用过程:

for (int left = 0; left < leftTreesSize; left++) {
    for (int right = 0; right < rightTreesSize; right++) {
    	//先创建一棵临时树
        struct TreeNode* currTree = malloc(sizeof(struct TreeNode));
        currTree->val = i;
        currTree->left = leftTrees[left];
        currTree->right = rightTrees[right];

        (*returnSize)++;
        //动态增加forest大小,增加一棵树的大小
        //space = realloc(space, sizeof(type)*newSize);
        //realloc函数可以用于动态增大或者减小空间
        
        allTrees = realloc(allTrees, sizeof(struct TreeNode*) * (*returnSize));
        allTrees[(*returnSize) - 1] = currTree;
    }
}
增加对左子树集和右子树集的free操作

这个纯粹是我忘记free了,低级问题

free(rightTrees);
free(leftTrees);

本人菜鸡一只
如有错误,欢迎指正,卑微鞠躬

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/290981.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号