LeetCode 114.二叉树展开为链表 C语言

一 先序遍历写入数组再生成二叉树

1 递归遍历

int num;

void makelink(struct TreeNode* root, struct TreeNode*** link)
{
    if(!root)
        return ;
    num++;
    *link = (struct TreeNode**)realloc(*link, sizeof(struct TreeNode*) * num);
    (*link)[num - 1] = root;
    makelink(root -> left, link);
    makelink(root -> right, link);
}

void flatten(struct TreeNode* root) {
    num = 0;
    struct TreeNode** link = (struct TreeNode**)malloc(0);
    makelink(root, &link);
    for(int i = 1; i < num; i++)
    {
        struct TreeNode* pre = link[i - 1], *cur = link[i];
        pre -> left = NULL;
        pre -> right = cur;
    }
    free(link);
}

对二叉树进行先序遍历 将节点写入一个二叉树节点数组 最后将数组中的节点展开为右撇的二叉树 

先将数组申请一个大小为零的地址 将数组地址传入递归函数以便对数组所指的地址进行修改

将num定义为全局变量便于在递归函数中进行数组下标的更新

因为我们不知道树究竟有多少个节点 所以再每先序遍历一个节点时 都对数组所指向的地址realloc

这样将遍历到的元素存入当前数组的最后一个位置 下标为 num - 1;

函数跑完之后我们就得到了先序遍历的节点顺序 但树中节点之间的指向还没有改变

这时候再用for循环遍历一遍数组中的元素并修改他们之间的指向即可

2 迭代遍历

void flatten(struct TreeNode* root) {
    if(!root)
        return;
    struct TreeNode** sta = (struct TreeNode**)malloc(0);
    struct TreeNode** val = (struct TreeNode**)malloc(0);
    int num = 0, top = -1;
    struct TreeNode* node = root;
    while(node || top != -1)
    {
        while(node)
        {
            num++;
            sta = (struct TreeNode**)realloc(sta, sizeof(struct TreeNode*) * num);
            sta[++top] = node;
            val = (struct TreeNode**)realloc(val, sizeof(struct TreeNode*) * num);
            val[num - 1] = node;
            node = node -> left;
        }
        if(top != -1)
            node = sta[top--] -> right;
    }
    for(int i = 1; i < num; i++)
    {
        struct TreeNode* pre = val[i - 1], *cur = val[i];
        pre -> left = NULL;
        pre -> right = cur;
    }
    free(sta);
}

迭代遍历也是一样 只不过需要申请两个节点数组

一个用来实现栈的操作得到先序遍历的顺序

一个用来将节点按顺序存放起来

同样的 每遍历到一个节点都要用realloc额外申请一个节点的空间

二 先序遍历同时生成二叉树

一中必须先得到先序遍历的顺序在生成二叉树,因为如果同时生成二叉树的话就会改变原有二叉树的结构 这时再出栈得到的右子节点就是错误的

但如果我们改变栈存入的方式每次将左右子节点都存入栈 就可以再先序遍历的同时生成二叉树。

void flatten(struct TreeNode* root) {
    if(!root)
        return;
    struct TreeNode** sta = (struct TreeNode**)malloc(sizeof(struct TreeNode*));
    int top = 0, num = 1;
    sta[top] = root;
    struct TreeNode* pre = NULL, *cur = NULL;
    while(top != -1)
    {
        cur = sta[top--];
        if(pre)
        {
            pre -> left = NULL;
            pre -> right = cur;
        }
        struct TreeNode* left = cur -> left, *right = cur -> right;
        if(right)
        {
            num++;
            sta = (struct TreeNode**)realloc(sta, sizeof(struct TreeNode*) * num);
            sta[++top] = right;
        }
        if(left)
        {
            num++;
            sta = (struct TreeNode**)realloc(sta, sizeof(struct TreeNode*) * num);
            sta[++top] = left;
        }
        pre = cur;
    }
    free(sta);
}

上面的入栈方式是右子节点 左子节点

pre为上一层循环的节点 cur为本层循环节点

三 寻找前驱节点

上面两种方法都利用了数组 能不能省去数组直接对树进行操作呢

void flatten(struct TreeNode* root) {
    while(root)
    {
        if(root -> left)
        {
            struct TreeNode* next = root -> left;
            struct TreeNode* nnext = next;
            while(nnext -> right)
                nnext = nnext -> right;
            nnext -> right = root -> right;
            root -> left = NULL;
            root -> right = next;
        }
        root = root -> right;
    }
}

思路是先序遍历中 右子树都是跟在左子树最后一个节点后面的

我们先找到当前左子树中的最右侧元素 将右子树安在他的右子节点上

最后将右子节点换为左子节点将左子节点置空

循环遍历 root = root-> right

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值