zoukankan      html  css  js  c++  java
  • 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;
    	}
    

      

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

    下一篇的地址为:

         

         

      

      

     

      

     

      

     

     

  • 相关阅读:
    TP之Model(select(),add())
    TP之空操作及View模块
    ThinkPHP之初识
    smarty引擎之练习
    领先环境HTML
    php流程
    分页
    弹窗
    邮箱项目
    TP框架修改操作
  • 原文地址:https://www.cnblogs.com/xiohao/p/4355334.html
Copyright © 2011-2022 走看看