?
C++线索二叉树的相关操作
#pragma once
//5.21 --212--线索二叉树的类定义
template<class T>
struct ThreadNode
{
int ltag, rtag;
ThreadNode<T>* leftChild, * righChild;
T data;
ThreadNode(const T item) :data(item), leftChild(nullptr), righChild(nullptr),
ltag(0), rtag(0) {}
};
template<class T>
class ThreadTree {
protected:
ThreadNode<T>* root;
void createInThread(ThreadNode<T>* current, ThreadNode<T>*& pre);
//中序遍历建立二叉树
ThreadNode<T>* parent(ThreadNode<T>* t);
//寻找结点t的父结点
public:
ThreadTree() :root(nullptr) {}
void createInThread();
ThreadNode<T>* First(ThreadNode<T>* current);//寻找第一个结点
ThreadNode<T>* Last(ThreadNode<T>* current);//寻找最后一个结点
ThreadNode<T>* Next(ThreadNode<T>* current);//寻找 后继结点
ThreadNode<T>* Prior(ThreadNode<T>* current);//寻找 前驱结点
void InOrder(void (*visit)(ThreadNode<T>* p));
void PreOrder(void (*visit)(ThreadNode<T>* p));
void PostOrder(void (*visit)(ThreadNode<T>* p));
void InsertRight(ThreadNode<T>* current);//插入一个结点
//........
};
//5.22 --213-中序二叉树 成员函数实现
//求序列的 第一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::First(ThreadNode<T>* current) {
//以*current為根的 第一个结点
ThreadNode<T>* p = current;
while (p->ltag == 0) {//只要有 左子女,就一直向左
p = p->leftChild;//最左下结点,(不一定是叶子结点)
}
//最左边的就是 中序遍历的第一个结点。
return p;
};
//求后继
template<class T>
ThreadNode<T>* ThreadTree<T>::Next(ThreadNode<T>* current) {
ThreadNode<T>* p = current->righChild;
if (current->rtag == 0) {//该点 A有 右子女,
return First(p);//求该点的右子女为根的子树的 第一个结点就是E
}else{//否则就是 rtag==1.存放的就是后继结点。
return p;//返回后继结点
}
};
//序列的最后一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::Last(ThreadNode<T>* current) {
ThreadNode<T>* p = current;
while (p->rtag == 0) {//只要有右子女,就一直向右。
p = p->righChild;
}
return p;
};
//求 前驱结点。
template<class T>
ThreadNode<T>* ThreadTree<T>::Prior(ThreadNode<T>* current) {
ThreadNode<T>* p = current->leftChild;//先记录改点的左子女,
if (current->ltag == 0) {//如果 有左 子女,比如A,
return Last(p);//求以 该点 左子女为根的子树(比如B) 的最右一个结点。
}
else {//否则就是rtag==1,存放的就是 前驱结点
return p;
}
};
//5.23进行中序遍历
template<class T>
void ThreadTree<T>::InOrder(void (*visit)(ThreadNode<T>* p)) {
ThreadNode<T>* p;
for (p = First(root);p != nullptr;p = Next(p)) {
visit(p);
}
};
//5.24利用中序遍历 对二叉树进行中序线索化
template<class T>
void ThreadTree<T>::createInThread() {
ThreadNode<T>* pre = nullptr;//前驱结点指针
if (root != nullptr) {//非空二叉树,进行线索化
createInThread(root, pre);//中序遍历 线索化
pre->righChild = nullptr;//后 处理中序最后一个结点指针。(最后一个是特殊的)
pre->rtag = 1;
}
};
template<class T>
void ThreadTree<T>::createInThread(ThreadNode<T>* current,
ThreadNode<T>*& pre) {
//通过中序遍历,对二叉树进行线索化
if (current == nullptr) {
return;
}
createInThread(current->leftChild, pre);//递归,左子树线索化
if (current->leftChild == nullptr) {//建立当前结点的前驱
current->leftChild = pre;
current->ltag = 1;
}
if (pre != nullptr && pre->righChild == nullptr) {
pre->righChild = current;//建立当前结点的后继
pre->rtag = 1;
}
pre = current;
createInThread(current->righChild, pre);//递归,右子树线索化
};
//5.25 在中序遍历二叉树上实现前序遍历算法
template<class T>
void ThreadTree<T>::PreOrder(void (*visit)(ThreadNode<T>* current)) {
ThreadNode<T>* current = root;
while (current != null) {
visit(current);//访问根结点
if (current->ltag == 0) {//如果有 左子女.即为 后继
current = current->leftChild;
}
else if (current->rtag == 0) {//否则 有 右子女,即为后继
current = current->righChild;
}
else {
//沿着后继继续检测
while (current != nullptr && current->rtag == 1) {
current = current->righChild;//直到有 右子女的结点
}
if (current != nullptr) {//右 子女 即为后继
current = current->righChild;
}
}
}
};
//5.26 在中序遍历二叉树上实现后序遍历算法
template<class T>
void ThreadTree<T>::PostOrder(void (*visit)(ThreadNode<T>* current)) {
ThreadNode<T>* current = root;
//寻找最后一个结点
while (current->ltag == 0 || current->rtag == 0) {
if (current->ltag == 0) {
current = current->leftChild;
}
else if (current->rtag == 0) {
current = current->righChild;
}
}
visit(current);//访问第一个结点
ThreadNode<T>* p;
while ((p = parent(t)) != nullptr) {
if (p->righChild == current || p->rtag == 1) {//*current是*p的后序后继
current = p;
}else{//否则,current 移动到 p的右子树
current = p->righChild;
while (current->ltag == 0 || current->rtag == 0) {
if (current->ltag == 0) {
current = current->leftChild;
}
else if (current->rtag == 0) {
current = current->righChild;
}
}
}
visit(current);
}
};
//5.27 求父结点
template<class T>
ThreadNode<T>* ThreadTree<T>::parent(ThreadNode<T>* t) {
ThreadNode<T>* p;
if (t == root)return nullptr;//根结点 无父结点
for (p = t;p->ltag == 0;p = p->leftChild);//求 t为根子树第一个结点。
if (p->leftChild != nullptr)
for (p = p->leftChild;
p != nullptr && p->leftChild != t && p->righChild != t;
p = p->righChild);
if (p == nullptr || p->leftChild == nullptr) {
for (p = t;p->rtag == 0;p = p->righChild);
for (p = p->righChild;p != nullptr && p->leftChild != t && p->righChild != t;
p = p->leftChild);
}
return p;
};
//5.28
template<class T>
void ThreadTree<T>::InsertRight(ThreadNode<T>* s, ThreadNode<T>* r) {
//将新结点*r当做*s的 右子女插入
r->rightChild = s->rightChild;//s的右子女或者后继 线索 传给r
r->rtag = s->rtag;//后继线索 标志一同传送
t->leftChild = s;
r->ltag = 1;
s->rightChild = r;//r成为s右子女
s->rtag = 0;
if (r->rtag == 0) {//s原来有右子女
ThreadNode<T>* temp;
temp = First(r->rightChild);//在s原来的柚子树找中序遍历 第一个点
temp->leftChild = r;//建立指向r的前驱线索
}
};
//在*s的左子女处插入 *p
template<class T>
void ThreadTree<T>::InsertRight(ThreadNode<T>* s, ThreadNode<T>* p) {
if (s != nullptr && p != nullptr) {
if (s->rtag) {//首先判断 是否有子女。 无!
p->leftChild = s->leftChild;//s的左线索 复制给 p
p->rtag = 1; //p无右子女
}
else {//有左子女
p->leftChild = s->leftChild;
p->ltag = 0;//插入
p->rightChild = s;//p的后继 是s
p->rtag = 1;//p无右子女
ThreadNode<T>* temp = p->leftChild;
while (!temp->rtag) {//找p左子树 中序遍历中的最后一个点。
temp = temp->rightChild;
}
temp->rightChild = p;//该点的后继 是 p
}
s->leftChild = p;
s->ltag = 0;
}
};
?
|