数据结构之二叉树篇卷四 -- 二叉树线索化(With Java)

时间:2019-09-28
本文章向大家介绍数据结构之二叉树篇卷四 -- 二叉树线索化(With Java),主要包括数据结构之二叉树篇卷四 -- 二叉树线索化(With Java)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、线索二叉树简介

  二叉树本身是一种非线性结构,然而当你对二叉树进行遍历时,你会发现遍历结果是一个线性序列。这个序列中的节点存在前驱后继关系。因此,如何将这种前驱后继信息赋予给原本的二叉树呢?这就是二叉树的线索化过程。所以可以通过丰富原有的二叉树构建一棵可以知道结点的前驱后继的新的二叉树,我们叫它线索二叉树。

二、构建线索二叉树

2.1 定义线索二叉树节点

 1 public class ThreadNode<E> {
 2 
 3     public E data;
 4     public ThreadNode<E> lnode;
 5     public ThreadNode<E> rnode;
 6 
 7     enum tag {CHILD, THREAD};
 8     public tag ltag;
 9     public tag rtag;
10 
11     public ThreadNode(E data){
12         this.data = data;
13         ltag = tag.CHILD;
14         rtag = tag.CHILD;
15     }
16 
17     public ThreadNode(){}
18 }

   为了充分利用二叉树的空指针域,我们可以将结点线索依附在这些空指针中。这样一来,在我们访问根节点的左右节点时,我们必须要区分什么时候是线索,什么时候子女指针。因此为每个节点设置两个标志位。

2.2 建立线索二叉树

  在遍历二叉树的时候顺便进行线索化。线索化就是没遇到一个节点存在空指针域就要立即填上它的前驱(左指针空)或者后继(右指针空)。

 1     /**
 2      * 利用中序非递归遍历对二叉树进行线索化
 3      * @author sheepcore
 4      */
 5     public void createInThread(){
 6         if(root == null)
 7             return;
 8         ThreadNode<E> pre = null;
 9         ThreadNode<E> cur = root;
10         MyStack<ThreadNode<E>> stack = new MyStack<>();
11         while (cur != null || !stack.isEmpty()) {
12             while (cur != null){
13                 stack.push(cur);
14                 cur = cur.lnode;
15             }
16             if(!stack.isEmpty()){
17                 cur = stack.pop();
18                 if(cur.lnode == null) {     //当前节点的前驱作为线索
19                     cur.lnode = pre;
20                     cur.ltag = ThreadNode.tag.THREAD;
21                 }
22                 if(pre != null && pre.rnode == null){
23                     pre.rnode = cur;        //当前节点的前驱的后继节点是当前节点
24                     pre.rtag = ThreadNode.tag.THREAD;
25                 }
26                 pre = cur;
27                 if(cur.rnode != null){
28                     cur = cur.rnode;
29                 }
30                 else
31                     cur = null;
32 
33             } //if
34         } //while
35     }

2.3 遍历线索二叉树

  以中序线索二叉树的遍历为例。getFirst(root) 和 getNext(root) 分别是获取中序遍历中以 root 为根的第一个访问的节点和 root 的后继节点。这两个辅助函数在最后面的完整代码有实现。

1     public void inOrder(ThreadNode<E> root){
2         ThreadNode<E> cur;
3         for (cur = getFirst(root); cur != null; cur = getNext(cur)) {
4             visit(cur);
5         }
6     }

