数据结构之二叉树篇卷四 -- 二叉树线索化(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 }
原文地址:https://www.cnblogs.com/sheepcore/p/11604949.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 在linux下玩转带有超时时间的connect函数
- Linux/CentOS服务器安全配置通用指南
- 详解centos7中配置keepalived日志为别的路径
- jointplot快速探究两组变量的分布及关系
- linux中alarm函数的实例讲解
- 如何给Linux虚拟机连上WiFi详解
- Linux系统查看CPU、机器型号、内存等信息
- 实战基本的Linux sed命令示例代码
- 在Linux中如何查看可用的网络接口详解
- Linux程序运行时加载动态库失败的解决方法
- Linux/CentOS系统同步网络时间的2种方法详解
- Linux 常用命令之Linux more命令使用方法
- Ubuntu下VIM配置成C++开发编辑器
- Ubuntu环境下使用G++编译CPP文件
- Linux下Tomcat的几种运行方式讲解