🌙线索化二叉树的原因
普通的二叉树是非线性的,只能知道二叉树的去向,也就是它的左子树和右子树,而无法知道它的来处,也就是不知道它的上一个结点是什么,所以我们需要将这个二叉树线索化。
线索化的目的就是能够知道某个点的前驱点和后继点。
之前我们只知道某一个点能够去向哪里,而不知道来自哪里,通过线索化之后我们就能知道了。
🌙中序线索化二叉树
线索化其实是一个遍历的过程,通过这个过程把每个点联系起来,从而线性化,就像栈和队列一样,可以访问前驱和后继。
那么遍历的方式总的有三种,为什么要选择中序呢,这我就不讲了有点复杂,但不需要掌握,只要知道中序遍历是最简单的方式就行了。
中序线索化的原理
没有左子树和右子树的情况:
1、
2、
3、
4、
5、
6、
后面的使用递归就可以完成了。
🌙中序线索化的代码实现
完成一下代码实现,很简单的代码:
void Cordation_tree(struct binary_tree* tree)
{
if (tree)//判断树是否为空
{
Cordation_tree(tree->lsubtree);//1、递归完成左子树线索化
if (!tree->lsubtree)//2、处理中间部分,
{
//对应第4步
//判断当前结点左子树是否为空
tree->lflog = 1;//记录指向
tree->lsubtree = pre;//左子树指向前驱点
}
else
tree->lflog = 0;
if (pre)//判断是否为空
{
if (!pre->rsubtree)//pre是否为空,对应上面第3和第5步
{
pre->rflog = 1;
pre->rsubtree = tree;
}
else
pre->rflog = 0;
}
pre = tree;//更新pre的位置
Cordation_tree(tree->rsubtree);//3、递归完成右子树的线索化
}
}
🌙线索遍历二叉树
线索化之后就不能使用之前的遍历方法了,因为连接方法和之前不一样了。所以我们想要重新创建一个遍历方法。
void Thread_traversal(struct binary_tree* tree)
{
while (tree)
{
while (tree->lflog == 0)//先遍历左子树找到第一个结点d
tree = tree->lsubtree;
cout << tree->ch << " ";
while ((tree->rflog == 1) && (tree->rsubtree))//如果有后继点就一直循环打印
{
tree = tree->rsubtree;//更新tree的位置
cout << tree->ch << " ";
}
tree = tree->rsubtree;//如果没有后继点也更新tree的位置到右子树
}
}
🌙找到前驱点和后继点
先查找是否有你要找的结点,然后返回结点
struct binary_tree* search_tree(struct binary_tree* tree, char ch)
{
while (tree)
{
while (tree->lflog == 0)//先遍历左子树找到第一个结点
tree = tree->lsubtree;
if (tree->ch == ch)
return tree;
while (tree->rflog == 1 && tree->rsubtree)//如果有后继点就一直循环打印
{
tree = tree->rsubtree;//更新tree的位置
if (tree->ch == ch)
return tree;
}
tree = tree->rsubtree;//如果没有后继点也更新tree的位置到右子树
}
}
根据返回的这个结点找前驱点和后继点
//找前驱点
struct binary_tree* Precursor_point(struct binary_tree* tree)
{
if (tree->lflog == 1)//如果有前驱点就返回
return tree->lsubtree;
else
{
tree = tree->lsubtree;//返回左子树的最右的结点
while (tree->rflog == 0)
tree = tree->rsubtree;
return tree;
}
}
//找后继点
struct binary_tree* Successor_point(struct binary_tree* tree)
{
if (tree->rflog == 1)//如果有后继点就返回
return tree->rsubtree;
else
{
tree = tree->rsubtree;//返回右子树的最左的结点
while (tree->lflog == 0)
{
tree = tree->lsubtree;
}
return tree;
}
}
🌙总代码
binary_tree.h
#pragma once
#ifndef __BINARY_THREAD_TREE_H__
#define __BINARY_THREAD_TREE_H__
#include<iostream>
struct binary_tree
{
char ch;//数据
struct binary_tree* lsubtree, * rsubtree;//创建左子树和右子树
int lflog, rflog;
};
struct binary_tree* found_tree(struct binary_tree*);//补空法创建二叉树
void Cordation_tree(struct binary_tree*);//线索化二叉树
void Thread_traversal(struct binary_tree*);//线索遍历二叉树
struct binary_tree* search_tree(struct binary_tree* , char);
struct binary_tree* Precursor_point(struct binary_tree*);//找前驱点
struct binary_tree* Successor_point(struct binary_tree* );//找后继点
#endif
binary_tree.cpp
#include"binary_thread_tree.h"
struct binary_tree* pre;
using std::cin;
using std::cout;
struct binary_tree* found_tree(struct binary_tree* tree)
{
tree = new struct binary_tree;
char ch;
cin >> ch;//输入一串已经提前先序遍历好的二叉树字符串,但要将空的结点换成#,但是它只读取第一个字符,其余的都存在缓冲区里面,每递归一次读取一次
if (ch == '#')//如果读取到#字符就将这个结点设为空
tree = nullptr;
else
{
tree = new struct binary_tree;//开辟一个结构体
tree->ch = ch;//给结点数据赋值
tree->lsubtree = found_tree(tree->lsubtree);//递归调用这个函数创建左子树
tree->rsubtree = found_tree(tree->rsubtree);//递归调用这个函数创建右子树
}
return tree;
}
void Cordation_tree(struct binary_tree* tree)
{
if (tree)//判断树是否为空
{
Cordation_tree(tree->lsubtree);//1、递归完成左子树线索化
if (!tree->lsubtree)//2、处理中间部分,
{
//对应第4步
//判断当前结点左子树是否为空
tree->lflog = 1;//记录指向
tree->lsubtree = pre;//左子树指向前驱点
}
else
tree->lflog = 0;
if (pre)//判断是否为空
{
if (!pre->rsubtree)//pre是否为空,对应上面第3和第5步
{
pre->rflog = 1;
pre->rsubtree = tree;
}
else
pre->rflog = 0;
}
pre = tree;//更新pre的位置
Cordation_tree(tree->rsubtree);//3、递归完成右子树的线索化
}
}
void Thread_traversal(struct binary_tree* tree)
{
while (tree)
{
while (tree->lflog == 0)//先遍历左子树找到第一个结点d
tree = tree->lsubtree;
cout << tree->ch << " ";
while ((tree->rflog == 1) && (tree->rsubtree))//如果有后继点就一直循环打印
{
tree = tree->rsubtree;//更新tree的位置
cout << tree->ch << " ";
}
tree = tree->rsubtree;//如果没有后继点也更新tree的位置到右子树
}
}
struct binary_tree* search_tree(struct binary_tree* tree, char ch)
{
while (tree)
{
while (tree->lflog == 0)//先遍历左子树找到第一个结点
tree = tree->lsubtree;
if (tree->ch == ch)
return tree;
while (tree->rflog == 1 && tree->rsubtree)//如果有后继点就一直循环打印
{
tree = tree->rsubtree;//更新tree的位置
if (tree->ch == ch)
return tree;
}
tree = tree->rsubtree;//如果没有后继点也更新tree的位置到右子树
}
}
struct binary_tree* Precursor_point(struct binary_tree* tree)
{
if (tree->lflog == 1)//如果有前驱点就返回
return tree->lsubtree;
else
{
tree = tree->lsubtree;//返回左子树的最右的结点
while (tree->rflog == 0)
tree = tree->rsubtree;
return tree;
}
}
struct binary_tree* Successor_point(struct binary_tree* tree)
{
if (tree->rflog == 1)//如果有后继点就返回
return tree->rsubtree;
else
{
tree = tree->rsubtree;//返回右子树的最左的结点
while (tree->lflog == 0)
{
tree = tree->lsubtree;
}
return tree;
}
}
main.cpp
#include"binary_thread_tree.h"
using namespace std;
int main()
{
struct binary_tree* maker = nullptr;//创建一个根结点
struct binary_tree* node, *P, *S;
cout << "请输入带有补孔('#')的先序遍历出来的数据:";
maker = found_tree(maker);//用补空法创建二叉树
Cordation_tree(maker);//线索化二叉树
Thread_traversal(maker);//线索化遍历
char ch;
cin >> ch;
cin.sync();//清空缓冲区
node = search_tree(maker, ch);//找到你要找的结点
cout << ch << "的前驱点是:";
P = Precursor_point(node);//前驱点
cout << P->ch << endl;
cout << ch << "的后继点是:";
S = Successor_point(node);//后继点
cout << S->ch << endl;
return 0;
}