二叉树
(一)一颗非空二叉树的第i层最多有2的(i-1)次方个结点。
(二)一颗深度为k的二叉树中,最多有2的(k-1)次方个结点
(三)对于一个非空的二叉树,若叶子结点数为A,度数为2的结点个数为B。则A=B+1
//二叉树的先序递归遍历
public void PreOrder(BiTree root){
if (root!=null){
Visit(root);//访问结点
PreOrder(root.left);//递归遍历左孩子
PreOrder(root.right);//递归遍历右孩子
}
}
//中序遍历或者后序遍历就是把Visit方法放在中间或者后面
//二叉树的非递归遍历
public void NRPreOrder(BiTree root){
//利用栈来实现遍历
BiTree stack[]=new BiTree[100];//建立一个100大小的栈
BiTree p;
int top=-1;//栈顶指针初始化
if (root==null) return;
p=root;
while (!(p==null&&top==-1)){
//当p不为空或者top不为-1时执行外层循环
while (p!=null){
//如果p不为空
Visit(p);//访问p结点的值
top++;//栈顶指针+1
stack[top]=p;//把p结点压入栈
p=p.left;//p指向p的左孩子
}
if (top<0)break;//如果执行了上部循环top仍然为空,说明p为空,跳出循环
else {
//返回一层,读出栈顶元素,然后让p指向栈顶元素的右孩子
p=stack[top];
top--;
p=p.right;
}
}
}
//二叉树的层次遍历
public void LevelOrder(BiTree root){
BiTree queue[]=new BiTree[100];//定义一个队列
int front,rear;//定义头指针和尾指针
if(root==null)return;
front=-1;
rear=0;
queue[rear]=root;
while (front!=rear){
front++;
Visit(queue[front]);
if (queue[front].left!=null){
rear++;
queue[rear]=queue[front].left;
}
if (queue[front].left!=null){
rear++;
queue[rear]=queue[front].left;
}
}
}
//简易的Visit方法
public void Visit(BiTree root){
System.out.println(root.value);
}
//定义的BiTree类
class BiTree{
int value;
BiTree left;
BiTree right;
}
二、线索二叉树
线索二叉树就是利用结点的空的左孩子来存储结点的直接前驱结点,当结点的右孩子为空时,
利用右孩子来存储结点的后继结点。
改变原来二叉链表的结构,为每个结点增设两个标志位域ltag和rtag,当ltag=0时,left指向左孩子,当ltag=1时,left指向结点的前驱结点,rtag同理
//中序线索二叉树的建立
BiThrTree pre;//pre指向当前遍历结点的前驱结点
public BiThrTree InOrderThr(BiThrTree root) {//中序遍历root,并将其中序线索化
BiThrTree head=new BiThrTree();//建立头结点
head.ltag=0;
head.rtag=1;
head.right=head;//右指针回指
if(root==null) head.left=head;//若二叉树为空,则左指针回指
else {
head.left=root;
pre=head;
InTreading(root);//中序线索化
pre.right=head;//最后一个结点线索化
pre.rtag=1;
head.right=pre;
}
return head;
}
public void InTreading(BiThrTree p){
if(p!=null){
InTreading(p.left);//左子树线索化
if(p.left==null){//前驱线索
p.ltag=1;
p.left=pre;
}
if (pre.right==null){//后继线索
pre.rtag=1;
pre.right=p;
}
pre=p;
InTreading(p.right);//右子树线索化
}
}
中序线索二叉树的遍历:
一:寻找结点的前驱结点
1.如果该结点的左标志为1,那么其左指针域做指向的结点便是它的前驱结点
2.如果该结点的左标志位0,那么说明该结点有左孩子,根据中序遍历的定义,它的前驱结点是以该节点的左孩子为
根节点的子树的最右结点。故需要沿着其左子树的右指针链向下查找,当某结点的右标志为1时,它就是所要找的前驱
结点。
public BiThrTree InPreNode(BiThrTree p){
BiThrTree pre;
pre=p.left;//令pre指向p的左孩子,如果左孩子是指向其前驱结点,就返回,如果有左孩子,则寻找以左孩子为 根节点的最右结点
if(p.ltag!=1){
while (pre.rtag==0) pre=pre.right;
}
return pre;
}
二:寻找结点的后继结点
1.如果该结点的右标志为1,那么其右指针域做指向的结点便是它的后继结点
2.如果该结点的右标志位0,那么说明该结点有右孩子,根据中序遍历的定义,它的后继结点是以该节点的右孩子为
根节点的子树的最左结点。故需要沿着其右子树的左指针链向下查找,当某结点的左标志为1时,它就是所要找的后继
结点。
public BiThrTree InPostNode(BiThrTree p){
BiThrTree post;
post=p.right;//令pre指向p的左孩子,如果左孩子是指向其前驱结点,就返回,如果有左孩子,则寻找以左孩子为根节点的最右结点
if(p.rtag!=1){
while (post.ltag==0) post=post.left;
}
return post;
}
三:线索树的遍历
以中序为例,利用在中序线索二叉树上寻找后继结点和前驱结点的算法,就可以遍历二叉树的所有结点,即先找到某许汴利的第一个结点,然后再一次查询其后继,或者先找到最后一个结点,然后再依次查询其前驱。
public BiThrTree Search(BiThrTree head){
BiThrTree p;
p=head.left;
while (p.ltag==0&&p!=head) p=p.left;//寻找中序遍历的第一个结点
while (p!=head){
p=InPostNode(p);//寻找它的后继结点
Visit(p);
}
}