Java数据结构之树和二叉树

从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~

Java中的数据结构模型可以分为一下几部分:

1.线性结构

2.树形结构

3.图形或者网状结构

接下来的几章,我们将会分别讲解这几种数据结构,主要也是通过Java代码的方式来讲解相应的数据结构。

今天要讲解的是:Java线性结构

Java数据结构之树形结构

之前我们前几章学习的都是Java数据结构的线性结构,都是一对一的,从现在开始我们将要学习Java的树形结构。

树对于我们来普通Java程序员而言,也许平常的时候我们似乎感觉不到它的存在。但其实不是这样的。

其实是jdk帮我们已经封装好了,所以给我们一种错觉,树这种数据结构似乎离我们很远。

随便举一个例子:TreeMap这种集合框架,底层使用的就是红黑树...

下面对树这种数据结构进行一下简单的介绍(如果想要了解详细的内容的话,请自己百度吧~亲)。

1.树中的节点可以有若干个子节点,但是每个子节点只能有一个父节点。

   这就好比一对夫妇可能有多个孩子,但是每个孩子只能有唯一的一对父母。

2.树的分类 

   按照当前节点是否有父节点可以分为:根节点和普通节点。

   按照当前节点是否有子节点可以分为:叶子节点和普通节点。

3.节点

   树的最基本组成单元,通常包括当前元素内容和指向下一个元素的引用

4.节点的度

    当前节点所包含的子树的个数被称为节点的度

5.树的度

   树中节点度数最大的值,我们称之为树的度

6.叶子节点

   树中度数为0的节点我们称之为叶子节点

7. 分支节点

   树中度数不为0的节点,我们称之为分支节点

8.节点的层次

   节点的层次从根开始算起,根的层次为1,其余节点的层次为父节点的层次加1

9.树的深度

  树中节点的最大层次被称为树的深度

10.有序树和无序树

 如果将树中的节点看成是从左往右的有序的,我们称之为有序树。否则的话我们称之为无序树。

 ...

 好吧,树的基本概念就介绍到这里。下面是具体的java代码的实现了哦。

为了记录树这种数据结构,我们必须记录节点和节点之间的关系。

主要有两种记录树与树之间的关系

 1.父节点表示法,每个子节点都记录它所对应的父节点

 2.子节点表示法,每个父节点都记录它所对应的所有子节点

 下面从代码的角度进行相应的讲解

一、父节点表示法

 

package com.yonyou.test;

import java.util.ArrayList;
import java.util.List;

import com.yonyou.test.TreeParent.Node;






/**
 * 测试类
 * @author 小浩
 * @创建日期 2015-3-20
 */
public class Test
 { 
	public static void main(String[] args){
		TreeParent<String> tp = new TreeParent<String>("root");
		TreeParent.Node<String> root = tp.root();
		System.out.println(root);
		tp.addNode("节点1" , root);
		System.out.println("此树的深度:" + tp.deep());
		tp.addNode("节点2" , root);
		// 获取根节点的所有子节点
		List<Node<String>> nodes = tp.children(root);
		System.out.println("根节点的第一个子节点:" + nodes.get(0));
		// 为根节点的第一个子节点新增一个子节点
		tp.addNode("节点3" , nodes.get(0));
		System.out.println("此树的深度:" + tp.deep());
	}
 }


/**
 * 父节点表示法,当前子节点记录他所对应的父节点的位置
 * @author 小浩
 * @创建日期 2015-3-23
 * @param <E>
 */
