• 数据结构之二叉树篇卷四 -- 二叉树线索化(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("	");
    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

      

  • 相关阅读:
    关于linux下如何使用svn 客户端
    vscode 如何格式化vue(template)html代码 , 保持标签属性不换行
    echarts的一些基础笔记
    Stompjs websocket vue
    GLSL反转矩阵inverse
    【入门向】使用 MetaHook Plus 绘制 HUD
    取文件MD5 WINAPI
    BAD APPLE C++控制台程序
    查看struct或class的内存布局
    让游戏以高性能GPU(独立显卡)运行
  • 原文地址:https://www.cnblogs.com/sheepcore/p/11604949.html
Copyright © 2020-2023  润新知