二叉树的存储结构

二叉树节点的表示法:

  1. 二叉树数组表示法
  2. 二叉树链表表示法

“数组表示法”属于静态内存空间配置,而“链表表示法”是利用链表结构的方式,属于动态内存空间配置。、

二叉树数组表示法

/**
 * 树节点的定义
 */
class TreeNode
{
	int val;
	TreeNode left; // 左子树节点
	TreeNode right; // 右子树节点
	
	TreeNode(int x)
	{
		val = x;
	}
}

/**
 * 二叉树的顺序存储结构
 */
class BinaryTree
{
	private int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	private static List<TreeNode> nodeList = null;
	 
	/**
	 * 树节点的定义
	 */
	private class TreeNode
	{
		int val;
		TreeNode left; // 左子树节点
		TreeNode right; // 右子树节点
		
		TreeNode(int x)
		{
			left = null;
			right = null;
			val = x;
		}
	}
	
	
	public BinaryTree()
	{
		createBiTree();
     	// nodeList中第0个索引处的值即为根节点
		TreeNode root = nodeList.get(0);
		
		System.out.println("先序遍历:");
		preOrderTraverse(root);
		System.out.println();
		
		System.out.println("中序遍历:");
		inOrderTraverse(root);
		System.out.println();
		
		System.out.println("后序遍历:");
		postOrderTraverse(root);
	}
	
	/**
	 * 构造一棵满二叉树
	 */
	private void createBiTree()
	{
		nodeList = new LinkedList<TreeNode>();
		// 将TreeNode节点加入到链表中
		for (int nodeIndex=0; nodeIndex<array.length; nodeIndex++)
		{
			nodeList.add(new TreeNode(array[nodeIndex]));
		}
		
		// 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树
		for (int parentIndex=0; parentIndex<array.length/2-1; parentIndex++)
		{
			// 左孩子
			nodeList.get(parentIndex).left = nodeList.get(parentIndex*2+1);
			// 右孩子
			nodeList.get(parentIndex).right = nodeList.get(parentIndex*2+2);
		}
		
		// 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理
		int lastParentIndex = array.length / 2 - 1;
		// 左孩子
		nodeList.get(lastParentIndex).left = nodeList.get(lastParentIndex*2+1);
		// 右孩子,如果数组的长度为奇数才建立右孩子
		if (array.length % 2 == 1)
		{
			nodeList.get(lastParentIndex).right = nodeList.get(lastParentIndex*2+2);
		}
	}
	
	/**
	 * 先序遍历
	 */
	public static void preOrderTraverse(TreeNode node)
	{
		if (node == null)
		{
			return;
		}
		System.out.print(node.val + " ");
		// 遍历左子树
		preOrderTraverse(node.left);
		// 遍历右子树
		preOrderTraverse(node.right);
	}
	
	/**
	 * 中序遍历
	 */
	public static void inOrderTraverse(TreeNode node)
	{
		if (node == null)
		{
			return;
		}
		// 遍历左子树
		inOrderTraverse(node.left);
		System.out.print(node.val + " ");
		// 遍历右子树
		inOrderTraverse(node.right);
	}
	
	/**
	 * 后序遍历
	 */
	public static void postOrderTraverse(TreeNode node)
	{
		if (node == null)
		{
			return;
		}
		// 遍历左子树
		postOrderTraverse(node.left);
		// 遍历右子树
		postOrderTraverse(node.right);
		System.out.print(node.val + " ");
	}
}


二叉树链表表示法

/**
 * 二叉树的链式存储结构
 * https://www.cnblogs.com/Dylansuns/p/6791852.html
 */
public class BinaryTree<E>
{
	/**
	 * 树节点的定义
	 */
	class TreeNode
	{
		Object data;
		TreeNode left; // 左子树节点
		TreeNode right; // 右子树节点
		
		TreeNode()
		{
		}
		
		TreeNode(Object data)
		{
			this.data = data;
		}
		
		TreeNode(Object data, TreeNode left, TreeNode right)
		{
			this.data = data;
			this.left = left;
			this.right = right;
		}
	}
	
	private TreeNode root;
	
	// 以默认的构造器创建二叉树
	public BinaryTree()
	{
		this.root = new TreeNode();
	}
	
	// 以指定根元素创建二叉树
	public BinaryTree(E data)
	{
		this.root = new TreeNode(data);
	}
	
	/**
	 * 为指定节点添加子节点
	 */
	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;
	}
	
	// 判断二叉树是否为空
	public boolean empty()
	{	
		return root.data==null;
	}
	
	// 返回根节点
	public TreeNode root()
	{
		if (empty())
		{
			throw new RuntimeException("树为空,无法访问根节点");
		}
		return root;
	}
	
	// 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
	 public E leftChild(TreeNode parent) {
	     if (parent == null) {
	         throw new RuntimeException(parent + "节点为null,无法添加子节点");
	     }
	     return parent.left == null ? null : (E) parent.left.data;
	 }

	 // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
	 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
	public 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;
		}
	}
	
	// 测试
	public static void main(String[] args)
	{
		BinaryTree<String> binTree = new BinaryTree<String>("根节点");
        // 依次添加节点
        BinaryTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
        BinaryTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
        BinaryTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
        BinaryTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
        BinaryTree.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());
	}
	
}

猜你喜欢

转载自blog.csdn.net/tc_1337/article/details/80543110