二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历。用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继。
为了保存这种在遍历中需要的信息,我们利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息。
enum PointerTag {THREAD, LINK};
template <class T>
struct BinaryTreeNode_Thd
{
T _data ; // 数据
BinaryTreeNode_Thd<T >* _left; // 左孩子
BinaryTreeNode_Thd<T >* _right; // 右孩子
PointerTag _leftTag ; // 左孩子线索标志
PointerTag _rightTag ; // 右孩子线索标志
};
前序线索化以及遍历:
void PrevOrderThreading()//前序线索化
{
Node * prev = NULL;
_PrevOrderThreading(_root, prev);
}
void PrevOrderThd()//前序遍历
{
_PrevOrderThd(_root);
cout << "over" << endl;
}
//前序线索化
//prev必须要保证进入下一次递归时,保留上次递归的cur值,所以用“引用”
void _PrevOrderThreading(Node * root,Node * & prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
//线索化前驱
if (cur->_left == NULL)
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
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);
}
}
//前序遍历
void _PrevOrderThd(Node *root)
{
Node * cur = root;
while (cur)
{
while (cur->_leftTag == LINK)
{
cout << cur->_data << "->";
cur = cur->_left;
}
cout << cur->_data << "->";
//当存在右线索时,跳转过去
while (cur->_rightTag == THREAD)
{
cur = cur->_right;
cout << cur->_data << "->";
}
//该节点存在左子树时,跳到左子树上遍历
if (cur->_leftTag == LINK)
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
}
//前序遍历(2)
//void _PrevOrderThd(Node *root)
//{
// Node * cur = root;
// while (cur)
// {
// while (cur->_leftTag == LINK)
// {
// cout << cur->_data << "->";
// cur = cur->_left;
// }
// cout << cur->_data << "->";
// //直接看作是根节点,重新进行遍历
// cur = cur->_right;
// }
//}
中序线索化以及中序遍历:
void InOrderThreading()//中序线索化
{
Node * prev = NULL;
_InOrderThreading(_root, prev);
}
void InOrderThd()//中序遍历
{
_InOrderThd(_root);
cout << "over" << endl;
}
//中序线索化
void _InOrderThreading(Node *root, Node * &prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
_InOrderThreading(cur->_left, prev);//递归cur->_left==NULL的cur节点
if (cur->_left == NULL)//线索化前驱
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
if (prev&&prev->_right == NULL)
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
//更新prev
prev = cur;
_InOrderThreading(cur->_right, prev);
}
//中序遍历
void _InOrderThd(Node *root)
{
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 PostOrderThreading()//后序线索化
{
Node * prev = NULL;
_PostOrderThreading(_root, prev);
}
//后序线索化
void _PostOrderThreading(Node *root, Node * &prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
_PostOrderThreading(cur->_left, prev);//最左结点
_PostOrderThreading(cur->_right, prev);//最右结点
if (cur->_left == NULL)//线索化前驱
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
if (prev && prev->_right == NULL)
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
//更新prev
prev = cur;
}
测试代码以及结果:
void Test()
{
int array[10] = { 1, 2, 3, '#', '#', 4, '#' , '#', 5, 6 };
BinaryTreeThd<int> b1(array, 10, '#');
BinaryTreeThd<int> b2(array, 10, '#');
b1.PrevOrderThreading();
cout << "前序输出:";
b1.PrevOrderThd();
b2.InOrderThreading();
cout << "中序输出:";
b2.InOrderThd();
}
最后,附上全部代码:
#pragma once
#include <iostream>
using namespace std;
enum PointerTag
{
THREAD,//有线索标志
LINK //无线索标志
};
template <typename T>
struct BinaryTreeNodeThd
{
public:
T _data; //数据
BinaryTreeNodeThd<T> * _left; //左孩子
BinaryTreeNodeThd<T> * _right; //右孩子
PointerTag _leftTag; //左孩子线索标志
PointerTag _rightTag; //右孩子线索标志
public:
BinaryTreeNodeThd(const T a)
:_data(a)
,_left(NULL)
,_right(NULL)
,_leftTag(LINK)
,_rightTag(LINK)
{}
};
template <typename T>
class BinaryTreeThd
{
typedef BinaryTreeNodeThd<T> Node;
public:
BinaryTreeThd()//无参构造函数
:_root(NULL)
{}
BinaryTreeThd(const T* a, size_t size, const T & invalid)//有参构造函数
:_root(NULL)
{
size_t index = 0;
_root = _CheckTree(a, size, invalid, index);
}
void PrevOrderThreading()//前序线索化
{
Node * prev = NULL;
_PrevOrderThreading(_root, prev);
}
void InOrderThreading()//中序线索化
{
Node * prev = NULL;
_InOrderThreading(_root, prev);
}
void PostOrderThreading()//后序线索化
{
Node * prev = NULL;
_PostOrderThreading(_root, prev);
}
void PrevOrderThd()//前序遍历
{
_PrevOrderThd(_root);
cout << "over" << endl;
}
void InOrderThd()//中序遍历
{
_InOrderThd(_root);
cout << "over" << endl;
}
protected:
//创建二叉树
Node * _CheckTree(const T* a, size_t size, const T& invalid, size_t & index)
{
Node * root = NULL;
if (index < size&&a[index] != invalid)//不能越界
{
root= new Node(a[index]);//创建节点
root->_left = _CheckTree(a, size, invalid, ++index);
root->_right = _CheckTree(a, size, invalid, ++index);
}
return root;
}
//前序线索化
//prev必须要保证进入下一次递归时,保留上次递归的cur值,所以用“引用”
void _PrevOrderThreading(Node * root,Node * & prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
//线索化前驱
if (cur->_left == NULL)
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
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);
}
}
//前序遍历
void _PrevOrderThd(Node *root)
{
Node * cur = root;
while (cur)
{
while (cur->_leftTag == LINK)
{
cout << cur->_data << "->";
cur = cur->_left;
}
cout << cur->_data << "->";
//当存在右线索时,跳转过去
while (cur->_rightTag == THREAD)
{
cur = cur->_right;
cout << cur->_data << "->";
}
//该节点存在左子树时,跳到左子树上遍历
if (cur->_leftTag == LINK)
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
}
//前序遍历(2)
//void _PrevOrderThd(Node *root)
//{
// Node * cur = root;
// while (cur)
// {
// while (cur->_leftTag == LINK)
// {
// cout << cur->_data << "->";
// cur = cur->_left;
// }
// cout << cur->_data << "->";
// //直接看作是根节点,重新进行遍历
// cur = cur->_right;
// }
//}
//中序线索化
void _InOrderThreading(Node *root, Node * &prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
_InOrderThreading(cur->_left, prev);//递归cur->_left==NULL的cur节点
if (cur->_left == NULL)//线索化前驱
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
if (prev&&prev->_right == NULL)
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
//更新prev
prev = cur;
_InOrderThreading(cur->_right, prev);
}
//中序遍历
void _InOrderThd(Node *root)
{
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 _PostOrderThreading(Node *root, Node * &prev)
{
Node * cur = root;
if (cur == NULL)
{
return;
}
_PostOrderThreading(cur->_left, prev);//最左结点
_PostOrderThreading(cur->_right, prev);//最右结点
if (cur->_left == NULL)//线索化前驱
{
cur->_leftTag = THREAD;
cur->_left = prev;
}
//线索化后继
//cur是当前节点,线索化前一个节点的后继,指向cur
if (prev && prev->_right == NULL)
{
prev->_rightTag = THREAD;
prev->_right = cur;
}
//更新prev
prev = cur;
}
protected:
Node * _root;
};
void Test()
{
int array[10] = { 1, 2, 3, '#', '#', 4, '#' , '#', 5, 6 };
BinaryTreeThd<int> b1(array, 10, '#');
BinaryTreeThd<int> b2(array, 10, '#');
b1.PrevOrderThreading();
cout << "前序输出:";
b1.PrevOrderThd();
b2.InOrderThreading();
cout << "中序输出:";
b2.InOrderThd();
}
本文出自 “不断进步的空间” 博客,请务必保留此出处http://10824050.blog.51cto.com/10814050/1770408