二叉树——Java初步实现

原创 2016年06月01日 00:28:44
二叉树图解网址:Visualgo-二叉树
这里是二叉树的图示:
野生的二叉树
不好意思放错了

这一部分就是一棵树,而每一个圆圈则叫做一个节点,每个节点最终指向的内容都是NULL,这里就直接省略了
节点是最基本的单位,那么根据上图,我们应该这样设计节点:
第一部分:指针—— 一个节点会有两个指针,一个指向左边,一个指向右边
第二部分:数据—— 这里的数据是int整型,根据需要我们可以改为其他类,譬如说我在自己写的图书馆管理系统里就改成了Book这一个类
那么为什么要用二叉树作为数据结构呢?我们来看一下二叉树的特点:凡是左边的数都要比右边的小
这一特点可以缩短搜索的时间,每一个节点都只要选择一个方向进行搜索就行了。

下面,我们来具体实现一个二叉树:
一、二叉树的构建与增加节点
首先是节点部分,一个节点应该包括:1.存储的数据2.指向比数据小的节点的指针3.指向比存储数据大的节点的指针
/**
 * @author 起名比做卷子难
 */
public class Node {
	private Node left = null;//指向较小的节点
	private Node Right = null;//指向较大的节点
	private int data;//存储的数据
	public Node(int data) {
		this.data = data;
	}//创建新节点的时候把数据存储上
	public Node getLeft() {
		return left;
	}
	public void setLeft(Node left) {
		this.left = left;
	}
	public Node getRight() {
		return Right;
	}
	public void setRight(Node right) {
		Right = right;
	}
	public int getData() {
		return data;
	}
	public void setData(int data) {
		this.data = data;
	}
}
然后开始构建,实质上就是向二叉树中增添数据,基本思路基于上面所说的二叉树的特点,左边的数据比右边的大,所以从树根开始,小于节点的,去左边,大于节点的,去右边,如果左边(右边)是空,那么就可以创建一个新节点了。
/**
 * @author 起名比做卷子难
 */
public class BinaryTree {
	//这是一棵树
	private Node root = null;//树根
	private Node node = null;//节点指针
}
//增加数据的方法
public void add(int num) {
	//首先判断树根是否为空,若为空新建树根
	if (root == null) {
		root = new Node(num);
		return;
	}
	node = root;//增加每一个数据都要从头开始搜索
	while (true) {
		if (num < node.getData()) {//如果增加的数据比节点数据小
			if (node.getLeft() != null) {//进行判断,也是一个保护,考虑考虑如果节点左边空了呢?
				node = node.getLeft();//节点指针指向左侧节点
				continue;//继续循环
			} else {//节点左边空了
				node.setLeft(new Node(num));//新建节点,同时这个节点的左指针指向新建的节点
				break;//跳出,增加完毕
			}
		} else {//以下的内容为上面的重复,尝试自己进行理解?
			if (node.getRight() != null) {
				node = node.getRight();
				continue;
			} else {
				node.setRight(new Node(num));
				break;
			}
		}
	}
}
现在我们就创建好了一个二叉树了,但是我们看不见,为了进行检验,我们需要对二叉树进行遍历,这里使用DFS(深度优先搜索算法)进行遍历
DFS算法:(如果熟悉可忽略)



