今天我们来学习如何将二叉树转为数组(填坑学点算法(九)——二叉树中序遍历算法(递归实现))。
首先,我们看下面这棵二叉树,我们从根节点出发,左右孩子依次排列在根节点后面,放入数组中,然后继续以同样的方法遍历其左右孩子,如果孩子节点的位置已经被叔父节点占据,则继续排在叔父节点后面,如果遇到没有左右孩子的情况,则将没有的节点置为null
,将节点排列在数组中,直至遍历结束,位于数组结尾的null
(后面没有有效节点值)可去除。
我们来看下这个过程:
- 首先我们放入
1
及其左右孩子,得到[1, 2, 3]
。 - 取
1
的左孩子2
的左右孩子,因为2
后面的位置被3
占据了,所以4, 5
需要排在3
后面,得到[1, 2, 3, 4, 5]
。 - 取
1
的右孩子3
的左右孩子,因为3
后面的位置被4, 5
占据了,所以6, 7
需要排在4, 5
后面,得到[1, 2, 3, 4, 5, 6, 7]
。 4 5 6 7
没有孩子节点,全部置为null
,得到[1, 2, 3, 4, 5, 6, 7, null, null, null, null]
因为null值都位于末尾,所以得到[1, 2, 3, 4, 5, 6, 7]
。
通过这个过程,可以发现节点的位置就是先到先得,谁先遇到了,就占据了这个位置,后面来的节点都往后排,这个过程跟队列的先进先出是一样的,所以我们很容易想到可以用队列来保存遇到的节点,并依次将它放到数组中。
/**
* 将二叉树转为数组(二叉树层次遍历)
* @param root 二叉树根节点
* @param <T> 二叉树元素类型
* @return 数组
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<T>> T[] convertTree2Array(BinaryTreeNode<T> root) {
if (root == null) {
// 如果根节点为null,则返回null
return null;
}
// 由于不知道数组长度,先将元素存入list中
List<T> list = new ArrayList<>();
BinaryTreeNode<T> currentNode = root;
Deque<BinaryTreeNode<T>> queue = new ArrayDeque<>();
// 创建一个特殊对象来存储null
BinaryTreeNode<T> NULL = new BinaryTreeNode<>(null);
do {
// 添加节点元素到列表中
list.add(currentNode.data);
if (currentNode != NULL) {
// 获取左子树节点
BinaryTreeNode<T> leftChild = currentNode.leftChild;
if (leftChild == null) {
queue.offer(NULL);
} else {
queue.offer(leftChild);
}
// 获取右子树节点
BinaryTreeNode<T> rightChild = currentNode.rightChild;
if (rightChild == null) {
queue.offer(NULL);
} else {
queue.offer(rightChild);
}
}
// 从队列中取出下一个节点
currentNode = queue.poll();
// 如果currentNode为null,表示没有剩余元素了,可退出循环
} while (currentNode != null);
return list.toArray((T[]) Array.newInstance(root.data.getClass(), 0));
}
代码中要注意的是NULL
这个特殊对象,这个对象表示此处没有节点,但是在数组中我们还是需要放置一个null
来表示,所以单独使用了一个特殊对象来存这个值。
测试代码如下:
BinaryTreeNode<Integer> one = new BinaryTreeNode<>(1);
BinaryTreeNode<Integer> two = new BinaryTreeNode<>(one, 2);
BinaryTreeNode<Integer> three = new BinaryTreeNode<>(one, 3);
one.leftChild = two;
one.rightChild = three;
BinaryTreeNode<Integer> four = new BinaryTreeNode<>(two, 4);
BinaryTreeNode<Integer> five = new BinaryTreeNode<>(two, 5);
two.leftChild = four;
two.rightChild = five;
BinaryTreeNode<Integer> six = new BinaryTreeNode<>(three, 6);
BinaryTreeNode<Integer> seven = new BinaryTreeNode<>(three, 7);
three.leftChild = six;
three.rightChild = seven;
Integer[] arr = convertTree2Array(one);
// 因为数组后面的null不影响数据,为了方便测试,将数组后面的null值都去掉
int idx = arr.length - 1;
while (arr[idx] == null) {idx--;}
Integer[] nullFilteredArr = Arrays.copyOf(arr, idx + 1);
assertArrayEquals(new Integer[]{1, 2, 3, 4, 5, 6, 7}, nullFilteredArr);