树:填充每个节点的右侧节点指针 populating-next-right-pointers-in-each-node-ii

填充每个节点的右侧节点指针1

给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

 

struct Node {

  int val;

  Node *left;

  Node *right;

  Node *next;

}

 

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

 

初始状态下示例,所有 next 指针都被设置为 NULL。

思路1:广度优先遍历

1先判空

2..广度优先遍历需要队列,将根节点入队

3.队不空时,出队首,保证该节点依次指向队列中的节点0<=i<queue.size-1

4.依次判断出队节点的左右孩子是否存在,若存在依次入队,每次size大小(每层节点个数)会变化

import java.util.LinkedList;

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void connect(TreeLinkNode root) {
        if(root==null){
            return ;
        }
       LinkedList<TreeLinkNode> queue=new LinkedList<>();
        queue.add(root);
        while(queue.size()>0){
            int size=queue.size();
             for(int i=0;i<size;i++){
                 TreeLinkNode node=queue.poll();
                 if(i<size-1){
                     node.next=queue.peek();
                 }
                 if(node.left!=null)  queue.add(node.left);
                 if(node.right!=null) queue.add(node.right);
             }
        }
        
    }
}

思路二:使用已建立的next指针

1.判空

2.当完美二叉树左孩子为空说明结束

3.head记录树节点,head不空分两种情况分配next指针

4.情况一:同一父节点(head不空)

5.情况二:不同父节点(保证head.next不空)

6.结束同一层遍历head=head.next

7.进入下一层:leftmost=leftmost.next

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void connect(TreeLinkNode root) {
        if(root==null){
            return;
        }
        TreeLinkNode leftmost=root;
        //完美二叉树没有左孩子说明结束啦
        while(leftmost.left!=null){
            TreeLinkNode head=leftmost;//head工作节点
            //head.next不空说明还有节点
            while(head!=null){
                //情况一:同一父节点
                head.left.next=head.right;
                //情况二:不同父节点,head是否有右节点
                if(head.next!=null){
                 head.right.next=head.next.left;
                }
                //同一层节点后移
                head=head.next;
            }
            //进入到下一层节点
            leftmost=leftmost.left;
        }
    }
}

填充每个节点的右侧节点指针2

 

如果给定的树可以是任意的二叉树呢?你之前的给出的算法还有效吗?

注意:

你只能使用常量的额外内存空间

解题思路:使用已建立的指针

一旦在某层的节点之间建立了 next 指针,那这层节点实际上形成了一个链表。基于该想法,提出降低空间复杂度的思路:

 

第 N 层节点之间建立 next 指针后,再建立第 N+1 层节点的 next 指针。因为可以通过 next 指针访问同一层的所有节点,所以使用第 N 层的 next 指针可以为第 N+1 层节点建立 next 指针。

1.从根节点开始。因为第 0 层只有一个节点,不需要处理。可以在上一层为下一层建立 next 指针。该方法最重要的一点是:位于第 N−1 层时为第 N 层建立 next 指针。一旦完成这些连接操作,移至第 N 层为第 N+1 层建立 next 指针。

2.当遍历到某层节点时,该层节点的 next 指针已经建立。这样就不需要队列从而节省空间每次只要知道下一层的最左边的节点,就可以从该节点开始,像遍历链表一样遍历该层的所有节点。

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    TreeLinkNode leftmost;
    TreeLinkNode pre;
     //处理下一层节点
    public void processchild(TreeLinkNode child){
        if(child!=null){
            //pre不空说明已经处理节点的下一层至少有一个孩子节点
            if(pre!=null){
                 this.pre.next=child;
            }else{
                //pre为空说明下一层没有节点,child是第一个节点,所以更新leftmost,
                this.leftmost=child;
            }
            //更新pre
            this.pre=child;
        }
    }
//处理该层节点
    public void connect(TreeLinkNode root) {
        if(root==null){
            return;
        }
        this.leftmost=root;//每层最左节点
        TreeLinkNode cur=leftmost;//当前处理节点的本层
        
        //如果leftmost结束说明整体结束
        while(this.leftmost!=null){
            cur=this.leftmost;//本层最新节点
            this.pre=null;//
            this.leftmost=null;//循环出口,如果没有孩子节点就可以结束了
            while(cur!=null){
                //处理该节点的左右孩子,处理下一层节点
                  this.processchild(cur.left);
                  this.processchild(cur.right);
                  //访问该层下一个节点
                  cur=cur.next;
            }
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值