二叉树虽然是非线性结构,但二叉树的遍历却为二叉树的结点集导出了一个线性序列。对于前、中、后序遍历,出了相应序列的第一个节点和最后一个节点,二叉树的遍历序列中每个结点都有一个前驱和后继结点,但在二叉树中,无法很快的找出按照某种遍历序列该结点的前驱和后继。
普通的二叉树可能存在以下问题:
- 递归遍历有可能导致栈溢出
- 非递归版本有可能降低程序效率
- 想要找到在某种遍历形势下某个结点的前驱或后继比较难
树中有大量的空指针域造成浪费,比如:假如树中有n个结点,则必定有n+1个空指针域
线索化二叉树
使二叉树中的左空指针域指向该结点的前驱,右空指针域指向该结点的后继。
如图给二叉树结点的左右指针域加一个标记为leftChild与rightChild,标记左右指针域是否为空。
结点代码:
struct ThreadNode
{
ThreadNode(const T &d)
:data(d)
, LChild(NULL)
, RChild(NULL)
, parent(NULL)
, leftThread(LINK)
, rightThread(LINK)
{ }
T data;
ThreadNode<T>* LChild;
ThreadNode<T>* RChild;
ThreadNode<T>* parent;
Object leftThread;
Object rightThread;
};
根据二叉树的前序遍历、中序遍历、后序遍历对应的实现前序线索化二叉树、中序线索化二叉树、后续线索化二叉树。
- 前序线索化二叉树:
void _PreThreading(pThread pRoot, pThread& prev) //1.前序线索化
{
if (pRoot == NULL)
return;
//线索化当前结点的左指针域
if (pRoot->LChild == NULL)
{
pRoot->LChild = prev;
pRoot->leftThread = THREAD;
}
//线索化上一个节点的右指针域
if (prev!=NULL&&prev->RChild==NULL)
{
prev->RChild = pRoot;
prev->rightThread = THREAD;
}
prev = pRoot;
if (pRoot->leftThread == LINK)
{
_PreThreading(pRoot->LChild, prev);
}
if (pRoot->rightThread == LINK)
{
_PreThreading(pRoot->RChild, prev);
}
}
2.中序线索化二叉树:
void _InThreading(pThread pRoot, pThread& prev) //2.中序线索化
{
if (pRoot == NULL)
return;
_InThreading(pRoot->LChild,prev);
if (pRoot->LChild == NULL)
{
pRoot->LChild