class TreeParent<E>
{
	//树中能够存储的最大节点的个数
	private final int DEFAULT_TREE_SIZE = 100;
	//树中实际节点对的个数
	private int treeSize = 0;
	//内部类,用于存储相应的节点内容
	public  static class Node<T>
	{   
		//保存对应的数据
		T data;
		// 记录其父节点的位置
		int parent;
		public Node()
		{
		}
		public Node(T data)
		{
			this.data = data;
		}
		public Node(T data , int parent)
		{
			this.data = data;
			this.parent = parent;
		}
		public String toString()
		{
			return "TreeParent$Node[data=" + data
				+ ", parent=" + parent + "]";
		}
	}
	// 使用一个Node[]数组来记录该树里的所有节点
	private Node<E>[] nodes;
	// 记录节点数
	private int nodeNums;
	// 以指定根节点创建树
	@SuppressWarnings("unchecked")
	public TreeParent(E data)
	{
		treeSize = DEFAULT_TREE_SIZE;
		nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data , -1);
		nodeNums++;
	}
	
	/**
	 *  以指定根节点、指定treeSize创建树
	 * @param data
	 * @param treeSize
	 */
	@SuppressWarnings("unchecked")
	public TreeParent(E data ,int treeSize)
	{
		this.treeSize = treeSize;
		nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data , -1);
		nodeNums++;
	}
	
	
	/**
	 * 为指定节点添加子节点
	 * @param data
	 * @param parent
	 */
	public void addNode(E data , Node parent)
	{
		for (int i = 0 ; i < treeSize ; i++)
		{
			// 找到数组中第一个为null的元素,该元素保存新节点
			if (nodes[i] == null)
			{
				//创建新节点,并用指定的数组元素保存它
				nodes[i] = new Node<E>(data , pos(parent));;
				nodeNums++;
				return;
			}
		}
		throw new RuntimeException("该树已满,无法添加新节点");
	}
	
	/**
	 * 判断树是否为空。
	 */
	public boolean empty()
	{
		// 根节点是否为null
		return nodes[0] == null;
	}
	
	/**
	 * 返回根节点
	 * @return
	 */
	public Node<E> root()
	{
		// 返回根节点
		return nodes[0];
	}
	
	/**
	 * 返回指定节点(非根节点)的父节点。
	 */
	public Node<E> parent(Node node)
	{
		// 每个节点的parent记录了其父节点的位置
		return nodes[node.parent];
	}
	
	/**
	 * 返回指定节点(非叶子节点)的所有子节点。
	 * @param parent
	 * @return
	 */
	public List<Node<E>> children(Node parent)
	{
		List<Node<E>> list = new ArrayList<Node<E>>();
		for (int i = 0 ; i < treeSize  ; i++)
		{
			// 如果当前节点的父节点的位置等于parent节点的位置
			if (nodes[i] != null &&
				nodes[i].parent == pos(parent))
			{
				list.add(nodes[i]);
			}
		}
		return list;
	}
	
	/**
	 * 返回该树的深度。
	 */
	public int deep()
	{
		// 用于记录节点的最大深度
		int max = 0;
		for(int i = 0 ; i < treeSize && nodes[i] != null
			; i++)
		{
			// 初始化本节点的深度
			int def = 1;
			// m记录当前节点的父节点的位置
			int m = nodes[i].parent;
			// 如果其父节点存在
			while(m != -1 && nodes[m] != null)
			{
				// 向上继续搜索父节点
				m = nodes[m].parent;
				def++;
			}
			if(max < def)
			{
				max = def;
			}
		}
		// 返回最大深度
		return max;
	}
	
	/**
	 * 返回包含指定值的节点。
	 * @param node
	 * @return
	 */
	public int pos(Node node)
	{
		for (int i = 0 ; i < treeSize ; i++)
		{
			// 找到指定节点
			if (nodes[i] == node)
			{
				return i;
			}
		}
		return -1;
	}
}

 

二、子节点表示法

  

package com.yonyou.test;

import java.util.ArrayList;
import java.util.List;







/**
 * 测试类
 * @author 小浩
 * @创建日期 2015-3-20
 */
public class Test
 { 
	public static void main(String[] args){
	TreeChild<String> treeChild=new TreeChild<String>("0");
	TreeChild.Node<String> root=treeChild.root();
	System.out.println("当前树的根节点为:"+root.data);
	treeChild.addNode("1",root);
	treeChild.addNode("2",root);
	treeChild.addNode("3",treeChild.children(root).get(0));
	System.out.println("树的深度为:"+treeChild.deep());
	}
 }