2.4 完整代码

  1 public class ThreadTree <E> {
  2     
  3     private ThreadNode<E> root;
  4 
  5     /**
  6      * using for construct a binary tree with its element as an integer
  7      */
  8     public ArrayList<Integer> list;
  9 
 10     public ThreadNode<E> getRoot() { return root; }
 11     
 12     public ThreadTree(){
 13         list = new ArrayList<>();
 14     }
 15 
 16     /**
 17      * build a binary tree in a preorder way recursively
 18      * @return root 
 19      * @author sheepcore
 20      */
 21     public  ThreadNode<E> generate() {
 22         if(list.isEmpty())
 23             return null;
 24         int data = list.get(0);
 25         list.remove(0);
 26         ThreadNode<E> node;
 27 
 28         if(data != -1) {
 29             node = (ThreadNode<E>) new ThreadNode<Integer>(data);
 30             node.lnode = generate();    //generate left subtree
 31             node.rnode = generate();    //generate right subtree
 32             return node;
 33         }
 34         else
 35             return null;
 36     }
 37 
 38     /**
 39      * build a binary tree in preorder
 40      * @param treeSequence  "1 2 -1 -1 3 -1 -1 "
 41      */
 42     public void preOderBuild(String treeSequence) {
 43         String[] nodes = treeSequence.split("\\s+");
 44         for (int i = 0; i < nodes.length; i++) {
 45             list.add(Integer.parseInt(nodes[i]));
 46         }
 47         root = generate();
 48     }
 49 
 50     /**
 51      * 利用中序非递归遍历对二叉树进行线索化
 52      * @author sheepcore
 53      */
 54     public void createInThread(){
 55         if(root == null)
 56             return;
 57         ThreadNode<E> pre = null;
 58         ThreadNode<E> cur = root;
 59         MyStack<ThreadNode<E>> stack = new MyStack<>();
 60         while (cur != null || !stack.isEmpty()) {
 61             while (cur != null){
 62                 stack.push(cur);
 63                 cur = cur.lnode;
 64             }
 65             if(!stack.isEmpty()){
 66                 cur = stack.pop();
 67                 if(cur.lnode == null) {     //当前节点的前驱作为线索
 68                     cur.lnode = pre;
 69                     cur.ltag = ThreadNode.tag.THREAD;
 70                 }
 71                 if(pre != null && pre.rnode == null){
 72                     pre.rnode = cur;        //当前节点的前驱的后继节点是当前节点
 73                     pre.rtag = ThreadNode.tag.THREAD;
 74                 }
 75                 pre = cur;
 76                 if(cur.rnode != null){
 77                     cur = cur.rnode;
 78                 }
 79                 else
 80                     cur = null;
 81 
 82             } //if
 83         } //while
 84     }
 85 
 86 
 87     public ThreadNode<E> getFirst(ThreadNode<E> root){
 88         ThreadNode<E> cur = root;
 89         while (cur != null && cur.ltag == ThreadNode.tag.CHILD){
 90             cur = cur.lnode;
 91         }
 92         return cur;
 93     }
 94 
 95     public ThreadNode<E> getLast(ThreadNode<E> root){
 96         ThreadNode<E> cur = root;
 97         while (cur != null && cur.rtag == ThreadNode.tag.CHILD){
 98             cur = cur.rnode;
 99         }
100         return cur;
101     }
102 
103     public ThreadNode<E> getNext(ThreadNode<E> root){
104         ThreadNode<E> cur = root;
105         if(cur.rtag == ThreadNode.tag.THREAD)
106             return cur.rnode;
107         else
108             return getFirst(cur.rnode);
109 
110     }
111 
112     public ThreadNode<E> getPrior(ThreadNode<E> root){
113         ThreadNode<E> cur = root;
114         if(cur.ltag == ThreadNode.tag.THREAD)
115             return cur.lnode;
116         else
117             return getLast(cur.lnode);
118 
119     }
120 
121     public void visit(ThreadNode<E> root){
122         if(root != null && root.data != null){
123             System.out.print(root.data);
124             System.out.print("\t");
125         }
126     }
127 
128     /**
129      * inorder traversal
130      * @param root
131      * @author sheepcore
132      */
133     public void inOrder(ThreadNode<E> root){
134         ThreadNode<E> cur;
135         for (cur = getFirst(root); cur != null; cur = getNext(cur)) {
136             visit(cur);
137         }
138     }
139 
140     public static void main(String[] args) {
141 
142         String str = "0 1 -1 3 -1 -1 2 4 -1 -1 -1";
143         ThreadTree<Integer> threadTree = new ThreadTree<>();
144         threadTree.preOderBuild(str);
145         threadTree.createInThread();
146         threadTree.inOrder(threadTree.getRoot());
147     }
148 }
View Code

  

原文地址:https://www.cnblogs.com/sheepcore/p/11604949.html