数据结构(三)树

36 篇文章 0 订阅

 树就是一种类似现实生活中树 (倒置的树) 的数据结构。对于任何一个非空树来说,它只有一个根节点。

树的特点如下:

  • 一棵树中的任意两个结点有且仅有唯一的一条路径连通。
  • 一棵树如果有 n 个结点,那么它一定恰好有 n-1 条边。
  • 一棵树不包含回路。

1 树中常用的概念 

 下图就是一颗树,并且是一颗二叉树:

  • 节点 :树中的每个元素都可以统称为节点。
  • 根节点 :顶层节点或没有父节点的节点。
  • 父节点 :若一个节点含有子节点,则这个节点称为其子节点的父节点。
  • 子节点 :一个节点下的节点称为该节点的子节点。
  • 兄弟节点 :具有相同父节点的节点互称为兄弟节点。
  • 叶子节点 :没有子节点的节点。上图中的 D、F、H、I 都是叶子节点。
  • 节点的高度 :叶子节点到该节点的最长路径所包含的边数。
  • 节点的深度 :根节点到该节点的路径所包含的边数
  • 节点的层数 :节点的深度+1。
  • 树的高度 :根节点的高度。

2 二叉树的分类

二叉树(Binary tree)是每个节点最多只有两个分支的树结构。

二叉树的特性:

  • 左子树上所有结点的值均小于或等于它的根结点的值。
  • 右子树上所有结点的值均大于或等于它的根结点的值。
  • 左、右子树也分别为二叉排序树。

二叉树 的分支通常被称作 “左子树” 或 “右子树” 。并且 二叉树 的分支具有左右次序,不能随意颠倒。

二叉树 的第 i 层至多拥有 2^(i-1) 个节点,深度为 k 的二叉树至多总共有 2^(k+1)-1 个节点(满二叉树的情况),至少有 2^(k) 个节点。

2.1 满二叉树

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是 满二叉树。也就是说,如果一个二叉树的层数为 K,且结点总数是(2^k) -1 ,则它就是 满二叉树。如下图所示:

2.2 完全二叉树

除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则这个二叉树就是 完全二叉树 。由定义可知,满二叉树也是完全二叉树的一种。

大家可以想象为一棵树从根结点开始扩展,扩展完左子节点才能开始扩展右子节点,每扩展完一层,才能继续扩展下一层。如下图所示:

 完全二叉树有一个很好的性质父结点和子节点的序号有着对应关系。这个性质使得完全二叉树利用数组存储时可以极大地节省空间,以及利用序号找到某个节点的父结点和子节点,后续二叉树的存储会详细介绍。比如当根节点的值为 0 的情况下,若父结点的序号是 i,那么左子节点的序号就是 2i + 1,右子节点的序号是 2i + 2。

2.3 平衡二叉树

平衡二叉树又称平衡二叉查找树 并且 是一个二叉排序树 。当节点数目一定,使得树的左右两端保持平衡,树的查找效率最高。含有n个结点的平衡二叉树的最大深度为 O(log2(n)),即平衡二叉树的平均查找长度为  O(log2(n))。

平衡二叉树具有以下性质:

  • 可以是一棵空树
  • 如果不是空树,左右子树的高度相差不超过 1 的树为平衡二叉树,并且左右两个子树都是一棵平衡二叉树。

3 二叉树的存储 

二叉树的存储主要分为 链式存储 和 顺序存储 两种:

3.1 链式存储

和链表类似,二叉树的链式存储依靠指针将各个节点串联起来,不需要连续的存储空间。

每个节点包括三个属性:

  • 数据 data。data 不一定是单一的数据类型,根据不同情况,可以是多个具有不同类型的数据。
  • 左节点指针 left
  • 右节点指针 right。

3.2 顺序存储

顺序存储就是利用数组进行存储,数组中的每一个位置仅存储节点的 data,不存储左右子节点的指针,所有子节点的索引会通过数组下标完成。根结点的序号索引为 1,对于每个节点 Node,假设它存储在数组中下标为 i 的位置,那么它的左子节点就存储在 2 * i 的位置,它的右子节点存储在下标为 2 * i + 1 的位置。

一棵完全二叉树的数组顺序存储如下图所示:

4 二叉树的遍历

遍历方式包括:

  • 先序遍历
  • 中序遍历
  • 后序遍历

4.1 先序遍历

二叉树的先序遍历,就是先输出根结点,再遍历左子树,最后遍历右子树。遍历左子树和右子树的时候,同样遵循先序遍历的规则,也就是说,我们可以递归实现先序遍历。 

public void preOrder(TreeNode root){
	if(root == null){
		return;
	}
	system.out.println(root.data);
	preOrder(root.left);
	preOrder(root.right);
}

4.2 中序遍历

二叉树的中序遍历,就是先递归中序遍历左子树,再输出根结点的值,再递归中序遍历右子树。

public void inOrder(TreeNode root){
	if(root == null){
		return;
	}
	inOrder(root.left);
	system.out.println(root.data);
	inOrder(root.right);
}

4.3 后序遍历

二叉树的后序遍历,就是先递归后序遍历左子树,再递归后序遍历右子树,最后输出根结点的值。

public void postOrder(TreeNode root){
	if(root == null){
		return;
	}
	postOrder(root.left);
	postOrder(root.right);
	system.out.println(root.data);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值