通俗的讲就是树上每一个节点最多有两个子节点
官方的递归定义是:
这里有两种特殊的二叉树。
二叉树是以链表的形式来存储的,每个结点由地址域,数据域和两个指针域构成。
创建二叉树的结点类,由于java没有引用,所以需要比C++多增加一个父结点
public class BinaryNode{
int data; //数据域,使用泛型
BinaryNode lchild;//左节点
BinaryNode rchild;//右结点
BinaryNode pnode; //父结点
//构造方法
public BinaryNode(int data) {
this.data = data;
}
public BinaryNode(){
}
}
创建新结点
new BinaryNode(data)
查找结点
/**
* 会把所有data结点的值都改为newdata,使用深度优先的方法遍历整个树
* @param root 根结点
* @param data 需要查找并修改的数据
* @param newdata 修改后的数据
* @return
*/
public static void search(BinaryNode root,int data,int newdata ){
if(root==null){
return ; //没有找到该结点,返回
}
if(root.data==data){
root.data=newdata;
}
search(root.lchild,data,newdata);
search(root.rchild,data,newdata);
}
插入结点
方法一:这里需要定义一个全局变量,因为java中没有引用,没办法将改变后的地址往上传,所以用一个全局变量记录递归上一层的地址
/**
* 以搜索二叉树的方法插入结点
* @param root
* @param x
*/
private static BinaryNode tree;//定义一个全局变量
public static void insert(BinaryNode root,int x){
//判断是否为空树
if(root==null){
BinaryNode node=newNode(x);
node.pnode=tree;
if(tree.data<=x){
tree.rchild=node;
}else{
tree.lchild=node;
}
return;
}
tree=root;
if(root.data<=x){
insert(root.rchild,x);
}else{
insert(root.lchild,x);
}
}
方法二:这个比上面一个方法简单了很多,并且不用定义全局变量,也不用pnode属性,这是因为这个方法在递归前已经判断子节点存不存在,就不用考虑引用的问题了(推荐)
public static void insert(BinaryNode root,int x){
if(root.data<=x&&root.rchild!=null){
insert(root.rchild,x);//如果右子结点存在且新结点大于等于该结点
}else if(root.data>x&&root.lchild!=null){
insert(root.lchild,x);//如果左子结点存在且新结点小该结点
}else if(root.data<=x){
root.rchild=new BinaryNode(x);
return;//如果右子结点不存在且新结点大于等于该结点
}else{
root.lchild=new BinaryNode(x);
return;如果左子结点不存在且新结点小该结点
}
}
建立二叉树
BinaryNode BinaryNode = newNode(3);//创建根结点
insert(BinaryNode,2);
insert(BinaryNode,5);
insert(BinaryNode,7);
insert(BinaryNode,4);
insert(BinaryNode,1);
insert(BinaryNode,9);
先序遍历
public void preOrder(BinaryNode root){
if(root==null){
return ;
}
System.out.println(root.data);
preOrder(root.lchild);
preOrder(root.rchild);
}
中序遍历
public void inorder(BinaryNode root){
if(root==null) {
return;
}
preOrder(root.lchild);
System.out.println(root.data);
preOrder(root.rchild);
}
后序遍历
public void postorder(BinaryNode root){
if(root==null) {
return;
}
preOrder(root.lchild);
preOrder(root.rchild);
System.out.println(root.data);
}
层序遍历,Queue是一个接口,LinkedList实现了该接口,使用poll,peek,offer方法
public void layerOrder(BinaryNode root){
Queue<BinaryNode> queue = new LinkedList<>();//Queue是一个接口,LinkedList实现了该接口
queue.offer(root);
while(!queue.isEmpty()){
BinaryNode peek=queue.peek();
System.out.println(peek.data);
if(peek.lchild!=null) queue.offer(peek.lchild);
if(peek.rchild!=null) queue.offer(peek.rchild);
queue.poll();
}
}
最后一个问题经常考虑的就是给定一棵二叉树的先序和中序,重建这颗二叉树,只有有中序排列的二叉树才能重建
BinaryNode create(int preL,int preR,int inL,int inR,int[] pre,int[] in){
if(preL>preR){
return null;
}
BinaryNode root=new BinaryNode();
root.data=pre[preL];
int k;
for(k=inL;k<=inR;k++){
if(in[k]==pre[preL]){
break;
}
}//在中序遍历中获得根结点
int numLeft=k-inL;
root.lchild=create(preL+1,preL+numLeft,inL,k-1,pre,in);
root.rchild=create(preL+numLeft+2,preR,k+1,inR,pre,in);
return root;
}