/**
 * 子节点表示法,当前子节点记录他所对应的所有子节点的位置
 * @author 小浩
 * @创建日期 2015-3-23
 * @param <E>
 */
class TreeChild<E>
{  
	/**
	 * 静态内部子类链
	 * @author 小浩
	 * @创建日期 2015-3-23
	 */
	 private static class SonNode
	{
		// 记录当前节点的位置
		private int pos;
		private SonNode next;
		public SonNode(int pos , SonNode next)
		{
			this.pos = pos;
			this.next = next;
		}
	}
	
	/**
	 * 静态内部类Node,用于存储相关节点的内容和对应子节点的首个链
	 * @author 小浩
	 * @创建日期 2015-3-23
	 * @param <T>
	 */
	public static class Node<T>
	{
		T data;
		// 记录第一个子节点
		SonNode first;
		public Node(T data)
		{
			this.data = data;
			this.first = null;
		}
		public String toString()
		{
			if (first != null)
			{
				return "TreeChild$Node[data=" + data
					+ ", first=" + first.pos + "]";
			}
			else
			{
				return "TreeChild$Node[data=" + data + ", first=-1]";
			}
		}
	}
	//树中能够存储的节点的最大数量
	private final int DEFAULT_TREE_SIZE = 100;
	//树中实际存储的节点个数
	private int treeSize = 0;
	// 使用一个Node[]数组来记录该树里的所有节点
	private Node<E>[] nodes;
	// 记录节点数
	private int nodeNums;
	
	/**
	 * 以指定根节点创建树
	 * @param data
	 */
	@SuppressWarnings("unchecked")
	public TreeChild(E data)
	{
		treeSize = DEFAULT_TREE_SIZE;
		nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data);
		nodeNums++;
	}
	
	/**
	 * 以指定根节点、指定treeSize创建树
	 */
	@SuppressWarnings("unchecked")
	public TreeChild(E data ,int treeSize)
	{
		this.treeSize = treeSize;
		nodes = new Node[treeSize];
		nodes[0] = new Node<E>(data);
		nodeNums++;
	}
	
	/**
	 * 为指定节点添加子节点
	 * @param data
	 * @param parent
	 */
	public void addNode(E data , Node parent)
	{
		for (int i = 0 ; i < treeSize ; i++)
		{
			// 找到数组中第一个为null的元素,该元素保存新节点
			if (nodes[i] == null)
			{
				// 创建新节点,并用指定数组元素来保存它
				nodes[i] = new Node<E>(data);
				if (parent.first == null)
				{
					parent.first = new SonNode(i , null);
				}
				else
				{
					SonNode next = parent.first;
					while (next.next != null)
					{
						next = next.next;
					}
					next.next = new SonNode(i , null);
				}
				nodeNums++;
				return;
			}
		}
		throw new RuntimeException("该树已满,无法添加新节点");
	}
	
	/**
	 * 判断树是否为空。
	 * @return
	 */
	public boolean empty()
	{
		// 根节点是否为null
		return nodes[0] == null;
	}
	
	/**
	 * 返回根节点
	 * @return
	 */
	public Node<E> root()
	{
		// 返回根节点
		return nodes[0];
	}
	
	/**
	 * 返回指定节点(非叶子节点)的所有子节点。
	 */
	public List<Node<E>> children(Node parent)
	{
		List<Node<E>> list = new ArrayList<Node<E>>();
		// 获取parent节点的第一个子节点
		SonNode next = parent.first;
		// 沿着孩子链不断搜索下一个孩子节点
		while (next != null)
		{
			// 添加孩子链中的节点
			list.add(nodes[next.pos]);
			next = next.next;
		}
		return list;
	}
	
	/**
	 * 返回指定节点(非叶子节点)的第index个子节点。
	 * @param parent
	 * @param index
	 * @return
	 */
	public Node<E> child(Node<E> parent , int index)
	{
		// 获取parent节点的第一个子节点
		SonNode next = parent.first;
		// 沿着孩子链不断搜索下一个孩子节点
		for (int i = 0 ; next != null  ; i++)
		{
			if (index == i)
			{
				return nodes[next.pos];
			}
			next = next.next;
		}
		return null;
	}
	
	/**
	 * 返回该树的深度。
	 * @return
	 */
	public int deep()
	{
		// 获取该树的深度
		return deep(root());
	}
    
	/**
	 * 采用递归的方式方式查找出树的最大深度
	 * @param root
	 * @return
	 */
	private int deep(Node<E> node) {
		if(node.first==null)
			return 1;
		else{	
	    int maxDeep=0;
		SonNode sonNode=node.first;
		while(sonNode!=null)
		{
			int tempDeep=deep(nodes[sonNode.pos]);
			if(tempDeep>maxDeep)
				maxDeep=tempDeep;
			sonNode=sonNode.next;
		}
		return maxDeep+1;
		}
	}

	/**
	 *  返回包含指定值的节点。
	 * @param node
	 * @return
	 */
	public int pos(Node<E> node)
	{
		for (int i = 0 ; i < treeSize ; i++)
		{
			// 找到指定节点
			if (nodes[i] == node)
			{
				return i;
			}
		}
		return -1;
	}
}

 

