二叉树的遍历运算是将二叉树中节点按一定规律线性化的过程,当二叉链表作为存储结构时,只能找到节点的左、右孩子信息,而不能直接得到节点在遍历序列中的前驱和后继信息。线索化二叉树能够解决这样的问题,将二叉链表中的空指针域填上相应节点的遍历前驱或后继节点的地址,而前驱和后继的地址只能在动态的遍历过程中才能得到。可以按照不同的遍历次序进行线索化,先序遍历、遍历过程中的节点的前驱、后继信息保存下来。下面是线索化二叉树节点结构:
其中,_left和_right表示节点的左、右孩子,_leftTag和_rightTag表示指向节点的遍历前驱、后继,指向前驱和后继的指针称为“线索”。
下面为先序线索二叉树示例:
——以下就是具体的程序代码:
#pragma once
//实现线索二叉树
enum PointerTag
{
THREAD, //线索
LINK //连接
};
template <class T>
struct BinaryTreeNodeThd
{
T _data; // 数据
BinaryTreeNodeThd<T>* _left; // 左孩子
BinaryTreeNodeThd<T>* _right; // 右孩子
PointerTag _leftTag; // 左孩子线索标志
PointerTag _rightTag; // 右孩子线索标志
BinaryTreeNodeThd(const T& x) //构造节点
:_data(x)
, _left(NULL)
, _right(NULL)
, _leftTag(LINK)
, _rightTag(LINK)
{ }
};
template <class T>
class BinaryTreeThd
{
typedef BinaryTreeNodeThd<T> Node;
public:
BinaryTreeThd(const T* a, size_t size, const T& invalid) //创建线索二叉树
{
size_t index = 0;
_root = _CreateTree(a, size, index, invalid);
}
~BinaryTreeThd() //析构函数
{ }
public:
void InOrderThreading() //中序线索二叉树
{
Node* prev = NULL;
_InOrderThreading(_root, prev);
}
void PrevOrderThreading() //前序线索二叉树
{
Node* prev = NULL;
_PrevOrderThreading(_root, prev);
}
void InOrderThd() //中序遍历线索二叉树
{
if (_root == NULL)
{
return;
}
Node* cur = _root;
while (cur)
{
//先找最左节点
while (cur->_leftTag == LINK)
{
cur = cur->_left;
}
cout << cur->_data << " ";
//访问连续后继
while (cur->_rightTag == THREAD)
{
cur = cur->_right;
cout << cur->_data << " ";
}
//访问右子树
cur = cur->_right;
}
}
//void PrevOrderThd() //前序遍历线索二叉树(方法一)
//{
// if (_root == NULL)
// {
// return;
// }
// Node* cur = _root;
// while (cur)
// {
// //遍历左子树
// while (cur->_leftTag == LINK)
// {
// cout << cur->_data << " ";
// cur = cur->_left;
// }
// cout << cur->_data << " ";
// //直接访问右子树
// cur = cur->_right;
// }
//}
void PrevOrderThd() //前序遍历线索二叉树(方法二)
{
if (_root == NULL)
{
return;
}
Node* cur = _root;
while (cur)
{
cout << cur->_data << " ";
if (cur->_leftTag == LINK) //直接用循环处理
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
}
protected:
Node* _CreateTree(const T* a, size_t size, size_t& index, const T& invalid)
//建立线索二叉树(前序)
{
Node* root = NULL;
if (index < size && a[index] != invalid)
{
root = new Node(a[index]);
root->_left = _CreateTree(a, size, ++index, invalid); //只能使用++index
root->_right = _CreateTree(a, size, ++index, invalid);
}
return root;
}
void _InOrderThreading(Node* cur, Node*& prev) //中序线索二叉树
{
if (cur == NULL)
{
return;
}
_InOrderThreading(cur->_left, prev); //线索化左子树
if (cur->_left == NULL) //遍历到左端
{
cur->_leftTag = THREAD; //添加线索
cur->_left = prev;
}
if (prev && prev->_right == NULL) //遍历到右端
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
prev = cur;
_InOrderThreading(cur->_right, prev); //线索化右子树
}
void _PrevOrderThreading(Node* cur, Node*& prev) //前序线索二叉树
{
if (cur == NULL)
{
return;
}
if (cur->_left == NULL) //线索化左端
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
if (prev && prev->_right == NULL) //线索化右端
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
prev = cur;
if (cur->_leftTag == LINK) //线索化左子树
{
_PrevOrderThreading(cur->_left, prev);
}
if (cur->_rightTag == LINK) //线索化右子树
{
_PrevOrderThreading(cur->_right, prev);
}
}
protected:
Node* _root;
};
转载于:https://blog.51cto.com/10740590/1768362