Java实现链式存储的二叉树

二叉树的定义:  

  二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。
  二叉树的遍历方式主要有:先序遍历(NLR),中序遍历(LNR),后序遍历(LRN),和层次遍历。

  注意:

    由二叉树的先序序列和中序序列可以唯一地确定一颗二叉树;

    由二叉树的后序序列和中序序列可以唯一地确定一颗二叉树;

    由二叉树的层序序列和中序序列可以唯一地确定一棵二叉树;

    但,由二叉树的先序序列和后序序列无法唯一地确定一棵二叉树。

Java实现链式存储的二叉树以及其各种遍历算法:

树节点:

public class TreeNode<E> {
    private E data;   //数据域
    private TreeNode<E> lchild;  //左孩子
    private TreeNode<E> rchild;  //右孩子

    TreeNode(){}

    TreeNode(E e){
        this.data = e;
    }

    TreeNode(E data,TreeNode<E> lchild, TreeNode<E> rchild){
        this.data = data;
        this.lchild = lchild;
        this.rchild = rchild;
    }

    public void setData(E data){
        this.data = data;
    }

    public E getData(){
        return this.data;
    }

    public void setLchild(TreeNode<E> lchild){
        this.lchild = lchild;
    }

    public TreeNode<E> getLchild(){
        return this.lchild;
    }

    public void setRchild(TreeNode<E> rchild){
        this.rchild = rchild;
    }

    public TreeNode<E> getRchild(){
        return this.rchild;
    }
}

二叉树的Java实现:

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;

/**
 * @author Cherish
 * 二叉树的链式存储结构
 * @param <E>
 */

public class BinaryTree<E> {
    private TreeNode<E> root;  //根节点
    private List<TreeNode> nodeList = null;   //二叉树节点的链式结构

    public BinaryTree(){

    }

    public BinaryTree(TreeNode<E> root){
        this.root = root;
    }

    //把一个数组转化为一颗完全二叉树
    public TreeNode<E> buildTree(E[] array){
        nodeList = new LinkedList<TreeNode>();
        //将数组中的元素依次转换为TreeNode节点,存放于链表中
        for(int i=0; i< array.length; i++){
            nodeList.add(new TreeNode(array[i]));
        }
        //对前(array.length / 2 - 1)个父节点,按照父节点与孩子节点的数字关系建立完全二叉树
        //对完全二叉树,按从上到下,从左到右的顺序依次编号0,1,2,3....N,则i>0的节点,其左孩子为(2*i+1),
        //其右孩子为(2*i+2)
        for(int j=0; j < (array.length/2-1);j++){
            //左孩子
            nodeList.get(j).setLchild(nodeList.get(j*2+1));
            //右孩子
            nodeList.get(j).setRchild(nodeList.get(j*2+2));
        }
        //最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独处理
        int index = array.length/2 -1;
        //左孩子
        nodeList.get(index).setLchild(nodeList.get(index*2+1));
        //右孩子:如果数组的长度为奇数才有右孩子
        if(array.length % 2 == 1){
            nodeList.get(index).setRchild(nodeList.get(index*2+2));
        }
        root=nodeList.get(0); //设置根节点
        return root;
    }

    //得到树的高度
    public int height(TreeNode<E> node){
        if(node == null){
            return 0;
        }else{
            int i = height(node.getLchild());
            int j = height(node.getRchild());
            return (i<j)?(j+1):(i+1);
        }
    }

    //得到节点的个数
    public int size(TreeNode<E> node){
        if(node == null){
            return 0;
        }else{
            return 1+ size(node.getLchild())+size(node.getRchild());
        }
    }