三、二叉树的讲解

   对于普通树而言,由于它们没有特定的规律,所以在现实生活中的应用不如二叉树广泛。

   所谓二叉树,指的就是让每棵树中的节点最多有两个子节点,而且它们是严格的区分左子节点和右子节点的。

   下面简单说一下二叉树和普通树的区别和联系

  1、树中节点的度数是没有限制的,而二叉树中的节点的最大度数是有限制,最大为2.

  2、普通树的节点无左右节点之分,但是二叉树是严格区分左右节点的。

  什么样的树为满二叉树?

  一个深度为k的二叉树,它所包含的节点的个数为2^k-1个节点的话,那么这样的树被称为满二叉树。

  什么样的树为完全二叉树呢?

  如果一棵二叉树除最后一层外,其余层都是满的。并且最后一层或者是满的,或者仅在右边缺少若干连续的节点,则此二叉树

  被称为完全二叉树。

 下面简单讲解一下二叉树的常见特性,如果想要了解详细的内容的话,请自己百度...谢谢。

 1.二叉树第n层上面节点的个数为2^(n-1)。

 2.深度为k的二叉树最多有2^n-1个节点,即我们所说的满二叉树。

 3.在任何一棵二叉树上面,如果其叶子节点的度数为n0,度数为2的节点的个数为n2,那么下面的等式是一定成立的。

    n0=n2+1;

 4.具有n个节点的完全二叉树的深度为log2(n+1); 

 

 下面以具体的代码为例讲解二叉树的实现过程

 1.二叉树的顺序存储

   首先进行一下说明,当使用数组进行存储二叉树的时候可能会产生一定的浪费。

   如果该树是完全二叉树的话,那么很好,不会产生任何的空间浪费,但是如果当前二叉树仅仅有右子节点的话

   那样的话会产生很大的空间的浪费哦。

package com.yonyou.test;

import java.util.ArrayList;
import java.util.List;







/**
 * 测试类
 * @author 小浩
 * @创建日期 2015-3-20
 */
public class Test
 { 
	public static void main(String[] args){
		ArrayBinTree<String> binTree =new ArrayBinTree<String>(4, "根");
			binTree.add(0 , "第二层右子节点" , false);
			binTree.add(2 , "第三层右子节点" , false);
			binTree.add(6 , "第四层右子节点" , false);
			System.out.println(binTree);
	}
 }


/**
 * 子节点表示法,当前子节点记录他所对应的所有子节点的位置
 * @author 小浩
 * @创建日期 2015-3-23
 * @param <E>
 */
