二叉树
树是一种非线性数据结构;
只有一个根节点,其余为不相交的有限集合;
基本术语:
- 度:节点拥有的子树数;度为0表示为叶子节点;树的度指树内各结点度的最大值;
- 树的层次:根为第一层,根孩子为第二层;树中节点最大层次为树的深度;
- 对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0(树叶——当前节点);
- 对于任意节点n,n的深度为从根到n的唯一路径长度(根深度为0);
二叉树(Binary Tree)
定义:每个节点至多只有两个子树;有左右之分,不可调换位置;
性质:
- 二叉树第i层至多有2 ^(i-1)个节点;
- 深度k的二叉树至多有2^(k)-1个节点;
- 任意二叉树终端节点数n0,度为2的节点数为n2,n0=n2+1;
分支总数与节点数关系:除根节点外,每个节点对应一个分支,所以节点数n=B+1;
分支数为度为1与度为2的之和,所以B=n1+2n2;
n=n0+n1+n2;
n=n1+2n2+1;
所以n0=n2+1;
数据结构:
抽象数据类型:
Java
class BinNode
{
private int data;
private BinNode leftchild;
private BinNode rightchild;
}
class BinTree
{
//根节点
private BinNode root;
//返回根节点
public BinNode Root()
{
return root;
}
//二叉树是否为空
public boolean IsEmpty()
{
if(root==null)
{
return true;
}
else
return false;
}
//查找二叉树
public boolean FindNode(int e)
{
//根节点为空,查找失败
if(IsEmpty())
{
return false;
}
BinNode rear=root;
while(rear)
{
if(e<rear.data)
{
rear=rear.leftchild;
}
else if(e>rear.data)
{
rear=rear.rightchild;
}
else
{
return true;//相等时,找到;
}
}
//跳出循环,未找到相等数据;
return false;
}
//插入节点;
public boolean InsertNode(int e)
{
//根节点为空;
if(root==null)
{
root=new BinNode();
root.data=e;
return root;
}
BinNode rear=root;
BinNode parent=null;
while(true)
{
if(e<rear.data)
{
parent=rear;
rear=rear.leftchild;
if(rear==null)
{
rear=new BinNode();
rear.data=e;
parent.leftchild=rear;
break;
}
}
else if(e>rear.data)
{
parent=rear;
rear=rear.rightchild;
if(rear==null)
{
rear=new BinNode();
rear.data=e;
parent.rightchild=rear;
break;
}
}
else
{
return false;
}
}
return true;
}
//删除节点
public boolean DeleteNode(int e)
{
if(IsEmpty())
{
return false;
}
Node rear=root;
Node parent=null;
//设定标志位,为左孩子为true;
boolean isLeftchild=false;//判断删除元素后,直接后继连接在父节点左孩子或是右孩子;
while(rear.data!=e)
{
//查找该元素,找不到直接返回false;
//找到该元素,保存其父节点;
parent=rear;
if(e<rear.data)
{
rear=rear.leftchild;
isLeftchild=true;
}
else (e>rear.data)
{
rear=rear.rightchild;
isLeftchild=false;
}
if(rear==null)
{
return false;
}
}
//找到元素,parent为父节点,rear为待删除节点;
//分情况删除节点;
//1>删除节点为叶子节点
if(rear.leftchild==null&&rear.rightchild==null)
{
//为根节点;
if(rear==root)
{
root=null;
}
else if(isLeftchild)
{
parent.leftchild=null;
}
else
{
parent.rightchild=null;
}
return true;
}
// 2>删除节点有一个孩子
if(rear.leftchild!=null&&rear.rightchild==null)//删除节点有左孩子;
{
//如果为根节点
if(rear==root)
{
root=rear.leftchild;
}
else if(isLeftchild)
{
parent.leftchild=rear.leftchild;
}
else
{
parent.rightchild=rear.leftchild;
}
return true;
}
else if(rear.leftchild==null&&rear.rightchild!=null)
{
if(rear==root)
{
root=rear.rightchild;
}
else if(isLeftchild)
{
parent.leftchild=rear.rightchild;
}
else
{
parent.rightchild=rear.rightchild;
}
return true;
}
// 3>删除节点有左,右孩子同时存在;
if(rear.leftchild!=null&&rear.rightchild!=null)
{
//待删除节点的直接后继为大于当前节点的后继集合中权值最小的节点
Node replacechild=successorNode(rear);
if(rear==root)
{
root=replacechild;
}
else if(isLeftchild)
{
parent.leftchild=replacechild;
}
else
{
parent.rightchild=replacechild;
}
return true;
}
}
//查找删除节点的直接后继;
public BinNode successorNode(BinNode delNode)
{
BinNode successorParent=delNode;//后继节点的父节点
BinNode successor=delNode;//后继节点;
BinNode rear=delNode.rightchild;//比删除节点权值大的在其右子树中;
//遍历右子树找右子树中的最小值
while(rear!=null)
{
successorParent=successor;
successor=rear;
rear=rear.leftchild;
}
//待删除节点右孩子无左孩子时,待删除节点右孩子即为直接后继;
if(successor==delNode.rightchild)
{
return successor;
}
if(successor!=delNode.rightchild)
{
successorParent.leftchild=successor.rightchild;
successor.rightchild=delNode.rightchild;//后继替代删除节点,删除节点的右孩子为后继节点的右孩子;
}
return successor;
}
//前序遍历(递归)
public void preOrder(BinNode rear)
{
if(rear!=null)
{
System.out.print(rear.data+" ");
preOrder(rear.leftchild);
preOrder(rear.rightchild);
}
}
//中序遍历(递归)
public void midOrder(BinNode rear);
{
if(rear!=null)
{
midOrder(rear.leftchild);
System.out.print(rear.data+" ");
midOrder(rear.rightchild);
}
}
//后序遍历(递归)
public void postOrder(BinNode rear)
{
if(rear!=null)
{
postOrder(rear.leftchild);
postOrder(rear.rightchild);
System.out.print(rear.data+" ");
}
}
//前序遍历(非递归),使用堆栈
public void preOrder()
{
BinNode rear=root;
Stack<BinNode>preStack=new Stack<BinNode>();
//先访问当前节点,放入堆栈,移至左孩子;
while(rear!=null||!preStack.isEmpty())
{
while(rear!=null)
{
System.out.print(rear.data+" ");
preStack.push(rear);//压入堆栈,以访问右孩子;
rear=rear.leftchild;
}
if(!preStack.isEmpty())
{
rear=preStack.pop();
rear=rear.rightchild;
}
}
}
//中序遍历(非递归)
public void midOrder()
{
BinNode rear=root;
Stack<BinNode>midStack=new Stack<BinNode>();
while(rear!=null||!midStack.isEmpty())
{
while(rear!=null)
{
midStack.push(rear);
rear=rear.leftchild;
}
if(!midStack.isEmpty())
{
rear=midStack.pop();
System.out.print(rear.data+" ");
rear=rear.rightchild;
}
}
}
//后序遍历(非递归)
public void postOrder()
{
BinNode rear=root;
BinNode preVisit=null;
Stack<BinNode>postStack=new Stack<BinNode>();
while(rear!=null||!postStack.isEmpty())
{
//根与所有左孩子依次入栈;
while(rear!=null)
{
postStack.push(rear);
rear=rear->leftchild;
}
if(!postStack.isEmpty())
{
rear=postStack.peek().rightchild;//当前节点若有右孩子,先访问右孩子,不出栈;
if(rear==null||rear==preVisit)//右孩子为空或已经访问过,访问该节点,并标记该节点为已访问;
{
rear=postStack.pop();
System.out.print(rear.data+" ");
preVisit=rear;
rear=null;
}
}
}
}
}