什么是线索化
在前面二叉树的遍历中我们可以了解到,二叉树的先序、中序、后序、层序遍历,所以我们都知道当以二叉树链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得到。
所以我们能想到的最简单的办法是在每个结点上增加两个指针雨fwd和bkwd,分别指示结点在任一序列遍历时得到的前驱和后继信息。这样可以大大降低存储空间密度;另一方面,在有n个结点的二叉链表中必定存在n+1个空指针域,由此就可以存放它的前驱和后继的信息。
所以:若结点有左子树,则其lchild域指示器左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild域指示其后继。为此增加了两个标志域:
以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表;
构建线索化二叉树
先序构建线索化二叉树:
我们在构建结点的时候,所有用来标记线索化的指针域全部设为LINK;所以,在构建线索化二叉树时,需要将线索化的结点改为THREAD,其实在构建二叉树的时候就是找到所有的叶子结点,然后进行修改,前驱在寻找的时候只需要将结点的上一个结点保存起来,到时候用前驱指向就可以了,后继就比较困难了;下图可以看到,prev的后继就是pRoot 所以:
以下是先序构建线索二叉树的代码:
enum PointFlag{LINK, THREAD}; //LINK表示结点,THREAD表示线索化
template<class T>
struct BinaryTreeNodeThd
{
BinaryTreeNodeThd(const T& data)
: _data(data)
, _pLeft(NULL)
, _pRight(NULL)
, _parent(NULL)
, _leftThread(LINK)
, _rightThread(LINK)
{}
T _data;
BinaryTreeNodeThd<T>* _pLeft;
BinaryTreeNodeThd<T>* _pRight;
BinaryTreeNodeThd<T>* _parent;
PointFlag _leftThread;
PointFlag _rightThread;
};
void _PreThreading(Node* pRoot, Node*& Prev)
{
if (NULL != pRoot)
{
//遍历根结点
if (NULL == pRoot->_pLeft)//找到最左边的结点
{
pRoot->_pLeft = Prev; //将前驱赋给它
pRoot->_leftThread = THREAD; //将它的改为THREAD
}
if (Prev && Prev->_pRight == NULL) //Prev是pRoot的前一个结点, 前驱就用两者的关系解决
{
Prev->_pRight = pRoot;
Prev->_rightThread = THREAD;
}
Prev = pRoot; //将Prev的值修改掉
//递归遍历左子树
if (pRoot->_leftThread == LINK)
_PreThreading(pRoot->_pLeft, Prev);
//递归遍历右子树
if (pRoot->_rightThread == LINK)
_PreThreading(pRoot->_pRight, Prev);
}
}
完整版代码:
#include<iostream>
using namespace std;
enum PointFlag{LINK, THREAD}; //LINK表示结点,THREAD表示线索化
template<class T>
struct BinaryTreeNodeThd
{
BinaryTreeNodeThd(const T& data)
: _data(data)
, _pLeft(NULL)
, _pRight(NULL)
, _parent(NULL)
, _leftThread(LINK)
, _rightThread(LINK)
{}
T _data;
BinaryTreeNodeThd<T>* _pLeft;
BinaryTreeNodeThd<T>* _pRight;
BinaryTreeNodeThd<T>* _parent;
PointFlag _leftThread;
PointFlag _rightThread;
};
template<class T>
class BinaryTreeThd
{
typedef BinaryTreeNodeThd<T> Node;
public:
BinaryTreeThd()
: _pRoot(NULL)
{}
BinaryTreeThd(const T array[], size_t size, const T& invalid)
{
size_t idx = 0;
Node* parent = NULL;
_CreatTree(_pRoot, array, size, idx, invalid, parent);
}
void PreThreading() //前序构建线索二叉树
{
Node* prev = NULL;
_PreThreading(_pRoot, prev);
}
void InThreading() //中序构建线索二叉树
{
Node* prev = NULL;
_InThreading(_pRoot, prev);
}
void PostThreading() //后序构建线索二叉树
{
Node* prev = NULL;
_PostThreading(_pRoot, prev);
}
void PreOrder()
{
Node* pCur = _pRoot;
while (pCur)
{
while (pCur->_leftThread == LINK)
{
cout << pCur->_data << " ";
pCur = pCur->_pLeft;
}
cout << pCur->_data << " ";
pCur = pCur->_pRight;
/* while (pCur->_rightThread == THREAD)
{
pCur = pCur->_pRight;
cout << pCur->_data << " ";
}
if (pCur->_leftThread == LINK)
pCur = pCur->_pLeft;
else
pCur = pCur->_pRight;*/
}
}
void InOrder()
{
Node* pCur = _pRoot;
while (pCur)
{
while (pCur->_leftThread == LINK)
{
pCur = pCur->_pLeft;
}
cout << pCur->_data << " ";
while (pCur && pCur->_rightThread == THREAD)
{
pCur = pCur->_pRight;
if (pCur)
cout << pCur->_data << " ";
}
if (pCur)
pCur = pCur->_pRight;
}
}
void PostOrder()
{
Node* pCur = _pRoot;
Node* prev = NULL;
while (pCur)
{
while (pCur->_pLeft != prev && pCur->_leftThread == LINK)//找到最左边的结点
pCur = pCur->_pLeft;
while (pCur && pCur->_rightThread == THREAD)//判断结点的右子树是否为线索
{
cout << pCur->_data << " ";
prev = pCur;
pCur = pCur->_pRight;
}
if (_pRoot == pCur) //判断是否为根结点, 左单只的情况
{
cout << pCur->_data << endl;
return;
}
while (pCur && pCur->_pRight == prev)
{
cout << pCur->_data << " ";
prev = pCur;
pCur = pCur->_parent;
}
if (pCur && pCur->_rightThread == LINK)
pCur = pCur->_pRight;
}
}
private:
void _CreatTree(Node*& pRoot, const T array[], size_t size, size_t &idx, const T& invalid, Node*& parent)
{
if (idx < size && array[idx] != invalid)
{
pRoot = new Node(array[idx]);
pRoot->_parent = parent;
_CreatTree(pRoot->_pLeft, array, size, ++idx, invalid, pRoot);
_CreatTree(pRoot->_pRight, array, size, ++idx, invalid, pRoot);
}
}
void _PreThreading(Node* pRoot, Node*& Prev)
{
if (NULL != pRoot)
{
//遍历根结点
if (NULL == pRoot->_pLeft)//找到最左边的结点
{
pRoot->_pLeft = Prev; //将前驱赋给它
pRoot->_leftThread = THREAD; //将它的改为THREAD
}
if (Prev && Prev->_pRight == NULL) //Prev是pRoot的前一个结点, 前驱就用两者的关系解决
{
Prev->_pRight = pRoot;
Prev->_rightThread = THREAD;
}
Prev = pRoot; //将Prev的值修改掉
//递归遍历左子树
if (pRoot->_leftThread == LINK)
_PreThreading(pRoot->_pLeft, Prev);
//递归遍历右子树
if (pRoot->_rightThread == LINK)
_PreThreading(pRoot->_pRight, Prev);
}
}
void _InThreading(Node* pRoot, Node*& Prev)
{
if (pRoot != NULL)
{
_InThreading(pRoot->_pLeft, Prev);
if (pRoot->_pLeft == NULL)
{
pRoot->_pLeft = Prev;
pRoot->_leftThread = THREAD;
}
if (Prev && Prev->_pRight == NULL)
{
Prev->_pRight = pRoot;
Prev->_rightThread = THREAD;
}
Prev = pRoot;
if (pRoot->_rightThread == LINK)
{
_InThreading(pRoot->_pRight, Prev);
}
}
}
void _PostThreading(Node* pRoot, Node*& Prev)
{
if (pRoot)
{
_PostThreading(pRoot->_pLeft, Prev);
_PostThreading(pRoot->_pRight, Prev);
if (pRoot->_pLeft == NULL)
{
pRoot->_pLeft = Prev;
pRoot->_leftThread = THREAD;
}
if (Prev && Prev->_pRight == NULL)
{
Prev->_pRight = pRoot;
Prev->_rightThread = THREAD;
}
Prev = pRoot;
}
}
private:
Node* _pRoot;
};
void Test()
{
char array[] = "124###35##6";
BinaryTreeThd<char> b(array, strlen(array), '#');
//b.PreThreading();
//b.InThreading();
b.PostThreading();
//b.PreOrder();
//b.InOrder();
b.PostOrder();
}
int main()
{
Test();
return 0;
}