class ArrayBinTree<T>
{
	// 使用数组来记录该树的所有节点
	private Object[] datas;
	// 使用数组的深度
	private int DEFAULT_DEEP = 8;
	// 保存该树的深度
	private int deep;
    //树中实际节点的个数
	private int arraySize;
	
	/**
	 * 以默认的深度来创建二叉树
	 */
	public ArrayBinTree()
	{
		this.deep = DEFAULT_DEEP;
		this.arraySize = (int)Math.pow(2 , deep) - 1;
		datas = new Object[arraySize];
	}
	/**
	 *  以指定深度来创建二叉树
	 * @param deep
	 */
	public ArrayBinTree(int deep)
	{
		this.deep = deep;
		this.arraySize = (int)Math.pow(2 , deep) - 1;
		datas = new Object[arraySize];
	}
	
	/**
	 * 以指定深度,指定根节点创建二叉树
	 * @param deep
	 * @param data
	 */
	public ArrayBinTree(int deep , T data)
	{
		this.deep = deep;
		this.arraySize = (int)Math.pow(2 , deep) - 1;
		datas = new Object[arraySize];
		datas[0] = data;
	}
	/**
	 * 为指定节点添加子节点。
	 * @param index 需要添加子节点的父节点的索引
	 * @param data 新子节点的数据
	 * @param left 是否为左节点
	 */
	public void add(int index , T data , boolean left)
	{
		if (datas[index] == null)
		{
			throw new RuntimeException(index + "处节点为空,无法添加子节点");
		}
		if (2 * index + 1 >= arraySize)
		{
			throw new RuntimeException("树底层的数组已满,树越界异常");
		}
		// 添加左子节点
		if (left)
		{
			datas[2 * index + 1] = data;
		}
		else
		{
			datas[2 * index + 2] = data;
		}
	}
	
	/**
	 * 判断二叉树是否为空。
	 * @return
	 */
	public boolean empty()
	{
		// 根据根元素来判断二叉树是否为空
		return datas[0] == null;
	}
	
	/**
	 * 返回根节点。
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T root()
	{
		return (T)datas[0] ;
	}
	
	/**
	 * 返回指定节点(非根节点)的父节点。
	 * @param index
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T parent(int index)
	{
		return (T)datas[(index - 1) / 2] ;
	}
	
	/**
	 * 返回指定节点(非叶子)的左子节点。
	 * @param index
	 * @return
	 */
	// 当左子节点不存在时返回null。
	@SuppressWarnings("unchecked")
	public T left(int index)
	{
		if (2 * index + 1 >= arraySize)
		{
			throw new RuntimeException("该节点为叶子节点,无子节点");
		}
		return (T)datas[index * 2 + 1] ;
	}
	
	/**
	 * 返回指定节点(非叶子)的右子节点。
	 * @param index
	 * @return
	 */
	// 当右子节点不存在时返回null。
	@SuppressWarnings("unchecked")
	public T right(int index)
	{
		if (2 * index + 1 >= arraySize)
		{
			throw new RuntimeException("该节点为叶子节点,无子节点");
		}
		return (T)datas[index * 2 + 2] ;
	}
	/**
	 *  返回该二叉树的深度。
	 * @param index
	 * @return
	 */
	public int deep(int index)
	{
		return deep;
	}
	
	/**
	 * 返回指定节点的位置。
	 * @param data
	 * @return
	 */
	public int pos(T data)
	{
		// 该循环实际上就是按广度遍历来搜索每个节点
		for (int i = 0 ; i < arraySize ; i++)
		{
			if (datas[i].equals(data))
			{
				return i;
			}
		}
		return -1;
	}
	/**
	 * 重写toString方法
	 */
	public String toString()
	{
		return java.util.Arrays.toString(datas);
	}
}

2.二叉树的二叉链表存储

 

package com.yonyou.test;

import java.util.ArrayList;
import java.util.List;







