中序线索二叉树就是在普通的二叉树上加上了中序线索。
为了节省空间,只增加两个判定位。flagLeft 和 flagRight,当为0时,表示存放的是子女节点。为1时,表示存放的线索。
其中,左节点存放中序前继,右节点存放中序后继。
使用线索,可以有效降低二叉树遍历的复杂度。前序,中序,后序遍历都可不用递归栈实现,而付出的代价只是几个标志位。
建立中序线索二叉树,可以用普通中序遍历实现。用一个pre保存中序前节点,在中序访问时,贯通前后即可。
C++ pre用指针引用,java pre用对象数组保存。因为pre值要保证能在递归过程中传递
最后注意将中序最后一个节点手动赋值。
对于由中序线索二叉树实现树的前序、中序、后序非递归,非栈遍历。之所以能不用栈,是因为中序线索保存了相关信息。
要注意,先找到第一个节点,然后利用中序线索找后继即可。
对于前序,其后继为当前节点右子女走,flagRight为0的第一个节点的右子女。
中序,后继已给出,注意同样要将flagRight为1的的节点一次遍历完。
实际上,画个图模拟一下就清楚了。
建立普通二叉树可根据中序、前序字符串建立的。思想是,根据前序找到根节点,然后根据中序化为左右子树,不断递归。
在划分过程中,左子树和右子树在前序、中序字符串中都是连续的。并且中序和前序字符串长度总是相等。可根据这一点简化划分。
下面给出java代码实现:
package com.company;
/**
* 根据中序及前序建立二叉树
* 根据后序及前序建立二叉树
* 二叉树中序索引化
* Created by zqiguo on 2017/3/8.
*/
public class IndexBinaryTree {
private static class IndexNode{
char value;
IndexNode left;
IndexNode right;
boolean flagLeft;
boolean flagRight;
}
/**
* 建立中序索引二叉树的公用接口,注意手动赋值最后一节点。
* @param root
*/
public static void creatMidIndexTree(IndexNode root){
if (root == null) {
return;
}
IndexNode[] pre = new IndexNode[1];
creatMidIndexTree(root, pre);
pre[0].right = null;
pre[0].flagRight = true;
}
/**
* 建立中序索引,之所以pre 为[]类型,为了在递归中传递值。
* pre保存前一中序节点,这样就足够,注意要手动将最后一个节点右子树赋值。
* 左节点走到底,脑中模拟一遍,就出结果了。
* @param root 根节点
* @param pre IndexNode[], 数组容量为1,用于在递归中保存中序前一节点
*
*/
private static void creatMidIndexTree(IndexNode root, IndexNode[] pre){
if (root == null){
return;
}
creatMidIndexTree(root.left, pre);
if (root.left == null){
root.left = pre[0];
root.flagLeft = true;
}
if (pre[0] != null && pre[0].right == null){
pre[0].right = root;
pre[0].flagRight = true;
}
pre[0] = root;
creatMidIndexTree(root.right, pre);
}
/**
* 根据中序和前序建立二叉树
* @param pre String 前序序列
* @param mid String 中序序列
* @return 根节点
*/
public static IndexNode creatTreeByPreAndMid(String pre, String mid){
IndexNode indexNode = null;
if(pre.length() > 0){
indexNode = new IndexNode();
indexNode.value = pre.charAt(0);
String left = mid.substring(0, mid.indexOf(indexNode.value));
int i = 1;
while (i < pre.length()){
if (left.contains(pre.charAt(i) + "")){
i++;
}else {
break;
}
}
String preLeft = pre.substring(1,i);
String preRight = pre.substring(i,pre.length());
String right = mid.substring(mid.indexOf(indexNode.value)+1, mid.length());
indexNode.left = creatTreeByPreAndMid(preLeft,left);
indexNode.right = creatTreeByPreAndMid(preRight,right);
}
return indexNode;
}
/**
* 根据后序和中序建立二叉树
* @param mid
* @param suf
* @return
*/
public static IndexNode createTreebyMidAndSuf(String mid, String suf){
IndexNode root = null;
if (suf.length() > 0){
root = new IndexNode();
root.value = suf.charAt(suf.length()-1);
String midLeft = mid.substring(0,mid.indexOf(suf.charAt(suf.length()-1)));
String midRight = mid.substring(mid.indexOf(suf.charAt(suf.length()-1))+1, mid.length());
String sufLeft = suf.substring(0,midLeft.length());
String sufRight = suf.substring(midLeft.length(),suf.length()-1);
root.left = createTreebyMidAndSuf(midLeft,sufLeft);
root.right = createTreebyMidAndSuf(midRight,sufRight);
}
return root;
}
/**
* 中序非递归遍历
* @param root
*/
public static void printMidNonStack(IndexNode root){
IndexNode[] stack = new IndexNode[20];
int top = -1;
IndexNode tmp = root;
while (tmp != null || top != -1){
while (tmp != null){
stack[++top] = tmp;
tmp = tmp.left;
}
if (top != -1){
tmp = stack[top--];
System.out.printf(tmp.value + " ");
}
tmp = tmp.right;
}
System.out.println();
}
public static void printMid(IndexNode root){
if (root != null){
printMid(root.left);
System.out.printf(root.value + " ");
printMid(root.right);
}
}
/**
* 前序非递归遍历
* @param root
*/
public static void printPreNonStack(IndexNode root){
IndexNode tmp = root;
IndexNode[] stack = new IndexNode[20];
int top = -1;
while (top != -1 || tmp != null){
if (tmp == null){
tmp = stack[top--];
}else {
System.out.printf(tmp.value + " ");
if (tmp.right != null){
stack[++top] = tmp.right;
}
tmp = tmp.left;
}
}
System.out.println();
}
public static void printPre(IndexNode root){
if (root != null){
System.out.printf(root.value + " ");
printPre(root.left);
printPre(root.right);
}
}
public static void printSuf(IndexNode root){
if (root != null){
printSuf(root.left);
printSuf(root.right);
System.out.printf(root.value + " ");
}
}
/**
* 后序非递归遍历
* @param root
*/
public static void printSufNonStack(IndexNode root){
class FlagIndexNode{
IndexNode indexNode;
boolean right;
}
FlagIndexNode[] stack = new FlagIndexNode[20];
int top = -1;
IndexNode tmp = root;
while (top != -1 || tmp != null){
while (tmp != null){
FlagIndexNode flagIndexNode = new FlagIndexNode();
flagIndexNode.indexNode = tmp;
stack[++top] = flagIndexNode;
tmp = tmp.left;
}
if (stack[top].right == false){
stack[top].right = true;
tmp = stack[top].indexNode.right;
}else {
System.out.printf(stack[top--].indexNode.value + " ");
}
}
System.out.println();
}
/**
* 使用中序索引二叉树来实现前序遍历。不用栈。
* 方法要点在于找出节点的前序后继。节点的前序后继就是节点中序后继标志不为TRUE的第一个节点的右子树。
* 画一个树图示意一下,就明白了。
* @param root
*/
public static void printPreOrderUseIndex(IndexNode root){
IndexNode tmp = root;
while (tmp != null){
while (tmp.flagLeft != true) {
System.out.printf(tmp.value + " ");
tmp = tmp.left;
}
System.out.printf(tmp.value + " ");
if (tmp.flagRight != true){
tmp = tmp.right;
}else {
while (tmp.flagRight == true && tmp.right != null){
tmp = tmp.right;
}
tmp = tmp.right;
}
}
System.out.println();
}
/**
* Use middle indexed binary tree to print middle traversal order.
* @param root the root of tree
*/
public static void printMidOrderUseIndex(IndexNode root){
IndexNode tmp = root;
while (tmp != null){
while (tmp.flagLeft != true){
tmp = tmp.left;
}
System.out.printf(tmp.value + " ");
while (tmp.flagRight == true && tmp.right != null){
tmp = tmp.right;
System.out.printf(tmp.value + " ");
}
tmp = tmp.right;
}
}
public static void main(String[] args){
String pre = "ABDGCEF";
String mid = "BGDACEF";
String suf = "GDBFECA";
IndexNode root = creatTreeByPreAndMid(pre,mid);
IndexNode root2 = createTreebyMidAndSuf(mid,suf);
printMid(root);
System.out.println();
printMidNonStack(root);
printMid(root2);
System.out.println();
printMidNonStack(root2);
System.out.println();
printPre(root);
System.out.println();
printPreNonStack(root2);
printPre(root2);
System.out.println();
System.out.println();
printSuf(root);
System.out.println();
printSufNonStack(root);
System.out.println();
System.out.println();
printPreNonStack(root);
printMidNonStack(root);
creatMidIndexTree(root);
printPreOrderUseIndex(root);
printMidOrderUseIndex(root);
}
}