每日一题(力扣)二叉树展开为链表(C语言实现)

给定一个二叉树,原地将它展开为一个单链表。

例如,给定二叉树

    1
   / \
  2   5
 / \   \
3   4   6

将其展开为:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

我们不难发现这个链表展开的顺序就是二叉树的先序遍历,但是题目要求我们是原地展开,所以我们需要一个东西来储存二叉树的先序遍历顺序,然后再循环建立链表。

方法一

前序遍历

所以我们第一种实现函数如下,主要是利用指向结构体root类型的指针数组来实现。

int num;
void flatten(struct TreeNode* root){
        num=0;//结点数量
        struct TreeNode **l=(struct TreeNode **)malloc(0);//节点数量开始为0,后来根据结点的不同来扩大容量.
        preOrderTravesal(root,&l);//先序访问结点,记录结点顺序并存储到指针数组中
        for(int i=1;i<num;i++)
        {
            struct TreeNode *pre=l[i-1],*cur=l[i];
            pre->left=NULL;
            pre->right=cur;
        }
        free(l);//最后释放指针数字
}
void preOrderTravesal(struct TreeNode *root,struct TreeNode ***l)//***l是指向**l的指针数组
{  
    if(root)//树不为空的时候
    {
        num++;//树的结点+1
        (*l)=(struct TreeNode**)realloc((*l),sizeof(struct TreeNode**)*num);//realloc函数是扩展malloc函数开辟的空间,我们具体根据Num的值来开辟空间
        (*l)[num-1]=root;
        preOrderTravesal(root->left,l);//递归访问左子树先序遍历
        preOrderTravesal(root->right,l);//递归访问右子树先序遍历
    }
}

最后得到的结果是这样:

在这里插入图片描述
我们不难发现,执行速度还是可以的,但是空间消耗太大了。由此我们需要再想一种更有效率的办法。

方法二

寻找前驱结点

我们对这道题目的具体做法是,对于当前节点,如果他的左子节点不为空,则在其左子树中找到最右边的节点,作为前驱的节点,将当前节点的右子节点赋给前驱节点的右子节点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

执行代码如下:

void flatten(struct TreeNode* root){
    struct TreeNode *current=root;//目前结点指向根节点
    while(current!=NULL)//循环
    {
        if(current->left)//我们每次都去找当前结点的左子树,左子树有结点,再去找左子树的右子树,右子树的最后一个节点为前驱结点,若没有右子树,则左子树的最后一个节点为前驱结点。
        {
            struct TreeNode *next=current->left;
            struct TreeNode *pre=next;
            while(pre->right)
            {
                pre=pre->right;//递归找到前驱结点
            }
        
        pre->right=current->right;//将目前结点的右子树全部连接到前驱结点的右子树上去
        current->right=next;//目前结点右子树连接目前结点的左子树
        current->left=NULL;//目前结点左子树置为空
        }
        current=current->right;//递归找目前结点的右子树
    }
}

结果如下
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值