/**
 * 测试类
 * @author 小浩
 * @创建日期 2015-3-20
 */
public class Test
 { 
	public static void main(String[] args){
		TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根节点");
		// 依次添加节点
		TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root()
			,  "第二层左节点" , true);
		TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root()
			, "第二层右节点" ,false );
		TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2
			, "第三层左节点" , true);
		TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2
			, "第三层右节点" , false);
		TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3
			, "第四层左节点" , true);
		System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
		System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
		System.out.println(binTree.deep());
	}
 }


/**
 * 二叉树的二叉链表存储法
 * @author 小浩
 * @创建日期 2015-3-23
 * @param <E>
 */
class TwoLinkBinTree<E>
{
	/**
	 * 存储相应节点的内部类
	 * @author 小浩
	 * @创建日期 2015-3-23
	 */
	public static class TreeNode
	{
		Object data;
		TreeNode left;
		TreeNode right;
		public TreeNode()
		{
		}
		public TreeNode(Object data)
		{
			this.data = data;
		}
		public TreeNode(Object data , TreeNode left
			, TreeNode right)
		{
			this.data = data;
			this.left = left;
			this.right = right;
		}
	}
	//当前树的根节点
	private TreeNode root;
	// 以默认的构造器来创建二叉树
	public TwoLinkBinTree()
	{
		this.root = new TreeNode();
	}
	// 以指定根元素来创建二叉树
	public TwoLinkBinTree(E data)
	{
		this.root = new TreeNode(data);
	}
	/**
	 * 为指定节点添加子节点。
	 * @param index 需要添加子节点的父节点的索引
	 * @param data 新子节点的数据
	 * @param isLeft 是否为左节点
	 * @return 新增的节点
	 */
	public TreeNode addNode(TreeNode parent , E data
		, boolean isLeft)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		if (isLeft && parent.left != null)
		{
			throw new RuntimeException(parent +
				"节点已有左子节点,无法添加左子节点");
		}
		if (!isLeft && parent.right != null)
		{
			throw new RuntimeException(parent +
				"节点已有右子节点,无法添加右子节点");
		}
		TreeNode newNode = new TreeNode(data);
		if (isLeft)
		{
			// 让父节点的left引用指向新节点
			parent.left = newNode;
		}
		else
		{
			// 让父节点的right引用指向新节点
			parent.right = newNode;
		}
		return newNode;
	}
	
	/**
	 * 判断二叉树是否为空。
	 * @return
	 */
	public boolean empty()
	{
		// 根据根元素来判断二叉树是否为空
		return root.data == null;
	}
	
	/**
	 * 返回根节点。
	 * @return
	 */
	public TreeNode root()
	{
		if (empty())
		{
			throw new RuntimeException("树为空,无法访问根节点");
		}
		return root;
	}
	
	/**
	 * 返回指定节点(非根节点)的父节点。
	 * @param node
	 * @return
	 */
	public E parent(TreeNode node)
	{
		// 对于二叉链表存储法,如果要访问指定节点的父节点必须遍历二叉树
		return null;
	}
	
	/**
	 * 返回指定节点(非叶子)的左子节点。当左子节点不存在时返回null
	 * @param parent
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E leftChild(TreeNode parent)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		return parent.left == null ? null : (E)parent.left.data;
	}
	
	/**
	 * 返回指定节点(非叶子)的右子节点。当右子节点不存在时返回null
	 * @param parent
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E rightChild(TreeNode parent)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		return parent.right == null ? null : (E)parent.right.data;
	}
	
	
	/**
	 * 返回该二叉树的深度。
	 * @return
	 */
	public int deep()
	{
		// 获取该树的深度
		return deep(root);
	}
	
	/**
	 * 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1
	 * @param node
	 * @return
	 */
	private int deep(TreeNode node)
	{
		if (node == null)
		{
			return 0;
		}
		// 没有子树
		if (node.left == null
			&& node.right == null)
		{
			return 1;
		}
		else
		{
			int leftDeep = deep(node.left);
			int rightDeep = deep(node.right);
			// 记录其所有左、右子树中较大的深度
			int max = leftDeep > rightDeep ?
				leftDeep : rightDeep;
			// 返回其左右子树中较大的深度 + 1
			return max + 1;
		}
	}
}

