线索二叉树的实现:
先序二叉树其实是将二叉树线性化,使得每个节点在不同的遍历方式序列中都能找到自己的直接前驱和直接后继, 在需要高频度查找前驱后继的情况下,线索化二叉树是个好的选择。
1> 先序创建二叉树
2> 先序线索化二叉树
3> 遍历先序线索二叉树
4> 中序线索化二叉树
5> 遍历中序线索二叉树
6> 后序线索化二叉树
7> 遍历后序线索二叉树
8> 在线索二叉树中查找指定节点的父节点
9> 销毁线索二叉树
10> 为二叉树添加头结点并线索化对应类型的二叉树
11> 恢复线索二叉树到二叉树
#include <iostream>
typedef char DataType;
typedef enum{Link, Thread} PointerTag;
typedef enum{OK, ERROR, FAILED} STATUS;
typedef enum{PreOrder, InOrder, PostOrder}ThrType;
typedef struct ThreadBinaryNode
{
DataType data;
PointerTag lTag;
PointerTag rTag;
ThreadBinaryNode* lTree;
ThreadBinaryNode* rTree;
}ThrBinNode, *ThrBinTree;
// 先序创建二叉树
ThrBinTree PreCreateBinaryTree()
{
DataType tmp;
std::cin >> tmp;
if (tmp == '#') return NULL;
ThrBinNode* node = (ThrBinNode*) malloc(sizeof(ThrBinNode));
if (NULL == node)
{
std::cout << "malloc memory failed for create tree" << std::endl;
exit(0);
}
node->data = tmp;
node->lTree = PreCreateBinaryTree();
node->rTree = PreCreateBinaryTree();
return node;
}
// pre 为全局节点变量,用于在每一次线索化的过程中保存前一个节点,即当前节点的直接前驱
ThrBinTree pre;
// 先序线索化二叉树
void PreThreading(ThrBinTree tree)
{
if (NULL == tree) return;
if (tree->lTree) tree->lTag = Link; // 线索化的过程中更改tag属性,也可以放在创建过程中更改
if (tree->rTree) tree->rTag = Link;
if (NULL == tree->lTree) // 当前节点的直接前驱
{
tree->lTag = Thread;
tree->lTree = pre;
}
if (NULL != pre && pre->rTree == NULL)
{
pre->rTag = Thread;
pre->rTree = tree;
}
pre = tree;
if (tree->lTag == Link) PreThreading(tree->lTree);
if (tree->rTag == Link) PreThreading(tree->rTree);
}
// 遍历先序线索二叉树
void PreTraverse(ThrBinTree tree)
{
if (NULL == tree) return;
ThrBinTree ptr = tree->lTree;
while (ptr != tree)
{
while (true) // 遇到第一个点都是根节点 遇到就打印
{
std::cout << ptr->data << " ";
if (ptr->lTag != Link)
break;
ptr = ptr->lTree;
}
while (ptr->rTag == Thread && ptr->rTree != tree)
{
ptr = ptr->rTree;
std::cout << ptr->data << " ";
}
if (ptr->lTag == Link) ptr = ptr->lTree;
else ptr = ptr->rTree;
}
}
// --------------------------------------------------------
// 中序线索化二叉树
void InThreading(ThrBinTree tree)
{
if (NULL == tree) return;
InThreading(tree->lTree); // 左子树线索化
if (tree->lTree) tree->lTag = Link;
if (tree->rTree) tree->rTag = Link;
if (NULL == tree->lTree) // 前驱线索化
{
tree->lTag = Thread;
tree->lTree = pre;
}
if(pre != NULL && pre->rTree == NULL) // 后继线索化
{
pre->rTag = Thread;
pre->rTree = tree;
}
pre = tree;
InThreading(tree->rTree); // 又子树线索化
}
// 遍历中序线索二叉树
void InTraverse(ThrBinTree tree)
{
ThrBinNode* ptr = tree->lTree; // 从根节点开始进行
while(ptr != tree)
{
while(ptr->lTag == Link) ptr = ptr->lTree; // 找到中序序列第一个节点
std::cout << ptr->data << " ";
while(ptr->rTag == Thread && ptr->rTree != tree) // 打印后继节点
{
ptr = ptr->rTree;
std::cout << ptr->data << " ";
}
ptr = ptr->rTree; // 遍历右子树
}
}
// ------------------------------------------------------------------
// 后序线索化二叉树
void PostTreading(ThrBinTree tree)
{
if (tree == NULL) return;
PostTreading(tree->lTree); // 线索化左子树
PostTreading(tree->rTree); // 线索化右子树
if (tree->lTree) tree->lTag = Link;
if (tree->lTree) tree->rTag = Link;
if (NULL == tree->lTree)
{
tree->lTag = Thread;
tree->lTree = pre;
}
if (NULL != pre && NULL == pre->rTree)
{
pre->rTag = Thread;
pre->rTree = tree;
}
pre = tree;
}
// 查找指定节点p的父节点
ThrBinNode* fatherNode(ThrBinTree tree, ThrBinNode* p)
{
ThrBinNode* ptr = tree;
if (ptr->lTree == p) return ptr; // 根节点
ptr = ptr->lTree;
while(ptr->lTree != p && ptr->rTree != p)
{
if (Link == ptr->rTag) // 如果有有节点 遍历有节点查找
ptr = ptr->rTree;
else
ptr = ptr->lTree; // 如果没有右节点 往左边查找,左边查找要么查找左子树要么查找前驱
}
return ptr;
}
// 遍历后序线索二叉树
void PostTraverse(ThrBinTree tree)
{
ThrBinTree next;
ThrBinTree ptr = tree->lTree;
if (ptr == tree) return;
while (1) // 查找到后序序列的第一个节点
{
while( Link == ptr->lTag)
ptr = ptr->lTree;
if (ptr->rTag != Link)
break;
ptr = ptr->rTree;
}
while(ptr != tree)
{
std::cout << ptr->data << " ";
next = fatherNode(tree, ptr);
if (tree == next) ptr = tree; // 只剩一个根节点
else if (next->rTree == ptr || next->rTag == Thread) // 如果是右子树 或者只有左子树 则下一个节点即后继为next
ptr = next;
else
{
while(next->rTag == Link) // 如果有右支 则找到右支的后序第一个节点
{
next = next->rTree;
while(next->lTag == Link)
{
next = next->lTree;
}
}
ptr = next;
}
}
}
// 添加头结点并且根据类型线索化二叉树
STATUS Threading(ThrBinTree* head, ThrBinTree tree, ThrType ttype)
{
(*head) = (ThrBinNode*) malloc(sizeof(ThrBinNode));
if (NULL == (*head))
{
std::cout << "malloc memory for Threading failed~" << std::endl;
return FAILED;
}
(*head)->lTag = Link;
(*head)->rTag = Thread;
(*head)->rTree = (*head); // 头结点右指针回指
if (NULL == tree)
{
(*head)->lTag = Thread;
(*head)->lTree = (*head);
return OK;
}
pre = (*head); // init pre节点
(*head)->lTree = tree;
switch(ttype)
{
case PreOrder:
PreThreading(tree); // 先序线索化
break;
case InOrder:
InThreading(tree); // 中序线索化
break;
case PostOrder: // 后序线索化
PostTreading(tree);
if ( pre->rTree) // 后序线索化需要考虑最后一个节点是否有右子树
{
(*head)->rTree = pre;
return OK;
}
break;
default:
return ERROR;
}
(*head)->rTree = pre;
pre->rTree = (*head);
pre->rTag = Thread;
return OK;
}
// 释放线索二叉树
void DestoryThrBinTree(ThrBinTree tree)
{
if (tree->lTag == Thread && tree->rTag == Thread) // 销毁纯叶子节点
{
{
std::cout << "free Node " << tree->data << std::endl;
free(tree);
tree = NULL;
}
return;
}
if (tree->lTag == Link)
DestoryThrBinTree(tree->lTree); // 销毁左子树
if (tree->rTag == Link)
DestoryThrBinTree(tree->rTree); // 销毁右子树
{
std::cout << "free Node " << tree->data << std::endl;
free(tree); // 释放根节点
tree = NULL;
}
}
// 恢复线索二叉树到二叉树
void RecoverBinaryTree(ThrBinTree tree)
{
ThrBinTree ptr = tree;
if (ptr->lTag == Thread)
{
ptr->lTag = Link;
ptr->lTree = NULL;
}
if (ptr->rTag == Thread)
{
ptr->rTag = Link;
ptr->rTree = NULL;
}
if (ptr->lTree) RecoverBinaryTree(ptr->lTree);
if (ptr->rTree) RecoverBinaryTree(ptr->rTree);
}