二叉树中增加next指针 Populating Next Right Pointers in Each Node

题目源自于leetcode。

题目:Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL. Note:

  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,Given the following perfect binary tree,

         1
       /  \
      2    3
     / \  / \
    4  5  6  7

After calling your function, the tree should look like:

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NULL

思路:每个结点的next指针都指向其右边相邻的结点,这个顺序和树的层序遍历一致。因此,我们可以在层序遍历的过程中修改指针。

STL中queue的用法:二叉树的层序遍历一般需要借助队列来实现,先看一下STL中queue的用法:

queue<int> q;
queue的基本操作有:
入队:q.push(x);  将x接到队列的末尾。
出队:q.pop();  弹出队列的队头元素,注意,并不会返回被弹出元素的值。
访问队首元素:q.front(),即最早被压入队列的元素。
访问队尾元素:q.back(),即最后被压入队列的元素。
判断队列空:q.empty(),当队列空时,返回true。
访问当前队列中的元素个数:q.size()。

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if(root == NULL)
            return;
        queue<TreeLinkNode *> que;
        TreeLinkNode *p;
        que.push(root);
        
        unsigned int i=2;//为了使得每层的最右结点是2的n次幂
        while(!que.empty())
        {
            p = que.front();
            que.pop();
            
            if(p->left != NULL)
                que.push(p->left);
            if(p->right != NULL)
                que.push(p->right);

            if(i&(i-1)) //处理每层的非最右结点的next
                p->next = que.front();
                
            i++;
        }
        
    }
};

注意:每一层的最右结点是特殊的,它的next指针为NULL,但是层序的时候在队列中无法区分是不是到了下一层。所以我利用满二叉树的数学性质来判断是否是最右结点。这里使用了一个位运算小技巧来判断一个数是否是2的n次幂。i&(i-1)是将i的二进制的最右边的1变为0,对于2的n次幂,其无符号数只有最高位是1,所以i&(i-1)得到的是0。


方法二:在队列中加入NULL来作为层与层之间的分割。这样的方法对于任何二叉树一样适用。

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
	public:
		void connect(TreeLinkNode *root) {
			if(root == NULL)  
				return;  

			queue<TreeLinkNode *> q;  
			q.push(root);  
			q.push(NULL);
			TreeLinkNode *k;
			while(!q.empty())  
			{  
				k = q.front();  
				q.pop();
				if(k == NULL)  
				{  
					if(!q.empty()) // 如果后面还有元素,就再一个NULL  
						q.push(NULL);
				}
				else
				{
				    k->next = q.front();
				    if(k->left != NULL)  
					    q.push(k->left);  
				    if(k->right != NULL)  
					    q.push(k->right);  
				}
			}  

		}
};

方法三:上面两个方法都没有做到空间复杂度为O(1)。所以还是不要用队列结构了。从根节点开始,就在遍历的时候就把孩子结点横向串接起来。该方法的时间复杂度为O(N),空间复杂度O(1)。

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        
        if(root == NULL)
            return;
        TreeLinkNode head(0);
        TreeLinkNode *cur, *pre;
        cur = root;
        pre = &head;//head作为链表头结点,把root的下一层结点串联起来
        while(cur != NULL)
        {
            if(cur->left != NULL)
            {
                pre->next = cur->left;
                pre = pre->next;
            }
            if(cur->right != NULL)
            {
                pre->next = cur->right;
                pre = pre->next;
            }
            cur = cur->next;
        }
        connect(head.next); //只对下一层的第一个结点递归
    }
};


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值