1.二叉树的层序遍历
辅助队列
二叉树的层次遍历需要队列的原因在于层次遍历的核心思想是逐层遍历,而队列天然支持这种逐层的操作。
当我们从根节点开始遍历时,首先访问根节点,然后访问其子节点,接着访问孙子节点,以此类推。在每一层遍历时,我们需要确保按照从左到右的顺序访问节点。这就要求我们在处理每个节点时,先将其左右子节点暂存起来,以便后续按顺序访问。
使用队列可以很好地实现这一目的。我们可以将根节点入队,然后在每次处理一个节点时,将其左右子节点依次入队。这样,队列中的节点就按照层次
的顺序排列,而且在处理当前层节点时,下一层的节点已经按照顺序进入了队列,等待被处理。
因此,队列的先进先出(FIFO)特性非常适合层次遍历的需求,使得我们能够以按层级顺序逐个访问节点,从而实现二叉树的层次遍历。
public void levelorder()
{
if(this.root==null)
return ;
Queue<BinaryNode<T>> queue=new LinkedList<>();
queue.add(this.root);
while(!queue.isEmpty())
{
BinaryNode<T> p=queue.poll();
System.out.print(p.data+", ");
if(p.left!=null)
queue.add(p.left);
if(p.right!=null)
queue.add(p.right);
}
System.out.println();
}
2.线索二叉树
为什么需要线索二叉树 😄
在二叉树结构中,每个结点可以找到自己的左孩子和右孩子,但是想要找到他们的前驱和后继结点就会十分的难实现
。
要想实现可以这样:从头开始中序遍历这棵二叉树,与此同时增加一个指针pre用于指向当前结点的前驱结点**,这样当对比到当前结点的值和要寻找前驱结点的结点相同时,此时这个指针指向的就是结果(前驱)
实现代码如下
//中序遍历找前驱结点
public void findpreInOrder(BinaryNode<T> x)
{
if(x!=null) {
PreOrder(x.left);
visit(x);
PreOrder(x.right);
}
}
BinaryNode<T> pre=null;//前驱结点
BinaryNode<T> result=null;//最终要寻找的前驱结点
BinaryNode<T> p=null;//要寻找前驱结点的结点
public void visit(BinaryNode<T> q)
{
if(q==p)//如果当前访问的这个结点就是要找的结点
result=pre;//那么前驱结点就是要找的前驱结点
else
pre=q;//否则将当前结点记录为前驱结点,继续向下访问
}
1.中序线索二叉树
![](https://img-blog.csdnimg.cn/direct/af5d97bf8d5b4c4fbab8390d903dda39.png)
然后让pre指向当前结点。
接着就会访问G,G的left为null,同上道理,将其线索化,指向pre(D结点)。
接下来pre指向当前结点G,然后继续访问下一个结点B
此时pre的right不为null,我们此时应该把pre的right线索化,让right指向后继结点(正好是我们的X结点)
至此分析结束,或许同理,重复即可。
代码如下
ThreadNode<T> pre=null;
public void createInThread(ThreadNode<T> x){
if(x!=null)
{
InThread(x);
if (pre.right==null)//处理最后一个结点
pre.rtag=1;
}
}
public void InThread(ThreadNode<T> x)
{
if(x!=null)
{
InThread(x.left);
visit(x);
InThread(x.right);
}
}
private void visit(ThreadNode<T> x) {
System.out.println(x.data);
if(x.left==null)//为空那就可以线索化
{
x.left=pre;
x.ltag=1;
}
if(pre!=null&&pre.right!=null)
{
pre.right=x;
x.rtag=1;
}
//让pre指向当前结点
pre=x;
}
2.先序线索二叉树
为了避免转圈要在原来基础上进行改动,即加上判断left是指向左子树还是前驱。具体如下:
3.有了线索二叉树怎么找前驱和后继
1.找后继
//1.在中序线索二叉树中找到指定结点p的后继结点
public ThreadNode<T> findNextNode(ThreadNode<T> p)
{
//1.tag=1,right值即为后继
if(p.rtag==1)
return p.right;
//2.tag=0,其右子树第一个被访问的结点就是
else
return FirstNode(p.right);
}
//ps:找到以x为根的子树,中序遍历第一个被访问的结点
public ThreadNode<T> FirstNode(ThreadNode<T> x)
{
while(x.ltag==0)
x=x.left;
return x;
}
//2.利用上面就可以非递归的对二叉树进行中序遍历
public void Inorder(ThreadNode<T> x)
{
//找到中序遍历时第一个被访问的结点,然后依次访问它的后继即可
for(ThreadNode<T> i=FirstNode(x);i!=null;i=findNextNode(x))
System.out.println(x.data);
}
2.找前驱
//在中序线索二叉树中找到指定结点p的前驱结点
public ThreadNode<T> findPreNode(ThreadNode<T> p)
{
//1.tag=1,left值即为前驱
if(p.rtag==1)
return p.left;
//2.tag=0,其左子树最后一个被访问的结点就是
else
return LastNode(p.left);
}
//ps:找到以x为根的子树,中序遍历最后一个被访问的结点
public ThreadNode<T> LastNode(ThreadNode<T> x)
{
while(x.rtag==0)
x=x.right;
return x;
}