二叉树的递归定义
二叉树或者是一棵空树,或者是一棵由一个根节点和两棵互不相交的分别称作根节点的左子树和右子树所组成的非空树,左子树和右子树又同样是一棵二叉树。
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
二叉树构造
通过先序遍历和中序遍历来构造一棵二叉树,先序遍历是从父节点、左节点、右节点来进行的遍历,中序遍历则是先从左节点、父节点、右节点的遍历顺序,从先序遍历的串中可以得出其根节点,而根据该根节点可以将中序遍历的结果划分为两部分,左侧的是左子树,右侧的是右子树,那么,通过将该树划分成左右子树之后,可以通过递归的方式对左子树和右子树进行同样的递归操作,从而构造出一棵二叉树。
根据这样的思想进行实现,下面程序可能还要很多可以改进的地方,希望看到的朋友给出指正。
基本的思路:先序遍历的数组,依次取第一个元素node,构成父节点,在中序遍历的数组中找到该node的位置,将中序遍历的数组按照node的位置进行拆分,拆分成左右两部分。同时根据拆分出来的中序遍历中的左右数组的长度来切分先序遍历的数组,同样切分出左右子树两部分。那么左侧的子树和右侧的子树同样已经求出其先序遍历和中序遍历的序列了,通过递归的方式构造出整个二叉树。
/**
* 重构二叉树
* @param pre
* @param in
* @return
*/
public static TreeNode reConstructBinaryTree2(int [] pre,int [] in) {
if(pre.length == 0 || in.length == 0)
return null;
TreeNode node = new TreeNode(pre[0]);
if(pre.length == 1 && in.length == 1 && pre[0] == in[0])
return node;
int index = 0;
for(int a : in) {
if(a == node.val)
break;
index ++;
}
int[] leftin = Arrays.copyOfRange(in, 0, index);
int[] rightin = Arrays.copyOfRange(in, index + 1, pre.length);
int[] leftpre = Arrays.copyOfRange(pre, 1, leftin.length + 1);
int[] rightpre = Arrays.copyOfRange(pre, leftin.length + 1, pre.length);
node.left = reConstructBinaryTree2(leftpre, leftin);
node.right = reConstructBinaryTree2(rightpre, rightin);
return node;
}
二叉树的遍历
先序遍历、中序遍历和后序遍历通过递归的方式实现的话比较简单。
如先序遍历:先遍历父节点然后左节点,然后是遍历右节点,又因为二叉树定义又是递归的,所以也适用于其左子树和右子树,左子树又可以进行递归,右子树也可以。
/**
* 后序遍历
* @param node
*/
private static void getAllNodeAF(TreeNode node) {
if(node != null) {
getAllNode(node.left);
getAllNode(node.right);
System.out.print(node.val + " ");
}
else {
System.out.print("# ");
}
}
/**
* 中序遍历
* @param node
*/
private static void getAllNodeIn(TreeNode node) {
if(node != null) {
getAllNode(node.left);
System.out.print(node.val + " ");
getAllNode(node.right);
}
else {
System.out.print("# ");
}
}
/**
* 先序遍历
* @param node
*/
private static void getAllNode(TreeNode node) {
if(node != null) {
System.out.print(node.val + " ");
getAllNode(node.left);
getAllNode(node.right);
}
else {
System.out.print("# ");
}
}
二叉树的层次遍历
所谓层次遍历就是说将树中每一层的数据依次输出,那么这时需要考虑的一个问题就是左子树遍历的同时也要遍历右子树。当然这种方式是一个思路。但是要真正的实现左右子树同时的进行遍历还是比较麻烦的因为左子树不只有左节点还有右节点,如果现在当前节点有两个子节点而每个子节点本身又有两个子节点,同样下面仍然存在节点,暂且不论到底最终多少子节点,这里的问题是当你遍历到第二层(以根节点为第一层)时,下面的子节点两个,这时较容易表示,但是当再往下一层的时候节点数量就又一次变化了,变成了四个,那么要想依次的遍历四个节点的子树的话,通过固定数量变量的方式已经无法满足,所以这里我使用了两种方式来实现,一种是使用动态数组,另一种是队列的方式。
通过ArrayList的方式进行层次遍历。
基本思路是:将节点添加在该list中,取出的时候进行输出,并将其左右子节点全部放入该list中,只要是list不是空的就不断的遍历下去。
/**
* 层次遍历
* @param node
*/
private static void getAllNodeOrder(TreeNode node) {
List<TreeNode> list = new ArrayList<TreeNode>();
list.add(node);
while(list.size() > 0) {
TreeNode node2 = list.get(0);
if(node2 == null) {
System.out.print(" # ");
}else {
System.out.print(node2.val + " ");
if(!(node2.left == null && node2.right == null)) {
list.add(node2.left);
list.add(node2.right);
}
}
list.remove(0);
}
}
使用队列实现层次遍历,不过本质上用的这个ArrayDeque也是数组,循环数组。
其不支持null的数据,所以,将其放入队列中的时候,需要先访问后存储的方式,不是空的话并且其左右子节点至少一个存在的时候才将其存入队列中。
/**
* 层次遍历2
* @param node
*/
private static void getAllNodeOrder2(TreeNode node) {
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
queue.add(node);
System.out.print(node.val);
while(queue.size() > 0) {
TreeNode node2 = queue.poll();
if(node2.left != null)
System.out.print(node2.left.val + " ");
else if(!(node2.left == null && node2.right == null))
System.out.print("#");
if(node2.right != null)
System.out.print(node2.right.val + " ");
else if(!(node2.left == null&& node2.right == null))
System.out.print("#");
if(!(node2.left == null))
queue.add(node2.left);
if(!(node2.right == null))
queue.add(node2.right);
}
}