Java实现二叉树的创建和遍历操作
2015-11-16 17:13
671 查看
最近在学习二叉树的相关知识,一开始真的是毫无头绪。本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作。但是二者原理是一致的,而且实现的方式也是大同小异!
下面就让我们来看看代码吧。
1、首先我们需要创建一个二叉树的节点类,便于我们对树的操作,当然了,你也可以在二叉树类的内部将节点类声明为内部类,但是这样会降低操作的灵活性。我才用的是单独创建一个BinaryTreeNode类,代码如下:
2、有了节点类,下面就是二叉树类了,注释什么的在代码中已经非常详细了:
3、然后是我的测试类,下面请看代码:
4、接下来是测试的结果:
5、不足之处:
也许是测试的时候方式不对,因为使用递归方式对二叉树进行遍历的时候会报出NullPointerException的空指针错误。如果你知道原因在哪?不妨写下你的评论。也好让我加以改正。
6、总结:
在学习的过程中我意识到了一点,希望与君共勉!那就是埋头敲代码是解决不了问题的。重要的是思路。没有思路,一味的测试也是不可能成功的。在敲代码之前,我们一定要搞懂我们要做什么,怎么做,这样才会事半功倍。希望能和大家共同学习,一起进步!
下面就让我们来看看代码吧。
1、首先我们需要创建一个二叉树的节点类,便于我们对树的操作,当然了,你也可以在二叉树类的内部将节点类声明为内部类,但是这样会降低操作的灵活性。我才用的是单独创建一个BinaryTreeNode类,代码如下:
package MyBinaryTree; public class BinaryTreeNode<T> { T data; BinaryTreeNode<T> leftChild; BinaryTreeNode<T> rightChild; public T getData() { return data; } public void setData(T data) { this.data = data; } BinaryTreeNode() { this.data = null; this.leftChild = null; this.rightChild = null; } BinaryTreeNode(T data) { this.data = data; this.leftChild = null; this.rightChild = null; } public BinaryTreeNode(T data, BinaryTreeNode<T> leftChild, BinaryTreeNode<T> rightChild) { super(); this.data = data; this.leftChild = leftChild; this.rightChild = rightChild; } public BinaryTreeNode<T> getLeftChild() { return leftChild; } public void setLeftChild(BinaryTreeNode<T> leftChild) { this.leftChild = leftChild; } public BinaryTreeNode<T> getRightChild() { return rightChild; } public void setRightChild(BinaryTreeNode<T> rightChild) { this.rightChild = rightChild; } public boolean isLeaf() { if (this.leftChild == null && this.rightChild == null) { return true; } return false; } } //我才用的是泛型定义,在C++中我们可以使用模板来实现相同的处理
2、有了节点类,下面就是二叉树类了,注释什么的在代码中已经非常详细了:
package MyBinaryTree; import java.util.Queue; import java.util.Stack; import java.util.concurrent.LinkedBlockingQueue; public class BinaryTree<T> { private BinaryTreeNode<T> root; public BinaryTree() { BinaryTreeNode<T> node = new BinaryTreeNode<T>(); this.root = node; } public boolean isEmpty() { if (root == null) { return true; } return false; } public BinaryTreeNode<T> getRoot() { return this.root; } public void CreateTree(BinaryTreeNode<T> node, T data) { if (root == null) { root = new BinaryTreeNode<T>(); } else { if (Math.random() > 0.5) { //采用随机方式创建二叉树 if (node.leftChild == null) { node.leftChild = new BinaryTreeNode<T>(data); } else { CreateTree(node.leftChild, data); } } else { if (node.rightChild == null) { node.rightChild = new BinaryTreeNode<T>(data); } else { CreateTree(node.rightChild, data); } } } } /* * 访问当前节点 */ public void Visit(BinaryTreeNode<T> current) { if(current!=null&¤t.getData()!=null){ System.out.println(current.getData()); }else{ System.out.println("null"); } } /* * 广度优先遍历二叉树 */ public void levelOrder(BinaryTreeNode<T> root) { Queue<BinaryTreeNode<T>> queue = new LinkedBlockingQueue<BinaryTreeNode<T>>(); BinaryTreeNode<T> pointer = root; /* * 当前节点不为空时,放入队首 */ if (pointer != null) { queue.add(pointer); } /* * 队列不为空时,先访问中间节点,访问完成后弹出队首节点;然后是左节点,再是右节点; */ while (!queue.isEmpty()) { pointer = queue.peek(); Visit(pointer); queue.remove(); if (pointer.leftChild != null) { queue.add(pointer.leftChild); } if (pointer.rightChild != null) { queue.add(pointer.rightChild); } } } /* * 递归方式的前序遍历 */ public void preOrder(BinaryTreeNode<T> root) { Visit(root); preOrder(root.leftChild); preOrder(root.rightChild); } /* * 非递归方式实现的前序遍历 */ public void NPreOrder(BinaryTreeNode<T> root){ Queue<BinaryTreeNode<T>> queue=new LinkedBlockingQueue<BinaryTreeNode<T>>(); BinaryTreeNode<T> pointer=root; /* * 当前节点不为空,就一直放入队尾;当前节点为空时,访问队首元素,然后访问做孩子节点;然后弹出,再对新的队首元素进行判断 */ while(!queue.isEmpty()||pointer!=null){ if(pointer!=null){ Visit(pointer); if(pointer.rightChild!=null){ queue.add(pointer.rightChild); } pointer=pointer.leftChild; }else{ pointer=queue.peek(); queue.remove(); } } } /* * 采用递归方式实现的中序遍历操作 */ public void inOrder(BinaryTreeNode<T> root){ inOrder(root.leftChild); Visit(root); inOrder(root.rightChild); } /* * 非递归方式实现的中序遍历 */ public void NInOrder(BinaryTreeNode<T> root){ Stack<BinaryTreeNode<T>> stack=new Stack<BinaryTreeNode<T>>(); BinaryTreeNode<T> pointer=root; /* * 当前节点不为空,就一直进栈;当前节点为空时,访问栈顶元素,然后再访问右孩子节点 */ while(!stack.isEmpty()||pointer!=null){ if(pointer!=null){ stack.push(pointer); pointer=pointer.leftChild; }else{ pointer=stack.peek(); Visit(pointer); pointer=pointer.rightChild; stack.pop(); } } } /* * 递归方式实现的后序遍历二叉树 */ public void postOrder(BinaryTreeNode<T> root){ postOrder(root.leftChild); postOrder(root.rightChild); Visit(root); } /* * 非递归方式实现的后序遍历二叉树 */ public void NPostOrder(BinaryTreeNode<T> root){ Stack<BinaryTreeNode<T>> stack=new Stack<BinaryTreeNode<T>>();//初始化栈,用于保存带访问的节点 BinaryTreeNode<T> pointer=root; //保存根节点 BinaryTreeNode<T> preNode=root; //保存前一个被访问的节点 while(!stack.isEmpty()||pointer!=null){ //若当前节点不空,就一直进栈,然后继续向左走 while(pointer.leftChild!=null){ stack.push(pointer); pointer=pointer.leftChild; } /* * 当前节点为空时,分两种情况: * 1、当前节点移动到栈顶处,然后访问栈顶元素的右节点 * 2、当前节点移动到栈顶,但是栈顶元素没有右节点,这就需要弹出栈顶元素,再对此元素访问; * 然后再对新的栈顶元素进行判断即可 */ while(pointer!=null&&(pointer.rightChild==null)||(pointer.rightChild==preNode)){ Visit(pointer); preNode=pointer; if(stack.isEmpty()){ return; } pointer=stack.peek(); stack.pop(); } stack.push(pointer); pointer=pointer.rightChild; } } }
3、然后是我的测试类,下面请看代码:
public static void main(String[] args) { BinaryTree<Integer> tree = new BinaryTree<Integer>(); for (int i = 1; i < 10; i++) { tree.CreateTree(tree.root, i); } System.out.println("-----------下面是广度优先遍历二叉树--------------"); tree.levelOrder(tree.root); System.out.println("-----------下面是非递归的前序遍历方式-------------"); tree.NPreOrder(tree.root); System.out.println("-----------下面是非递归的中序遍历方式-------------"); tree.NInOrder(tree.root); System.out.println("-----------下面是非递归的后序遍历方式-------------"); tree.NPostOrder(tree.root); }
4、接下来是测试的结果:
-----------下面是广度优先遍历二叉树-------------- null 1 2 6 4 3 8 7 5 9 -----------下面是非递归的前序遍历方式------------- null 1 6 2 3 4 5 7 8 9 -----------下面是非递归的中序遍历方式------------- 6 7 1 5 4 null 3 9 2 8 -----------下面是非递归的后序遍历方式------------- 7 6 5 4 1 9 3 8 2 null
5、不足之处:
也许是测试的时候方式不对,因为使用递归方式对二叉树进行遍历的时候会报出NullPointerException的空指针错误。如果你知道原因在哪?不妨写下你的评论。也好让我加以改正。
6、总结:
在学习的过程中我意识到了一点,希望与君共勉!那就是埋头敲代码是解决不了问题的。重要的是思路。没有思路,一味的测试也是不可能成功的。在敲代码之前,我们一定要搞懂我们要做什么,怎么做,这样才会事半功倍。希望能和大家共同学习,一起进步!
相关文章推荐
- java 使用 mail 发送邮件
- spring mvc 框架搭建及详解
- MyEclipse2014 常用设置优化
- eclipse上单步调试Hive
- springmvc前台往后传值的几种方式
- java中的排序方法
- Spring AOP在Bean生命周期中的调用时机
- 加密解密java
- spring 定时任务的写法
- java加密解密简单列子
- Java Maven项目打包部署流程
- android推送:eclipse paho mqtt 项目在android studio环境下的源码
- spring+mybatis编译错误
- 从”JAVA“而终 24:BOM以及DOM讲解
- 源码分析:Java对象的内存分配
- eclipse插件
- java 内存分配
- JAVA字符串判等(== 与 equals)
- 15-11-16 Eclipse 操作菜单汉译之 Search [搜索]
- java 堆和栈