    //递归实现先序遍历 NLR
    public void preOrder(TreeNode<E> node){
        if(node != null){
            System.out.print(node.getData() + " ");
            preOrder(node.getLchild());
            preOrder(node.getRchild());
        }
    }
    //非递归实现先序遍历 NLR
    public void nonRecPreOrder(TreeNode<E> node){
        Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
        TreeNode<E> nodeTemp = node; //nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){   //当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){   //根指针非空,遍历左子树
                nodeStack.push(nodeTemp);   //根指针进栈
                System.out.print(nodeStack.peek().getData() + " "); //根指针退栈,访问根节点
                nodeTemp = nodeTemp.getLchild();  //每遇到非空二叉树先向左走
            }else{ //再向右子树走
                nodeTemp = nodeStack.pop();
                nodeTemp = nodeTemp.getRchild();
            }
        }
    }

    //递归实现中序遍历 LNR
    public void inOrder(TreeNode<E> node){
        if(node != null){
            inOrder(node.getLchild());
            System.out.print(node.getData() + " ");
            inOrder(node.getRchild());
        }
    }

    //非递归实现中序遍历 LNR
    public void nonRecInOrder(TreeNode<E> node){
        Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
        TreeNode<E> nodeTemp = node;  //nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){  //当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){  //根指针非空,遍历左子树
                nodeStack.push(nodeTemp);  //根指针进栈
                nodeTemp = nodeTemp.getLchild();  //每遇到非空二叉树先向左走
            }else{
                nodeTemp = nodeStack.pop();  //根指针退栈,访问根节点
                System.out.print(nodeTemp.getData() +" ");
                nodeTemp = nodeTemp.getRchild();  //再向右子树走
            }
        }
    }

    //递归实现后序遍历 LNR
    public void postOrder(TreeNode<E> node){
        if(node != null){
            postOrder(node.getLchild());
            postOrder(node.getRchild());
            System.out.print(node.getData() + " ");
        }
    }

    //非递归实现后序遍历 LNR
    public void nonRecPostOrder(TreeNode<E> node){
        Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
        TreeNode<E> nodeTemp = node; //nodeTemp作为遍历指针
        TreeNode<E> preNode = null;  //表示最近一次访问的节点
        while(nodeTemp != null || !nodeStack.isEmpty()){  //当nodeTemp非空或栈非空时循环
            while(nodeTemp != null){  //一直向左走,遍历左子树
                nodeStack.push(nodeTemp);
                nodeTemp = nodeTemp.getLchild();
            }
            nodeTemp = nodeStack.peek();
            if(nodeTemp.getRchild()==null || nodeTemp.getRchild() == preNode){  //右子树为空或右子树已被访问时,该节点出栈
                nodeTemp = nodeStack.pop();
                System.out.print(nodeTemp.getData()+" ");
                preNode = nodeTemp;   //将该节点赋值给最近一个访问节点
                nodeTemp = null;   //此处很重要,将刚出栈节点设置为空,对应于while循环的条件之一,否则陷入死循环
            }else{
                nodeTemp = nodeTemp.getRchild(); //遍历右子树
            }
        }
    }

    //层次遍历
    public void levelOrder(TreeNode<E> root){
        Queue<TreeNode<E>> nodeQueue = new LinkedList<TreeNode<E>>();
        TreeNode<E> node = null;
        nodeQueue.add(root);  //将根节点入队
        while(!nodeQueue.isEmpty()){  //队列不空循环
            node = nodeQueue.peek();
            System.out.print(node.getData()+" ");
            nodeQueue.poll();     //队头元素出队
            if(node.getLchild() != null){     //左子树不空,则左子树入队列
                nodeQueue.add(node.getLchild());
            }
            if(node.getRchild() != null){     //右子树不空,则右子树入队列
                nodeQueue.add(node.getRchild());
            }
        }
    }

    public static void main(String args[]){
        //将一个数组转化为一颗完全二叉树
        Object[] array = {1,2,3,4,5,6,7,8};
        BinaryTree bt = new BinaryTree();
        TreeNode root = bt.buildTree(array);
        System.out.print("树的高度:");
        System.out.println(bt.height(root));
        System.out.print("节点的个数:");
        System.out.println(bt.size(root));
        System.out.println("先序遍历:");
        bt.preOrder(root);
        System.out.println("\n"+"非递归先序遍历:");
        bt.nonRecPreOrder(root);
        System.out.println(); 

        System.out.println("中序遍历:");
        bt.inOrder(root);
        System.out.println("\n"+"非递归中序遍历:");
        bt.nonRecInOrder(root);
        System.out.println();

        System.out.println("后序遍历:");
        bt.postOrder(root);
        System.out.println("\n"+"非递归后序遍历:");
        bt.nonRecPostOrder(root);
        System.out.println(); 

        System.out.println("层次遍历:");
        bt.levelOrder(root); 

        //手工构建一颗二叉树
        TreeNode nodeA = new TreeNode("A");
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");
        TreeNode nodeD = new TreeNode("D");
        TreeNode nodeE = new TreeNode("E");
        TreeNode nodeF = new TreeNode("F");
        TreeNode nodeG = new TreeNode("G");
        TreeNode nodeH = new TreeNode("H");
        TreeNode nodeI = new TreeNode("I");
        nodeA.setLchild(nodeB);
        nodeA.setRchild(nodeD);
        nodeB.setRchild(nodeC);
        nodeD.setLchild(nodeE);
        nodeD.setRchild(nodeF);
        nodeF.setLchild(nodeG);
        nodeF.setRchild(nodeI);
        nodeG.setRchild(nodeH);

        System.out.println("\n\n"+"*****************");
        System.out.print("树的高度:");
        System.out.println(bt.height(nodeA));
        System.out.print("节点的个数:");
        System.out.println(bt.size(nodeA));
        System.out.println("先序遍历:");
        bt.preOrder(nodeA);
        System.out.println();  

        System.out.println("中序遍历:");
        bt.inOrder(nodeA);
        System.out.println();  

        System.out.println("后序遍历:");
        bt.postOrder(nodeA);
        System.out.println(); 

        System.out.println("层次遍历:");
        bt.levelOrder(nodeA);
    }
}