DFS其实很好理解,就是先遍历一支,再遍历另一支,就像图中的曲线跟箭头所示,一步步进行遍历,找到null就返回上一步
这里遍历的顺序是:7→4→2→4→6→4→7→11→9→11→15→11→7,看起来优点繁琐,但是实际上十分简单。
我们写一个方法来进行遍历,并在控制台打印以检验我们的构建是否成功
//DFS遍历二叉树
public void dfs(Node nodeBegin) {
	Node node = nodeBegin;//从头开始遍历
	//如果遍历到null了,证明这一支已经遍历完毕,直接返回
	if (node == null) {
		return;
	}
	dfs(node.getLeft());//遍历左支
	dfs(node.getRight());//遍历右支
	System.out.println(node.getData());//在遍历完左右支后再打印这个节点
	return;
}
注意!!!这里有一个问题非常值得探讨,那就是NullPointerException
可能有人会问,既然我们在先前已经定义了一个node作为节点指针,为什么还要在这里多新建一个node呢?
我们不妨试一下,将“Node”删去,得到的运行结果是:
为什么会出现这种情况呢?很简单,在递归的过程中,变量node的值不断改变,直到到达数据为2的这个节点并dfs(2的左支)后,node = null,这时候再进行null.getRight(),当然会报错。这种细节问题最为令人恼火,也最为致命。
当然了,我这里写的很复杂,为的是引出这个问题,如果希望简洁,可以直接不新建Node,把凡是出现“node”的地方换成nodeBegin就可以了
我们再创建一个display()的方法,以后还有用
public void display() {
	dfs(root);
}
既然都写好了,何不运行下?
/**
 * @author 起名比做卷子难
 * 强迫症新建一个类专门用于运行
 */
public class Store {
	public static void main(String[] args) {
		BinaryTree tree = new BinaryTree();//新建一个二叉树
		/*
		 *          7		
		 *         / \
		 *        4   11
		 *       / \  / \
		 *      2  6  9 15
		 *     数据结构图示
		 */
		int[] number = {7,6,11,2,6,9,15};//数组
		for (int num : number){
			tree.add(num);//for each方法向树中添加数据
		}
		tree.display();//运用display方法输出
	}
}
运行结果是: 2 6 4 9 15 11 7(有换行,在这里没有打出来)
如果希望得到的是 2 4 6 7 9 11 15, 只需要把打印的语句放在递归左右支的中间就好。如果希望得到逆序输出的,也只需要调换语句顺序,这里就不解释了。
(这样一来有没有觉得很方便?)
二、二叉树的查找
数据都已经放好了,那么我们就来对二叉树进行查找。查找所基于的也是数据左大右小的特点,譬如说我要找“2”,那么我们先跟根节点7比较,2<7,向左边继续找,2<4,还是向左边找,最后就找到了2。这一步非常简单,原理跟二叉树的遍历相同,而且查找用到的只是while不需要用到递归,更为简单方便。下面是查找的代码。
public Node find(int num) {
	Node node = root;//上面的情况太令人尴尬,索性就新建一个Node确保安全
	while (node != null) {//只要节点不为空
		if (node.getData() > num) {//要查找的小于当前节点
			node = node.getLeft();//向左
			continue;//继续
		} else if (node.getData() < num) {//要查找的大于当前节点
			node = node.getRight();//向右
			continue;//继续
		} else {//要查找的就是当前节点
			return node;//返回当前节点
		}
	}
	return null;//找不到就返回null
}
这里要实现的是找到二叉树的最小值,又或者是某个节点开始的最小值。二叉树找最大值、最小值都非常简单,只要一路向右(向左)就可以了。下面的代码写的是找最小值。
private Node findMin(Node node) {
	while (node.getLeft() != null) {//判断左侧还有没有,起到保护作用
		node = node.getLeft();//一路向左
	}
	return node;//返回的是一整个节点
}
三、二叉树节点的删除
前面做的都非常简单,小儿科而已,下面的删除节点操作就显得有点复杂了。我们先把删除的思路理清。

如图,二叉树的删除分为两部分(这里以4为被删除的节点)
(1)找到要删除的节点,然后在被删除的节点的右节点找一个最小支,然后将被删除节点的左支“嫁接”到最小支的左支,此时的最小支左支肯定为null,否则它就不是最小支。
(2)然后将被删除节点的父节点的左支(也有可能是右支,根据实际情况而定)连到被删除节点的右支(左支)就可以了。

