线索二叉树存储结构
结点定义
使用枚举类型表示结点的类型LINK
和THREAD
enum BiThrNodeType{LINK,THREAD};
template<class T>
struct BiThrNode
{
BiThrNodeType ltype, rtype;
T data;
BiThrNode<T>* lchild,* rchild;
};
线索二叉树类模板
template<class T>
class InBiThrTree
{
BiThrNode<T>* root;
public:
BiThrNode<T>* GetRoot() { return root; }
BiThrNode<T>* CreateByPre(vector<T>& pre, int& i);
InBiThrTree() { root = nullptr; }
InBiThrTree(vector<T>& pre);
void InThreaded(BiThrNode<T>* p);
void InThreaded();
BiThrNode<T>* GetNext(BiThrNode<T>* p);//求中序遍历中的后继节点
BiThrNode<T>* GetPrev(BiThrNode<T>* p);//求中序遍历中的前驱节点
void traverse();//利用线索进行中序遍历
BiThrNode<T>* GetParent(BiThrNode<T>*p);//求父节点地址
};
先序序列构造函数
*
表示nullptr,先序序列使用 “中左右” 的顺序构造二叉树
- 先构造当前结点
- 再遍历构造左子树
- 再遍历构造右子树
注意参数i
传的是引用,在某种程度上起到了 “返回 i ” 的效果。
初始将ltype
和rtype
都设为LINK
。
template<class T>
BiThrNode<T>* InBiThrTree<T>::CreateByPre(vector<T>& pre, int& i)
{
T e = pre[i++];
if (e == '*')return nullptr;
BiThrNode<T>* p = new BiThrNode<T>;
p->data = e;
p->ltype = LINK;
p->rtype = LINK;
p->lchild=CreateByPre(pre, i);
p->rchild = CreateByPre(pre, i);
return p;
}
template<class T>
InBiThrTree<T>::InBiThrTree(vector<T>& pre)
{
int i = 0;
root = CreateByPre(pre, i);
}
当输入
string str = "ABH**FD***E*CK**G**";
vector<char> pre(str.begin(), str.end());
InBiThrTree<char> tree(pre);
构建二叉树如下:
中序线索化函数
根据遍历次序,逐个检查每个结点。
若结点的左孩子为空,则将结点的左孩子设为前驱指针,左标记域设为THREAD
。
若结点的右孩子为空,则将结点的右孩子设为后继指针,右标记域设为THREAD
。
在代码的具体实现上,声明一个全局变量pre
来记录序列中上一个指针。
伪代码如下:
template<class T>
BiThrNode<T>* prenode;
template<class T>
void InBiThrTree<T>::InThreaded(BiThrNode<T>* p)
{
if (p == nullptr)return;
InThreaded(p->lchild);
if (p->lchild == nullptr) {
p->ltype = THREAD;
p->lchild = prenode<T>;
}
if (p->rchild == nullptr) {
p->rtype = THREAD;
}
if (prenode<T>) {
if (prenode<T>->rtype == THREAD)
prenode<T>->rchild = p;
}
prenode<T> = p;
InThreaded(p->rchild);
}
template<class T>
void InBiThrTree<T>::InThreaded()
{
BiThrNode<T>* prenode = root;
InThreaded(root);
}
中序线索化后的二叉数结构如下:
查找中序序列前驱和后继结点
查找后继结点
根据中序“左中右”顺序:
- 如果
p
的右标记为THREAD
,则p
的右孩子就是后继节点。 - 如果
p
的右标记为LINK
,则p
的后继节点就是右孩子的最左孩子。
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetNext(BiThrNode<T>* p)
{
if (p->rtype == THREAD)
return p->rchild;
p = p->rchild; //右孩子的最左孩子
while (p->ltype == LINK)
p = p->lchild;
return p;
}
查找前驱结点
同理,根据中序“左中右”顺序:
- 如果
p
的左标记为THREAD
,则p
的左孩子就是前驱节点。 - 如果
p
的左标记为LINK
,则p
的前驱节点就是左孩子的最右孩子。
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetPrev(BiThrNode<T>* p)
{
if (p->ltype == THREAD)
return p->lchild;
p = p->lchild; //左孩子的最右孩子
while (p->rtype == LINK)
p = p->rchild;
return p;
}
中序遍历
通过不断p=p->lchild
,找到中序序列的起点。
调用GectNext()
函数查找当前结点的后继结点,输出,实现中序遍历。
template<class T>
void InBiThrTree<T>::traverse()
{
BiThrNode<T>* p = root;
while (p->ltype == LINK)
p = p->lchild; //找到中序遍历的起点
while (p) {
cout << p->data << " ";
p = GetNext(p);
}
cout << endl;
}
查找父结点
根据中序“左中右”顺序:
- 如果
*p
是*parent
的左孩子,则*p
的最右下方节点的后继结点一定是*p
的父结点。 - 如果
*p
是*parent
的右孩子,则*p
的最左下方节点的前驱结点一定是*p
的父结点。
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetParent(BiThrNode<T>* p)
{
if (p == nullptr)
return nullptr;
BiThrNode<T>* parent = p;
while (parent->rtype == LINK) {
parent = parent->rchild;
}
parent = parent->rchild;//*p最右下方节点的后继指针
if (parent && parent->lchild == p)
return parent;
parent = p;
while (parent->ltype == LINK) {
parent = parent->lchild;
}
parent = parent->lchild;//*p最左下方节点的前驱指针
return parent;
}
测试
int main()
{
string str = "ABH**FD***E*CK**G**";
vector<char> pre(str.begin(), str.end());
InBiThrTree<char> tree(pre);
tree.InThreaded();
tree.traverse();
cout << "Get next node of B: " << tree.GetNext(tree.GetRoot()->lchild)->data << endl;
cout << "Get next node of K: " << tree.GetNext(tree.GetRoot()->rchild->rchild->lchild)->data << endl;
cout << "Get previous node of 'E': " << tree.GetPrev(tree.GetRoot()->rchild)->data << endl;
cout << "Get previous node of 'C': " << tree.GetPrev(tree.GetRoot()->rchild->rchild)->data << endl;
cout << "Parent of B: " << tree.GetParent(tree.GetRoot()->lchild)->data << endl;
cout << "Parent of C: " << tree.GetParent(tree.GetRoot()->rchild->rchild)->data << endl;
}