主要是利用二叉树的空指针域,若为空,使左指针指向前驱,并标记ltag为1;使右指针指向后驱,并标记rtag为1;
要注意的是构造结束后,此时pre指向最后一个结点,此时需记得pre->right = nullptr, pre->rtag = 1。否则这棵树的右子树无法遍历;
这样使得这些指针域不至于浪费,并能够加快查找结点前驱和后继的速度。
#include <iostream>
#include <string>
using namespace std;
typedef int ElementType;
typedef struct TreeNode{
ElementType val;
TreeNode* left;
TreeNode* right;
int ltag;
int rtag;
TreeNode(ElementType x):val(x), left(nullptr), right(nullptr)
, ltag(0), rtag(0){}
}*ThreadTree;
void visit(TreeNode* node)
{
cout << node->val << " ";
}
void inOrder(ThreadTree root)
{
if( root ){
inOrder(root->left);
visit(root);
inOrder(root->right);
}
}
ThreadTree BST_Insert(ThreadTree root, int n = 0)
{
cout << "Please input " << n << " value to insert BST:\n";
while( n-- )
{
ElementType x;
cin >> x;
ThreadTree t = new TreeNode(x);
if( root == nullptr ){
root = t;
continue;
}
ThreadTree p = root, pre;
while( p ){
pre = p;
if( x < p->val )
p = p->left;
else
p = p->right;
}
if( x < pre->val ) pre->left = t;
else pre->right = t;
}
return root;
}
// 构造中序线索二叉树,注意参数是引用
void InThread(ThreadTree& p, ThreadTree& pre)
{
if( p ){
InThread(p->left, pre); //左子树线索化
if( !p->left ){ //左结点为空,指向前驱
p->left = pre;
p->ltag = 1;
}
if( pre && !pre->right ){ //右节点为空,指向后继
pre->right = p;
pre->rtag = 1;
}
pre = p; //当前结点转为前驱
InThread(p->right, pre); //右子树线索化
}
}
bool createInThread(ThreadTree root)
{
ThreadTree pre = nullptr;
if( root ){
InThread(root, pre);
pre->right = nullptr; //最后一个结点,没有后继
pre->rtag = 1;
return true;
}
return false;
}
// 中序遍历第一个节点,是最左下的结点(不一定是叶节点)
TreeNode* firstNode(ThreadTree p)
{
while( p->ltag == 0 )
p = p->left;
return p;
}
// 后继结点,若无直接后继,则返回线索后继
TreeNode* nextNode(ThreadTree p)
{
if( p->rtag == 0 )
return firstNode(p->right);
else
return p->right;
}
void Thread_inOrder(ThreadTree root)
{
for(TreeNode* p = firstNode(root); p; p = nextNode(p))
visit(p);
cout << "\n";
}
//7
//6 2 8 1 4 7 3
int main( )
{
int n;
cin >> n;
ThreadTree root = nullptr;
root = BST_Insert(root, n);
inOrder(root);
if( createInThread(root) ){
cout << "\n";
Thread_inOrder(root);
}
return 0;
}