题目源自于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); //只对下一层的第一个结点递归
}
};