上述程序的运行结果:

树的高度:4
节点的个数:8
先序遍历:
1 2 4 8 5 3 6 7
非递归先序遍历:
1 2 4 8 5 3 6 7
中序遍历:
8 4 2 5 1 6 3 7
非递归中序遍历:
8 4 2 5 1 6 3 7
后序遍历:
8 4 5 2 6 7 3 1
非递归后序遍历:
8 4 5 2 6 7 3 1
层次遍历:
1 2 3 4 5 6 7 8 

*****************
树的高度:5
节点的个数:9
先序遍历:
A B C D E F G H I
中序遍历:
B C A E D G H F I
后序遍历:
C B E H G I F D A
层次遍历:
A B D C E F G I H 
时间: 2024-10-27 03:05:47

Java实现链式存储的二叉树的相关文章

链式存储的二叉树

package com.txq.dataStructure; import java.util.ArrayList;import java.util.List;import java.util.Queue;import java.util.concurrent.ConcurrentLinkedDeque; /** * 链式存储的二叉树 * * @author TongXueQiang * @date 2016/05/09 * @param <T> */public class LinkedBi

线性表的Java实现--链式存储(单向链表)

线性表的Java实现--链式存储(单向链表) 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素.由于不需要按顺序存储,链表在插入.删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢. 使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理.但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空

线性表的Java实现--链式存储(双向链表)

有了单向链表的基础,双向链表的实现就容易多了. 双向链表的一般情况: 增加节点: 删除节点: 双向链表的Java实现: package com.liuhao.algorithm;      public class DuLinkList<T> {          /**       * 内部类:链表中的一个节点       *        * @author liuhao data 节点中的数据 prev 指向前一个节点的引用 next 指向下一个节点的引用       */       

java实现二叉树的链式存储

package com.fxr.二叉树链式存储; import java.util.Scanner; public class Tree { static final int MAXLEN = 20; static Scanner input = new Scanner(System.in); CBTType InitTree() { CBTType node; if((node = new CBTType()) != null) { System.out.println("请输入一个根节点的数

链式存储二叉树(java)

 链式存储一个完全二叉树代码: //二叉树(链式存储) import java.util.ArrayDeque; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Stack; public class MyTree { static Node root; class Node{ private Node lChild; private Node rChild;

二叉树的链式存储结构----二叉链表

头文件:head.h #include<string.h> #include<ctype.h> #include<malloc.h> /* malloc()等 */ #include<limits.h> /* INT_MAX等 */ #include<stdio.h> /* EOF(=^Z或F6),NULL */ #include<stdlib.h> /* atoi() */ #include<io.h> /* eof()

数据结构:二叉树的链式存储

数据结构:二叉树的链式存储(C语言版) 1.写在前面 二叉树同样有两种存储方式,数组和链式存储,对于数组来说,我们利用二叉树的性质然后利用下标可以方便的找到一个节点的子节点和父节点. 二叉树的性质: 1.二叉树的第i层上至多有2i-1个节点 2.深度为K的二叉树至多有2k-1个节点 3.任何一个二叉树中度数为2的节点的个数必度数为0的节点数目少1. 说明:度数为0,为叶子节点. 4.具有n个节点的完全二叉树的深度为|_Log2N_|+1 5.若完全二叉树中的某节点编号为i,则若有左孩子编号为2i

二叉树的创建与遍历(链式存储)

这里采用的是链式存储,每个结点包含三个属性(指向左右孩子的指针和本结点的数据),如果想了解顺序存储二叉树,可以参考http://www.cnblogs.com/-beyond/p/6065189.html 采用先序递归创建二叉树,叶子的左右孩子链域为NULL 输入的顺序为:abd--e--c-f--   (-表示空一个空格) #include<iostream> #include<cstdio> using namespace std; struct BiTNode{ BiTNod

10 二叉树-链式存储-递归遍历

终于进入非线性数据结构的第一站了! 先从简单的开始回忆起来吧! 1.二叉树的链式存储 用一个链表来存储一颗二叉树,每一个结点用链表的一个链结点来存储. 通常地,一个二叉链表至少包含3个域:数据域data.左指针域lchild.右指针域rchild. 现实应用的过程中,可以按照自己的需求添加其他指针域. 1 typedef struct BitNode{ 2 int data; 3 struct BitNode *lchild,*rchild; 4 }BitNode,*BiTree; 2.遍历 二