二叉树的存储结构

二叉树节点的表示法:

  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());
	}
	
}

### 二叉树存储结构及其实现 #### 链式存储结构的特点 链式存储结构通过链表来表示一颗二叉树,其中每个节点由三个部分构成:数据域以及指向左子节点和右子节点的两个指针[^2]。 ```c++ struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; ``` 这种结构允许灵活地处理任意形状的二叉树而不必担心空间浪费的问题。对于非完全二叉树来说尤其有利,因为顺序存储可能会导致大量的内存浪费。 #### 构建二叉树的过程 创建一个基于字符串输入的函数`CreateBTNode`用于初始化给定形态的二叉树[^1]: ```cpp TreeNode* CreateBTNode(TreeNode*& b, const char* str){ if (*str == '\0') return nullptr; // 如果遇到结束符,则返回空 TreeNode *node = new TreeNode(*str); // 新建结点并赋初值 b = node; while (*(++str) != '(' && *str != '\0'); // 跳过字符直到找到'('或者'\0' if (*str != '\0'){ ++str; b->left = CreateBTNode(b->left, str); while (*str != ')' && *str != '\0') ++str; if (*str != '\0') ++str; b->right = CreateBTNode(b->right, str); while (*str != ')' && *str != '\0') ++str; } return b; } ``` 此代码片段展示了如何解析描述二叉树结构的字符串,并据此建立相应的二叉树实例。注意这里假设传入的是合法格式化的字符串表达形式。 #### 顺序存储结构的应用场景 尽管大多数情况下推荐使用链式存储方法,但在某些特定应用场景下(比如堆),仍然会选择采用数组来进行二叉树的顺序化保存。这种方式简单直观,但对于不完全是满二叉树的情况会造成不必要的资源占用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值