思路其实很简单,难的是实现过程中对于各种情况的讨论,最终代码如下:
private Node get(Node node, int num) {
	if (node == null || node.getData() == num)
		return node;//若已到分支底部或已找到 退出递归
	Node temp = null;//用于存放被删除节点的指针
	Node min = null;//用于存放需要需要删除节点右枝最小节点的指针
	if (node.getData() > num) {//被删除数据小于节点数据,所以下面只要讨论小于的情况
		temp = get(node.getLeft(), num);// 寻找被删除的节点,先递归左边树枝,如果没有找到返回null
		if (temp == null)//没有找到被删除节点
			return null;//没有被删除的节点
		else {//找到了要被删除的节点
			if (temp.getRight() == null){//如果被删除节点没有右支,那么就直接把父节点的左支设为被删除节点的左支。
				node.setLeft(temp.getLeft());//父节点的左支设为被删除节点的左支
				return null;//删除以后就返回null
			}
			min = findMin(temp.getRight());//有右枝就找右枝最小节点
			min.setLeft(temp.getLeft());//右枝的最小节点的左枝设为被删除节点的左枝
			node.setLeft(min);//父节点的左支设为被删除节点有右侧最小节点
			return null;
		}
	} else {
		temp = get(node.getRight(), num);// 寻找被删除的节点,先递归右边树枝,如果没有找到返回null
		if (temp == null)//下面的与上面的代码大同小异,尝试自己进行理解
			return null;
		else {
			if (temp.getRight() == null){
				node.setRight(temp.getLeft());
				return null;
			}//被删除的节点没有右枝
			min = findMin(temp.getRight());
			min.setLeft(temp.getLeft());
			node.setRight(min);
			return null;
		}
	}
}
到此为止,整个二叉树已经实现了。
版权声明:本文为博主原创文章,未经博主允许不得转载。

如何处理加括号的四则混合运算表达式——基于二叉树的实现(Eclipse平台 Java版)

记得上《数据结构》课程时,利用栈的特性解决过四则混合运算表达式。而如今在编写小型关系数据库的时候,编译部分要处理where后面的逻辑表达式——检查语法正确与否的同时,还要将信息传给下一个接口,进行优化...

二叉树的遍历(循环及递归实现)——Java

package go.jacob.day502; import java.util.Stack; /** * * @author Administrator 前序遍历:6 3 1 2 5 4...

数据结构的Java实现——二叉树

二叉树的二叉链表实现、先序、中序、后序遍历实现

二叉树——Java实现

二叉树的基本概念就不介绍了,这里主要学习二叉树的各种算法建立二叉树我们要建立如下的一棵树 首先我们来看一下一棵树的结构class MyTree { String data;// 节点数据 ...
  • zjsxxzh
  • zjsxxzh
  • 2017年07月13日 15:48
  • 88

二叉树的应用——表达式树的原理分析与实现(Java语言)

表达式树表达式树(expression tree)的树叶是操作数(operand),如常量或变量名,而其他节点为操作符(operator)。如下图 图1 (a+b*c)+((d*e+f)*g)的...

数据结构——树(2)一般树转二叉树Java实现

一般树转二叉树的算法理论和Java实现
  • picway
  • picway
  • 2017年02月26日 16:38
  • 181

数据结构与算法学习笔记——二叉树的初步理解

二叉树的概念二叉树是一棵每个节点都不能有多于两个儿子的树 有N个结点的完全二叉树的深度: 公式:K =「log2n」+1 证明:可用数学归纳法。 当n=1=2^1-1时显然。 ...

剑指Offer:面试题25——二叉树中和为某一值的路径(java实现)

问题描述: 输入一棵二叉树和一个整数,打印出二叉树中结点指的和为输入整数的所有路径。从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。二叉树结点的定义如下: public class Tr...

数据结构与算法Java版——二叉树及其遍历

二叉树可以用顺序存储结构表示,也可以用二叉链表表示,但顺序存储结构一般仅适合于存储完全二叉树……   这个学期学了数据结构这本书,所以我打算用Java实现其中表,队,栈,树。如果你有兴趣可以...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:二叉树——Java初步实现
举报原因:
原因补充:

(最多只允许输入30个字)