主要是利用二叉樹的空指針域,若爲空,使左指針指向前驅,並標記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;
}