3.二叉树的三叉链表存储

 

package com.yonyou.test;








/**
 * 测试类
 * @author 小浩
 * @创建日期 2015-3-20
 */
public class Test
 { 
	public static void main(String[] args)
	{
		ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree("根节点");
		//依次添加节点
		ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root()
			,  "第二层左节点" , true);
		ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root()
			, "第二层右节点" ,false );
		ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2
			, "第三层左节点" , true);
		ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2
			, "第三层右节点" , false);
		ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3
			, "第四层左节点" , true);
		System.out.println("tn2的父节点:" + binTree.parent(tn2));
		System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
		System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
		System.out.println(binTree.deep());
	}
 }


/**
 * 二叉树的二叉链表存储法
 * @author 小浩
 * @创建日期 2015-3-23
 * @param <E>
 */
class ThreeLinkBinTree<E>
{
	public static class TreeNode
	{
		Object data;
		TreeNode left;
		TreeNode right;
		TreeNode parent;
		public TreeNode()
		{
		}
		public TreeNode(Object data)
		{
			this.data = data;
		}
		public TreeNode(Object data , TreeNode left
			, TreeNode right , TreeNode parent)
		{
			this.data = data;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}
	}
	private TreeNode root;
	// 以默认的构造器来创建二叉树
	public ThreeLinkBinTree()
	{
		this.root = new TreeNode();
	}
	// 以指定根元素来创建二叉树
	public ThreeLinkBinTree(E data)
	{
		this.root = new TreeNode(data);
	}
	/**
	 * 为指定节点添加子节点。
	 * @param index 需要添加子节点的父节点的索引
	 * @param data 新子节点的数据
	 * @param isLeft 是否为左节点
	 * @return 新增的节点
	 */
	public TreeNode addNode(TreeNode parent , E data
		, boolean isLeft)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		if (isLeft && parent.left != null)
		{
			throw new RuntimeException(parent +
				"节点已有左子节点,无法添加左子节点");
		}
		if (!isLeft && parent.right != null)
		{
			throw new RuntimeException(parent +
				"节点已有右子节点,无法添加右子节点");
		}
		TreeNode newNode = new TreeNode(data);
		if (isLeft)
		{
			// 让父节点的left引用指向新节点
			parent.left = newNode;
		}
		else
		{
			// 让父节点的right引用指向新节点
			parent.right = newNode;
		}
		// 让新节点的parent引用到parent节点
		newNode.parent = parent;
		return newNode;
	}
	// 判断二叉树是否为空。
	public boolean empty()
	{
		// 根据根元素来判断二叉树是否为空
		return root.data == null;
	}
	// 返回根节点。
	public TreeNode root()
	{
		if (empty())
		{
			throw new RuntimeException("树为空,无法访问根节点");
		}
		return root;
	}
	// 返回指定节点(非根节点)的父节点。
	@SuppressWarnings("unchecked")
	public E parent(TreeNode node)
	{
		if (node == null)
		{
			throw new RuntimeException(node +
				"节点为null,无法访问其父节点");
		}
		return (E)node.parent.data;
	}
	// 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
	@SuppressWarnings("unchecked")
	public E leftChild(TreeNode parent)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		return parent.left == null ? null : (E)parent.left.data;
	}
	// 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
	@SuppressWarnings("unchecked")
	public E rightChild(TreeNode parent)
	{
		if (parent == null)
		{
			throw new RuntimeException(parent +
				"节点为null,无法添加子节点");
		}
		return parent.right == null ? null : (E)parent.right.data;
	}
	// 返回该二叉树的深度。
	public int deep()
	{
		// 获取该树的深度
		return deep(root);
	}
	// 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1
	private int deep(TreeNode node)
	{
		if (node == null)
		{
			return 0;
		}
		// 没有子树
		if (node.left == null
			&& node.right == null)
		{
			return 1;
		}
		else
		{
			int leftDeep = deep(node.left);
			int rightDeep = deep(node.right);
			// 记录其所有左、右子树中较大的深度
			int max = leftDeep > rightDeep ?
				leftDeep : rightDeep;
			// 返回其左右子树中较大的深度 + 1
			return max + 1;
		}
	}
}

