线索二叉树作为二叉树的进阶,不仅仅是面试高频,Linux 内核中不少地方使用到这个数据结构(比如:文件管理系统的实现)。
1、什么是线索二叉树
线索化的二叉树就是:在原有的二叉树基础上有些改动,将没有孩子结点的链域声明为线,左孩子指向前驱,右孩子指向后继节点。
有孩子结点的为链,表示指向原先的左右孩子。
线索二叉树的基本存储结构如下:
2、中序二叉树的图形
线索二叉树无需遍历,可以很方便的得到其任一结点的前驱、后继。
3、中序线索二叉树的建立
必须先建立好二叉树(根据先序序列),在其基础上创建中序线索二叉树;
核心程序:最好画图跟踪一下,才能弄得清楚;
注意:最后一个结点在函数结束时为LINK,没有更改过来!
b、看看根是否为父结点;
c、就是图中E、D这种情况,其父----->后继结点;
d、就是图中H、G这种情况,其父----->前驱结点;
以上就是针对存在线的求法;
针对没有线的求法: (一)、例如求D:看的是其右的最后一个,因为线,走了一圈,就是确定B是其父;
(二)、找当前结点的左树的第一个,在返回其左孩子(此时这个线就是父节点)。
5、完整代码、调试程序,测试结果
(1)、代码
推荐阅读:
从零开始学习数据结构-->入门篇
从零开始学习数据结构-->链表
从零开始学习数据结构-->线性表
从零开始学习数据结构-->栈
从零开始学习数据结构-->队列
从零开始学习数据结构-->矩阵+串
从零开始学习数据结构-->哈希表
从零开始学习数据结构-->散列桶
从零开始学习数据结构-->二叉树
![e6edb22cf4b0f069e8039f2dc10bcd67.png](https://i-blog.csdnimg.cn/blog_migrate/ceabdbeab797b949fc71505276f80c9a.png)
![2dae73e174a473324b1ff19b8fff1ac1.png](https://i-blog.csdnimg.cn/blog_migrate/c45efb51f15c14f1c21e7b91ff46043e.png)
1template<typename Type>
2void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){ //创建中序线索二叉树 3 if(t == NULL){ //pre必须引用传递,的保证及时的更改!!! 4 return; //空树直接返回 5 } 6 createInThread(t->leftChild, pre); //pre一直为空,一直在往左走; 7 if(t->leftChild == NULL){ 8 t->ltag = THREAD; //将左孩子设置为线 9 t->leftChild = pre; //因为是第一个,无前驱,所以置空10 }11 if(pre != NULL && pre->rightChild == NULL){ 12 pre->rtag = THREAD; //将右孩子设置为线;13 pre->rightChild = t; //此时指向后继结点,t已经回到了上一层14 }15 pre = t; //将当前结点给pre;16 createInThread(t->rightChild, pre); //往右边递归17}
完整创建程序:
1#ifndef _THREAD_BIN_TREE_H_
2#define _THREAD_BIN_TREE_H_
3
4#include
5using namespace std;
6
7typedef enum{LINK, THREAD}TAG; //定义枚举标记链和线
8
9template<typename Type>
10class BinTree;
11
12template<typename Type> //结点类,多了两个标记链和线的;
13class BinTreeNode{
14 friend class BinTree;
15public:
16 BinTreeNode() : data(Type()), leftChild(NULL), rightChild(NULL), ltag(LINK), rtag(LINK){}
17 BinTreeNode(Type value, BinTreeNode *left = NULL, BinTreeNode *right = NULL) :18 data(value), leftChild(left), rightChild(right), ltag(LINK), rtag(LINK){}19 ~BinTreeNode(){}20private:21 Type data;22 BinTreeNode *leftChild;23 BinTreeNode *rightChild;24 TAG ltag; //左标记25 TAG rtag; //右标记26};27///28template<typename Type>29class BinTree{30public:31 BinTree() : root(NULL){}32 BinTree(Type ref) : root(NULL), refval(ref){}33 BinTree(const BinTree &t){}34 ~BinTree(){35 }36public:37 void createBinTree(const char *str); //的先建立二叉树38 void createInThread();39protected :40 void createBinTree(const char *&str, BinTreeNode *&t);41 void createInThread(BinTreeNode *t, BinTreeNode *&pre);42template<typename Type>43void BinTree::createBinTree(const char *str){44 createBinTree(str, root);45}46template<typename Type>47void BinTree::createInThread(){ //在二叉树已经建立起来,创建中序线索二叉树;48 BinTreeNode *pre = NULL; //得弄一个前驱节点,做为参数传递过去49 createInThread(root, pre); //真正的创建中序线索二叉树50 pre->rtag = THREAD; //最后一个应该为线51}52template<typename Type>53void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){ //创建中序线索二叉树54 if(t == NULL){55 return;56 }57 createInThread(t->leftChild, pre);58 if(t->leftChild == NULL){59 t->ltag = THREAD;60 t->leftChild = pre;61 }62 if(pre != NULL && pre->rightChild == NULL){63 pre->rtag = THREAD;64 pre->rightChild = t;65 }66 pre = t;67 createInThread(t->rightChild, pre);68}69template<typename Type> //创建二叉树70void BinTree::createBinTree(const char *&str, BinTreeNode *&t){71 if(*str == refval){72 t = NULL;73 }else{74 t = new BinTreeNode(*str);75 createBinTree(++str, t->leftChild);76 createBinTree(++str, t->rightChild);77 }78}7980#endif
4、其它方法的实现
中序线索二叉树
1public:
2 BinTreeNode* first()const; //查找中序的第一个结点3 BinTreeNode* last()const; //查找中序的最后一个结点4 BinTreeNode* prev(BinTreeNode *cur)const; //查找当前结点的前驱5 BinTreeNode* next(BinTreeNode *cur)const; //查找当前结点的后继6 BinTreeNode* parent(BinTreeNode *cur)const; //查找当前结点的父结点7 void inOrder()const; //中序遍历线索二叉树8 BinTreeNode* find(const Type &key); //查找某一结点
关于还有些方法: 求树高,求结点个数,这些其实跟前面写的差不多,将结束条件换为:
1if(t->ltag == THREAD) {
2 return 0;
3}
(1)、查找第一个结点
1template<typename Type>
2BinTreeNode* BinTree::first(BinTreeNode *t)const{ 3 if(t == NULL){ 4 return NULL; 5 } 6 while(t->ltag == LINK){ 7 t = t->leftChild; 8 } 9 return t;10}
(2)、查找最后一个结点
1template<typename Type>
2BinTreeNode* BinTree::last(BinTreeNode *t)const{ 3 if(t == NULL){ 4 return NULL; 5 } 6 while(t->rtag == LINK){ 7 t = t->rightChild; 8 } 910 return t;
(3)、查找当前结点的前驱
1template<typename Type>
2BinTreeNode* BinTree::prev(BinTreeNode *t, BinTreeNode *cur)const{ 3 if(t == NULL || cur == NULL){ 4 return NULL; 5 } 6 if(cur->ltag == THREAD){ 7 return cur->leftChild; 8 }else{ 9 return last(cur->leftChild); //当前结点的前驱是:左树的最后一个结点;10 }11}
(4)、查找当前结点的后继
1template<typename Type>
2BinTreeNode* BinTree::next(BinTreeNode *t, BinTreeNode *cur)const{ 3 if(t == NULL || cur == NULL){ 4 return NULL; 5 } 6 if(cur->rtag == THREAD){ 7 return cur->rightChild; 8 }else{ 9 return first(cur->rightChild); //当前结点的后继是:右树的第一个结点;10 } 11}
(5)、中序遍历线索化二叉树
1template<typename Type>
2void BinTree::inOrder(BinTreeNode *t)const{ 3 BinTreeNode *p; 4 5 if(t == NULL){ 6 return; 7 } 8 for(p = first(t); p != NULL; p = next(t, p)){ 9 cout<data<<" ";10 }11 cout<<endl;12}
(6)、查找某一结点
1template<typename Type>
2BinTreeNode* BinTree::find(BinTreeNode *t, const Type &key){ 3 if(t == NULL){ 4 return NULL; 5 } 6 if(t->data == key){ 7 return t; 8 } 910 BinTreeNode *p;11 for(p = first(t); p != NULL; p = next(t, p)){12 if(p->data == key){13 return p;14 }15 }16 return NULL;17}
(7) 、查找当前结点的父结点,分析如下:
a、为空,或当前为根结点,其父结点----->NULL;
b、看看根是否为父结点;
c、就是图中E、D这种情况,其父----->后继结点;
d、就是图中H、G这种情况,其父----->前驱结点;
以上就是针对存在线的求法;
针对没有线的求法: (一)、例如求D:看的是其右的最后一个,因为线,走了一圈,就是确定B是其父;
(二)、找当前结点的左树的第一个,在返回其左孩子(此时这个线就是父节点)。
1template<typename Type>
2BinTreeNode* BinTree::parent(BinTreeNode *t, BinTreeNode *cur)const{ 3 if(t == NULL || cur == NULL || cur == t){ 4 return NULL; //父为空 5 } 6 if(t->ltag == LINK && t->leftChild == cur){ //父为根节点 7 return t; 8 } 9 if(t->rtag == LINK && t->rightChild == cur){10 return t;11 } 1213 if(cur->rtag == THREAD && cur->rightChild->leftChild == cur){ //线的找14 return cur->rightChild;15 }16 if(cur->ltag == THREAD && cur->leftChild->rightChild == cur){ //线的找17 return cur->leftChild;18 }1920 BinTreeNode *p = last(cur->rightChild); //往右找最后一个,21 p = p->rightChild;22 if(p != NULL && p->leftChild->rightChild == cur){23 return p->leftChild;24 }2526 p = first(cur->leftChild); //换换思路,往左找第一个。27 return p->leftChild;28}
![f45792b83e3bd2f866d17918a86af8c3.png](https://i-blog.csdnimg.cn/blog_migrate/2d331dc034904003fab135acbfe70b4b.png)
1#ifndef _THREAD_BIN_TREE_H_
2#define _THREAD_BIN_TREE_H_
3
4#include
5using namespace std;
6
7typedef enum{LINK, THREAD}TAG;
8
9template<typename Type>
10class BinTree;
11
12template<typename Type>
13class BinTreeNode{
14 friend class BinTree;
15public:
16 BinTreeNode() : data(Type()), leftChild(NULL), rightChild(NULL), ltag(LINK), rtag(LINK){}
17 BinTreeNode(Type value, BinTreeNode *left = NULL, BinTreeNode *right = NULL) : 18 data(value), leftChild(left), rightChild(right), ltag(LINK), rtag(LINK){} 19 ~BinTreeNode(){} 20private: 21 Type data; 22 BinTreeNode *leftChild; 23 BinTreeNode *rightChild; 24 TAG ltag; //左标记 25 TAG rtag; //右标记 26}; 27/// 28template<typename Type> 29class BinTree{ 30public: 31 BinTree() : root(NULL){} 32 BinTree(Type ref) : root(NULL), refval(ref){} 33 BinTree(const BinTree &t){} 34 ~BinTree(){ 35 } 36public: 37 void createBinTree(const char *str); 38 void createInThread(); 39public: 40 BinTreeNode* first()const; 41 BinTreeNode* last()const; 42 BinTreeNode* prev(BinTreeNode *cur)const; 43 BinTreeNode* next(BinTreeNode *cur)const; 44 BinTreeNode* parent(BinTreeNode *cur)const; 45 void inOrder()const; 46 BinTreeNode* find(const Type &key); 47protected: 48 BinTreeNode* first(BinTreeNode *t)const; 49 BinTreeNode* last(BinTreeNode *t)const; 50 BinTreeNode* prev(BinTreeNode *t, BinTreeNode *cur)const; 51 BinTreeNode* next(BinTreeNode *t, BinTreeNode *cur)const; 52 BinTreeNode* parent(BinTreeNode *t, BinTreeNode *cur)const; 53 void inOrder(BinTreeNode *t)const; 54 BinTreeNode* find(BinTreeNode *t, const Type &key); 55protected : 56 void createBinTree(const char *&str, BinTreeNode *&t); 57 void createInThread(BinTreeNode *t, BinTreeNode *&pre); 58private: 59 BinTreeNode *root; 60 Type refval; //'#' 61}; 62template<typename Type> 63void BinTree::createBinTree(const char *str){ 64 createBinTree(str, root); 65} 66template<typename Type> 67void BinTree::createInThread(){ 68 BinTreeNode *pre = NULL; 69 createInThread(root, pre); 70 pre->rtag = THREAD; //最后一个应该为线 71} 72template<typename Type> 73BinTreeNode* BinTree::first()const{ 74 return first(root); 75} 76template<typename Type> 77BinTreeNode* BinTree::last()const{ 78 return last(root); 79} 80template<typename Type> 81BinTreeNode* BinTree::prev(BinTreeNode *cur)const{ 82 return prev(root, cur); 83} 84template<typename Type> 85BinTreeNode* BinTree::next(BinTreeNode *cur)const{ 86 return next(root, cur); 87} 88template<typename Type> 89BinTreeNode* BinTree::parent(BinTreeNode *cur)const{ 90 return parent(root, cur); 91} 92template<typename Type> 93void BinTree::inOrder()const{ 94 inOrder(root); 95} 96template<typename Type> 97BinTreeNode* BinTree::find(const Type &key){ 98 return find(root, key); 99}100//101template<typename Type>102BinTreeNode* BinTree::find(BinTreeNode *t, const Type &key){103 if(t == NULL){104 return NULL;105 }106 if(t->data == key){107 return t;108 }109110 BinTreeNode *p;111 for(p = first(t); p != NULL; p = next(t, p)){112 if(p->data == key){113 return p;114 }115 }116 return NULL;117}118template<typename Type>119void BinTree::inOrder(BinTreeNode *t)const{120 BinTreeNode *p;121122 if(t == NULL){123 return;124 }125 for(p = first(t); p != NULL; p = next(t, p)){126 cout<data<<" ";127 }128 cout<<endl;129}130template<typename Type>131BinTreeNode* BinTree::parent(BinTreeNode *t, BinTreeNode *cur)const{132 if(t == NULL || cur == NULL || cur == t){133 return NULL;134 }135 if(t->ltag == LINK && t->leftChild == cur){136 return t;137 } 138 if(t->rtag == LINK && t->rightChild == cur){139 return t;140 } 141142 if(cur->rtag == THREAD && cur->rightChild->leftChild == cur){143 return cur->rightChild;144 }145 if(cur->ltag == THREAD && cur->leftChild->rightChild == cur){146 return cur->leftChild;147 }148149 BinTreeNode *p = last(cur->rightChild);150 p = p->rightChild;151 if(p != NULL && p->leftChild->rightChild == cur){152 return p->leftChild;153 }154155 p = first(cur->leftChild);156 return p->leftChild;157}158template<typename Type>159BinTreeNode* BinTree::next(BinTreeNode *t, BinTreeNode *cur)const{160 if(t == NULL || cur == NULL){161 return NULL;162 }163 if(cur->rtag == THREAD){164 return cur->rightChild;165 }else{166 return first(cur->rightChild);167 }168169}170template<typename Type>171BinTreeNode* BinTree::prev(BinTreeNode *t, BinTreeNode *cur)const{172 if(t == NULL || cur == NULL){173 return NULL;174 }175 if(cur->ltag == THREAD){176 return cur->leftChild;177 }else{178 return last(cur->leftChild);179 }180}181template<typename Type>182BinTreeNode* BinTree::last(BinTreeNode *t)const{183 if(t == NULL){184 return NULL;185 }186 while(t->rtag == LINK){187 t = t->rightChild;188 }189190 return t;191}192template<typename Type>193BinTreeNode* BinTree::first(BinTreeNode *t)const{194 if(t == NULL){195 return NULL;196 }197 while(t->ltag == LINK){198 t = t->leftChild;199 }200 return t;201}202template<typename Type>203void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){204 if(t == NULL){205 return;206 }207 createInThread(t->leftChild, pre);208 if(t->leftChild == NULL){209 t->ltag = THREAD;210 t->leftChild = pre;211 }212 if(pre != NULL && pre->rightChild == NULL){213 pre->rtag = THREAD;214 pre->rightChild = t;215 }216 pre = t;217 createInThread(t->rightChild, pre);218219}220template<typename Type>221void BinTree::createBinTree(const char *&str, BinTreeNode *&t){222 if(*str == refval){223 t = NULL;224 }else{225 t = new BinTreeNode(*str);226 createBinTree(++str, t->leftChild);227 createBinTree(++str, t->rightChild);228 }229}230231#endif
(2)、测试代码
1#include"threadBinTree.h"
2
3int main(void){
4 char *str = "ABC##DE##F##G#H##";
5 BinTree<char> bt('#');
6 bt.createBinTree(str);
7 bt.createInThread();
8
9 bt.inOrder();
10 BinTreeNode<char> *k = bt.find('A'); //直接输入字符查找,其方法find(const Type &key)中的const万万不可少
11 BinTreeNode<char> *p = bt.first(); //C
12 printf("%p\n", k); //A
13 BinTreeNode<char> *m;
14 m = bt.parent(p);
15// printf("%p\n", m); //B
16 BinTreeNode<char> *n;
17 n = bt.parent(m);
18 printf("%p\n", n); //A
19 return 0;
20}
(3)、测试结果
![1303d44d03d8d7b24cb48b0baea77a7d.png](https://i-blog.csdnimg.cn/blog_migrate/de4be49096f92ca0c557a619aa89a805.png)
从零开始学习数据结构-->二叉树方法实现
认真的人 自带光芒