书接上回,今天和大家一起动手来自己实现树。
相信通过前面的章节学习,大家已经明白树是什么了,今天我们主要针对二叉树,分别使用顺序存储和链式存储来实现树。
01、数组实现我们在上一节中说过,如果从树的顶层开始从上到下,从左到右,对每个节点按顺序进行编号,根节点为1作为起始,则有节点编号i,其左子节点编号为2i,其右子节点编号为2i+1。但是我们知道数组的索引是从0开始,因此如果我们用数组实现二叉树,那么我们可以把上面的编号改为从0开始,因此可以得到如下结论:
节点编号:i;
其左子节点编号:2i+1;
其右子节点编号:2i+2;
1、初始化 Init初始化主要是指定树节点容量,创建指定容量的数组。
树节点数可以通过内部数组长度直接获取。
获取节点索引主要是为了把节点值转为索引值,因为我们是使用数组实现,元素的操作更多依赖索引。其实我们还有其他方案来处理获取索引的方式,比如可以通过设计元素对象使其包含索引字段,这样其实操作起来更为方便。下面我们还是用最直接获取的方法作为演示。
该方法用于实现通过子节点索引计算父节点索引,无论左子节点还是右子节点,使用下面一个公式就可以了,代码如下:
该方法用于根据父节点索引计算左子节点索引。
该方法用于根据父节点索引计算右子节点索引。
该方法通过节点索引获取节点值,如果索引越界则报错。
该方法是通过节点索引获取其左节点值,首先获取左子节点索引,再取左子节点值。
该方法是通过节点索引获取其右节点值,首先获取右子节点索引,再取右子节点值。
该方法是通过节点索引添加或更新节点值,因为数组初始化的时候已经有了默认值,因此添加或者更新节点值就是直接给数组元素赋值,如果索引越界则报错。
该方法根据节点值添加或更新其左子节点值,首先通过节点值找到其索引,然后通过其索引计算出其左子节点索引,索引校验成功后,直接更新左子节点值。
该方法根据节点值添加或更新其右子节点值,首先通过节点值找到其索引,然后通过其索引计算出其右子节点索引,索引校验成功后,直接更新右子节点值。
该方法通过节点索引删除其自身以及其所有后代节点,删除后代节点需要左右子节点分别递归调用方法自身。
该方法通过节点值删除其左节点以及其左节点所有后代节点,首先通过节点值获取节点索引,然后计算出左子节点索引,最后通过调用删除节点Remove方法完成删除。
该方法通过节点值删除其右节点以及其右节点所有后代节点,首先通过节点值获取节点索引,然后计算出右子节点索引,最后通过调用删除节点Remove方法完成删除。
前序遍历的核心思想就是先打印树的根节点,然后再打印树的左子树,最后打印树的右子树。
中序遍历的核心思想就是先打印树的左子树,然后再打印树的根节点,最后打印树的右子树。
后序遍历的核心思想就是先打印树的左子树,然后再打印树的右子树,最后打印树的根节点。
层次遍历的核心思想是借助队列,从根节点开始,从上到下,从左到右,先入列后等待后续打印,然后出列后立即打印,同时把此节点的左右子节点按顺序加入队列,循环往复直至所有元素打印完成。
链表实现通用性会更强,基本可以实现所有的树结构,同时操作也更方便了,下面我们还是以二叉树的实现为例做演示。
1、初始化树根节点 InitRoot在初始化树根节点前需要定义好链表的节点,其包含数据域和左右子节点,同时在树种还需要维护根节点以及节点数量两个私有字段。
树节点数量可以通过私有字段_count直接返回。
根节点可以通过私有字段_root直接返回。
该方法是通过节点添加或更新其左子节点值。
该方法是通过节点添加或更新其右子节点值。
该方法通过节点删除其自身以及其所有后代节点,需要递归删除左右子节点及其所有后代节点。
核心思想和数组实现一样。
核心思想和数组实现一样。
核心思想和数组实现一样。
核心思想和数组实现一样。
注:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner