在存储满二叉树或近似满二叉树时,按节点层次顺序存储是个不错的主意,我们从根节点开始,逐层由左到右扫描各个节点,依次将节点数据存放到指定的数组中,如果偶尔遇到空的子节点,就用特殊符号来表示。
这个树结构已接近满二叉树了,如果使用按层次顺序存储,将会更简单,更节省空间。按照上面的方法,这棵树所对应的存储结构应该是:
['A', 'B', 'E', 'C', 'D', '#', 'F']
其中空的子节点,我们使用#号来占位。
根据这个存储结构,我们就可以构建出一棵二叉树,还原它本来的面目。
思路如下:
- 我们知道,根节点起始位置array[0],节点个数为1,第二层起始位置array[1],节点个数为2;依次类推,每一层起始位置的索引都是前面节点的总个数,我们需要记录父层起始位置和当前层的起始位置。
- 根据满二叉树的结构,可以得出当前层节点的个数:pow(2, level -1),即2的level - 1次方,其中level即为当前层数,从1开始。
- 遍历当前层的节点,规则是:每遍历两个节点(左右子节点),父层遍历一个,在遍历过程中,创建相应的节点对象,并与父节点进行关联。
- 遍历完成后,当前层将成为下一轮的父层,重新计算下一层的起始位置和节点个数。然后开始下一轮。
上面提到,这种存储顺序适用于满二叉树或接近满二叉树的情况,所以这里我们只考虑极少数的空叶子节点,对于最后一层空的叶子节点,如果它们是连续排在最后面的,则也可以省略,以节省存储空间。
下面是实现代码:
JS版:
//二叉树节点结构
function BinTreeNode(data) {
this.data = data;
this.leftChild = null;
this.rightChild = null;
}
//根据顺序存储序列创建二叉树
function createBinTreeByArray(array) {
//初始化树的层次,每层存储pow(2, currLevel - 1)个节点数据
var currLevel = 1;
//初始化当前节点层和父层起始位置
var currLevelBegin = 0,
parentLevelBegin = 0;
//节点数组,用于放置新建的节点
var nodeArray = [];
//循环遍历每一层
while (currLevelBegin < array.length) {
//每一层的节点数量
var levelNumber = Math.pow(2, currLevel - 1);
//记录父层的step,初始值0
var parentStep = 0;
//遍历当前节点层每个节点数据
for (var step = 0; step < levelNumber; step++) {
//计算在数组中的索引
var index = currLevelBegin + step;
if (index >= array.length) break;
var node = null;
//创建节点对象,并放进节点数组中
if (array[index] !== '#') {
node = new BinTreeNode(array[index]);
nodeArray.push(node);
}
//如果不是根节点层,则需要与父节点做关联
if (currLevelBegin > 0) {
//获取父节点
var parentNode = nodeArray[parentLevelBegin + parentStep];
//step是从0开始的,如果是偶数则成为左子节点,奇数则成为右子节点