二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历。用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继。
为了保存这种在遍历中需要的信息,我们利用二叉树中指向左、右子树的空指针来存放节点的前驱和后继信息。
实现源代码:
#include<iostream>
using namespace std;
enum PointerTag//枚举类型
{
THREAD,//0
LINK,//1
};
//线索化二叉树的结点结构
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;//Node 线索化结点结构
public:
BinaryTreeThd()
:_root(NULL)
{}
//构造函数,arr为结点数组,size为结点个数, index指向结点位置,invalid 非法值,如"#"
BinaryTreeThd(const T* arr,size_t size,size_t index,const T& invalid)
{
_root = _CreateBinaryTreeThd(arr, size, index, invalid);
}
//先序线索化
void PrevorderThread()
{
Node* prev = NULL;
_PrevorderThread(_root, prev);
}
//先序线索化遍历二叉树,访问根结点->左子树->右子树
void _PrevorderThreading()
{
Node* cur = _root;
if (cur == NULL)
{
return;
}
while (cur)
{
while (cur->_leftTag == LINK)
{
cout << cur->_data << " ";//依次访问根结点->左子树
cur = cur->_left;
}
cout << cur->_data<<" ";
//转移到右边的结点
cur = cur->_right;
}
}
//中序线索化
void InorderThread()
{
Node* prev = NULL;
_InorderThread(_root, prev);
}
//中序线索化遍历二叉树,访问左子树->根结点->右子树
void _InvorderThreading()
{
Node* cur = _root;
if (cur == NULL)
{
return;
}
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;
}
}
protected:
Node* _CreateBinaryTreeThd(const T* arr, size_t size, size_t& index, const T& invalid)
{
Node* root = NULL;
if (index < size&&arr[index] != invalid)
{
root = new Node(arr[index]);
root->_left = _CreateBinaryTreeThd(arr, size, ++index, invalid);
root->_right = _CreateBinaryTreeThd(arr, size, ++index, invalid);
}
return root;
}
//先序线索化子树
void _PrevorderThread(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)
{
_PrevorderThread(cur->_left, prev);
}
if (cur->_rightTag == LINK)
{
_PrevorderThread(cur->_right, prev);
}
}
//中序线索化子树
void _InorderThread(Node* cur, Node*& prev)
{
if (cur == NULL)
{
return;
}
//递归遍历左子树
_InorderThread(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;
//递归遍历右子树
_InorderThread(cur->_right, prev);
}
private:
Node* _root;
};
void test()
{
int arr1[10] = { 1,2,3,'#','#',4,'#','#', 5,6 };
int arr2[15] = { 1,2,'#',3,'#','#',4,5,'#',6,'#',7,'#','#',8 };
BinaryTreeThd<int>tree1(arr1, 10, 0, '#');//二叉树tree1
BinaryTreeThd<int>tree2(arr2, 15, 0, '#');//二叉树tree2
cout << "打印二叉树tree1:" << endl;
cout << " " << arr1[0] << endl;
cout << " " << arr1[1] << " " << arr1[8] << endl;
cout << arr1[2] << " " << arr1[5] << " " << arr1[9] << endl;
cout << "打印二叉树tree2:" << endl;
cout << " " << arr2[0] << endl;
cout << " " << arr2[1] << " " << arr2[6] << endl;
cout << " " << arr2[3] << " " << arr2[7] << " " << arr2[14]<<endl;
cout << " " << arr2[9] << endl;
cout << " " << arr2[11] << endl;
// 注意一棵二叉树一次只能线索化一次,如:先序线索之后,已经发生了线索标记,不能紧接着就进行中序线索化
cout << "先序线索化遍历二叉树tree1: ";
tree1.PrevorderThread();
tree1._PrevorderThreading();
cout << endl;
cout << "先序线索化遍历二叉树tree2: ";
tree2.PrevorderThread();
tree2._PrevorderThreading();
cout << endl;
/*cout << "中序线索化遍历二叉树tree1: ";
tree1.InorderThread();
tree1._InvorderThreading();
cout << endl;
cout << "中序线索化遍历二叉树tree2: ";
tree2.InorderThread();
tree2._InvorderThreading();
cout << endl;*/
}
int main()
{
test();
system("pause");
return 0;
}
扫描二维码关注公众号,回复:
949475 查看本文章
运行结果1:
打印二叉树tree1:
1
2 5
3 4 6
打印二叉树tree2:
1
2 4
3 5 8
6
7
先序线索化遍历二叉树tree1: 1 2 3 4 5 6
先序线索化遍历二叉树tree2: 1 2 3 4 5 6 7 8
请按任意键继续. . .
运行结果2:
打印二叉树tree1:
1
2 5
3 4 6
打印二叉树tree2:
1
2 4
3 5 8
6
7
中序线索化遍历二叉树tree1: 3 2 4 1 6 5
中序线索化遍历二叉树tree2: 2 3 1 5 6 7 4 8
请按任意键继续. . .