4.二叉树的几种遍历方法的讲解

   如果采用顺序存储来保存二叉树的话,那么遍历此二叉树很简单,直接遍历数组就可以了,但是如果要是采用三叉链表或者

   而叉链表的话,那么就会有很多的不同哦。

   如果采用链表来存储二叉树的话,那么我们可以有两种遍历二叉树的方法:

      1)深度优先遍历

          a、先序遍历二叉树(前序遍历二叉树)

          b、中序遍历二叉树

          c、后序遍历二叉树

      2)广度优先遍历,右称为按层遍历。

    

 下面将会从具体的代码进行相关内容的讲解:

  a、先序遍历二叉树

     

      // 实现先序遍历
	public List<TreeNode> preIterator()
	{
		return preIterator(root);
	}
	private List<TreeNode> preIterator(TreeNode node)
	{
		List<TreeNode> list = new ArrayList<TreeNode>();
		// 处理根节点
		list.add(node);
		// 递归处理左子树
		if (node.left != null)
		{
			list.addAll(preIterator(node.left));
		}
		// 递归处理右子树
		if (node.right != null)
		{
			list.addAll(preIterator(node.right));
		}
		return list;
	}

 

  b、中序遍历二叉树

   

// 实现中序遍历
	public List<TreeNode> inIterator()
	{
		return inIterator(root);
	}
	private List<TreeNode> inIterator(TreeNode node)
	{
		List<TreeNode> list = new ArrayList<TreeNode>();
		// 递归处理左子树
		if (node.left != null)
		{
			list.addAll(inIterator(node.left));
		}
		// 处理根节点
		list.add(node);
		// 递归处理右子树
		if (node.right != null)
		{
			list.addAll(inIterator(node.right));
		}
		return list;
	}
	public List<TreeNode> postIterator()
	{
		return postIterator(root);
	}

  

      c、后序遍历二叉树

 

// 实现后序遍历
	private List<TreeNode> postIterator(TreeNode node)
	{
		List<TreeNode> list = new ArrayList<TreeNode>();
		// 递归处理左子树
		if (node.left != null)
		{
			list.addAll(postIterator(node.left));
		}
		// 递归处理右子树
		if (node.right != null)
		{
			list.addAll(postIterator(node.right));
		}
		// 处理根节点
		list.add(node);
		return list;
	}

  d、广度优先遍历二叉树

     

// 广度优先遍历
	public List<TreeNode> breadthFirst()
	{
		Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
		List<TreeNode> list = new ArrayList<TreeNode>();
		if( root != null)
		{
			// 将根元素加入“队列”
			queue.offer(root);
		}
		while(!queue.isEmpty())
		{
			// 将该队列的“头部”的元素添加到List中
			list.add(queue.peek());
			// 将该队列的“头部”的元素移出队列
			TreeNode p = queue.poll();
			// 如果左子节点不为null,将它加入“队列”
			if(p.left != null)
			{
				queue.offer(p.left);
			}
			// 如果右子节点不为null,将它加入“队列”
			if(p.right != null)
			{
				queue.offer(p.right);
			}
		}
		return list;
	}

 

  

好吧,由于篇幅的限制,今天先到这里,下一篇我们将要继续探讨树和二叉树的相关内容。

下一篇的地址为:

 

     

     

  

 

  

 

 

 

  

 

 

 

  

 

 

 

 

posted on 2015-03-21 11:46  @ 小浩  阅读(1821)  评论(0编辑  收藏  举报