您的位置:首页 > 编程语言 > Java开发

Java实现二叉树的创建和遍历操作

2015-11-16 17:13 671 查看
最近在学习二叉树的相关知识,一开始真的是毫无头绪。本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作。但是二者原理是一致的,而且实现的方式也是大同小异!

下面就让我们来看看代码吧。

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、总结:

在学习的过程中我意识到了一点,希望与君共勉!那就是埋头敲代码是解决不了问题的。重要的是思路。没有思路,一味的测试也是不可能成功的。在敲代码之前,我们一定要搞懂我们要做什么,怎么做,这样才会事半功倍。希望能和大家共同学习,一起进步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: