线索二叉树
优点:充分利用了空指针来存储更多的信息 在拿到起始节点后遍历会比普通递归遍历更快(除后序线索树外 后序线索树必须还要从根结点去找父亲 是相当耗时的)
缺点:在插入新结点或者删除节点后 又需要重新建立线索 这是一个非常耗时的过程
具体实现代码
#include<iostream>
template<typename T>
struct BTreeNode
{
T data;
BTreeNode<T>* left;
BTreeNode<T>* right;
bool left_thread;//标志位 标志孩子是否是线索
bool right_thread;
};
//我们定义"#"为空节点
template<typename T>
class ThreadBinaryTree
{
public:
ThreadBinaryTree();
~ThreadBinaryTree();
void CreateBTreeAccordPT(char* pstr);//利用扩展二叉树的前序遍历序列创建二叉树
void CreateThreadInBTreeAccordIO();//根据中序建立线索
void CreateThreadInBTreeAccordPreO();
void CreateThreadInBTreeAccordPostO();
BTreeNode<T>* GetFirstIO();//拿到中序线索树的第一个结点
BTreeNode<T>* GetNextIO(BTreeNode<T>* cur);//拿到中序线索树中cur结点的下一个结点
BTreeNode<T>* GetFirstPreO();//拿到前序线索树的第一个结点
BTreeNode<T>* GetNextPreO(BTreeNode<T>* cur);//拿到前序线索树中cur结点的下一个结点
BTreeNode<T>* GetFirstPostO();
BTreeNode<T>* GetNextPostO(BTreeNode<T>* cur);
void ClearThread();//将所有线索置空
private:
BTreeNode<T>* GetFirstIO(BTreeNode<T>* cur);//拿到以cur结点为根结点的中序线索的第一个结点 每个节点作为根的时候都肯定存在一个线索开始的结点
BTreeNode<T>* GetFirstPreO(BTreeNode<T>* cur);//拿到以cur结点为根的前序线索树的第一个结点
BTreeNode<T>* GetFirstPostO(BTreeNode<T>* cur);
BTreeNode<T>* GetNextPostOHelper(BTreeNode<T>* root,BTreeNode<T>* search);
void CreateThreadInBTreeAccordIO(BTreeNode<T>*& root,BTreeNode<T>*& pre);//真正的建立线索实现函数
void CreateThreadInBTreeAccordPreO(BTreeNode<T>*& root,BTreeNode<T>*& pre);
void CreateThreadInBTreeAccordPostO(BTreeNode<T>*& root, BTreeNode<T>*& pre);
void CreateBTreeAccordPTRecu(BTreeNode<T>*& root, char*& pstr);//真正递归前序建立实现
void ReleaseNode(BTreeNode<T>* root);//用于析构这个节点以及以他为根的所有节点
void ClearThread(BTreeNode<T>* root);
private:
BTreeNode<T>* root;//树根指针
};
template<typename T>
ThreadBinaryTree<T>::ThreadBinaryTree()
{
root = nullptr;
}
template<typename T>
ThreadBinaryTree<T>::~ThreadBinaryTree()
{
ReleaseNode(root);//释放所有节点
}
template<typename T>
void ThreadBinaryTree<T>::CreateBTreeAccordPT(char* pstr)
{
CreateBTreeAccordPTRecu(root, pstr);//调用真正的递归函数处理
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordIO()
{
BTreeNode<T>* pre = nullptr;
CreateThreadInBTreeAccordIO(root, pre);
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordPreO()
{
BTreeNode<T>* pre = nullptr;
CreateThreadInBTreeAccordPreO(root, pre);
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordPostO()
{
BTreeNode<T>* pre = nullptr;
CreateThreadInBTreeAccordPostO(root, pre);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstIO()
{
return GetFirstIO(root);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetNextIO(BTreeNode<T>* cur)
{
if (cur == nullptr)return nullptr;//检查参数
if (cur->right_thread == 1)//有右线索
{
return cur->right;//有右线索则直接返回后驱结点便可
}
//如果没有右线索 根据左中右 接下来我们要去访问右结点 但是我们的后驱结点一定是右结点嘛? 当然不是 是以右结点为根结点的线索树的第一个结点 所以我们应该调用GetFirstIO(cur->right)
return GetFirstIO(cur->right);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstPreO()
{
return GetFirstPreO(root);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetNextPreO(BTreeNode<T>* cur)
{
if (cur == nullptr)return nullptr;
if (cur->right_thread)
{
return cur->right;
}
if (!cur->left_thread && cur->left)return cur->left;
if (!cur->right_thread && cur->right)return cur->right;
return nullptr;
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstPostO()
{
return GetFirstPostO(root);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetNextPostO(BTreeNode<T>* cur)
{
if (cur == nullptr)return nullptr;
if (cur->right_thread)
return cur->right;
return GetNextPostOHelper(root,cur);//通过这个函数拿到父节点
}
template<typename T>
void ThreadBinaryTree<T>::ClearThread()
{
ClearThread(root);
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstIO(BTreeNode<T>* cur)
{
if (cur == nullptr)return nullptr;
while (!cur->left_thread&&cur->left)
{
cur = cur->left;
}
return cur;
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstPreO(BTreeNode<T>* cur)
{
return cur;
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetFirstPostO(BTreeNode<T>* cur)
{
if (cur == nullptr)return nullptr;
auto f = [&]() {
while (cur->left&&!cur->left_thread)
{
cur = cur->left;
}
};
bool first = 1;
while (first || (cur->right&&!cur->right_thread))
{
if(first)
f();
else
{
cur = cur->right;
f();
}
first = false;
}
return cur;
}
template<typename T>
BTreeNode<T>* ThreadBinaryTree<T>::GetNextPostOHelper(BTreeNode<T>* root, BTreeNode<T>* search)
{
if (root == nullptr)return nullptr;
if (!root->left_thread && root->left == search)return root;
if (!root->right_thread && root->right == search)return root;
auto left =root->left_thread?nullptr: GetNextPostOHelper(root->left, search);
auto right = root->right_thread?nullptr:GetNextPostOHelper(root->right, search);
return left == nullptr ? right : left;
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordIO(BTreeNode<T>*& root, BTreeNode<T>*& pre)
{
if (root == nullptr)return;
CreateThreadInBTreeAccordIO(root->left, pre);
if (root->left == nullptr&&!root->left_thread)//如果我左节点为空 可为线索
{
root->left_thread = true;//表明左节点是线索
root->left = pre;
}
if (pre != nullptr && pre->right==nullptr&&!pre->right_thread)//上一个结点可以为线索的话
{
pre->right_thread = true;//
pre->right = root;
}
pre = root;
CreateThreadInBTreeAccordIO(root->right, pre);
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordPreO(BTreeNode<T>*& root, BTreeNode<T>*& pre)
{
if (root == nullptr)return;
if (!root->left_thread&&root->left == nullptr)//如果我左节点为空 可为线索
{
root->left_thread = true;//表明左节点是线索
root->left = pre;
}
if (pre != nullptr && pre->right==nullptr&&!pre->right_thread)//上一个结点可以为线索的话
{
pre->right_thread = true;//
pre->right = root;
}
pre = root;
if(!root->left_thread)CreateThreadInBTreeAccordPreO(root->left, pre);
if(!root->right_thread)CreateThreadInBTreeAccordPreO(root->right, pre);
}
template<typename T>
void ThreadBinaryTree<T>::CreateThreadInBTreeAccordPostO(BTreeNode<T>*& root, BTreeNode<T>*& pre)
{
if (root == nullptr)return;
CreateThreadInBTreeAccordPostO(root->left, pre);
CreateThreadInBTreeAccordPostO(root->right, pre);
if (root->left == nullptr&&!root->left_thread)//如果我左节点为空 可为线索
{
root->left_thread = true;//表明左节点是线索
root->left = pre;
}
if (pre != nullptr && pre->right==nullptr&&!pre->right_thread)//上一个结点可以为线索的话
{
pre->right_thread = true;//
pre->right = root;
}
pre = root;
}
template<typename T>
void ThreadBinaryTree<T>::CreateBTreeAccordPTRecu(BTreeNode<T>*& root, char*& pstr)
{
if (*pstr == '#')
{
root = nullptr;
}
else
{
root = new BTreeNode<T>;
root->data = *pstr;//给data赋值
root->left_thread = false;//建立的时候线索都置为0
root->right_thread = false;
CreateBTreeAccordPTRecu(root->left, ++pstr);
CreateBTreeAccordPTRecu(root->right, ++pstr);
}
}
template<typename T>
void ThreadBinaryTree<T>::ReleaseNode(BTreeNode<T>* root)
{
//后序遍历释放节点
if (root != nullptr)
{
if(!root->left_thread)ReleaseNode(root->left);
if(!root->right_thread)ReleaseNode(root->right);
delete root;
}
//为空不用管
}
template<typename T>
void ThreadBinaryTree<T>::ClearThread(BTreeNode<T>* root)
{
if (root == nullptr)return;
if(!root->left_thread)ClearThread(root->left);
if(!root->right_thread)ClearThread(root->right);
root->left_thread = false;
root->right_thread = false;
}
测试代码为
int main()
{
ThreadBinaryTree<char> Tree;
const char* o = "AB##CD##E##";
cout << "前序遍历线索二叉树为" << endl;
Tree.CreateBTreeAccordPT((char*)o);
Tree.CreateThreadInBTreeAccordPreO();
auto l=Tree.GetFirstPreO();
while (l != nullptr)
{
cout << l->data<<endl;
l = Tree.GetNextPreO(l);
}
cout << "后序遍历线索二叉树为" << endl;
Tree.ClearThread();
Tree.CreateBTreeAccordPT((char*)o);
Tree.CreateThreadInBTreeAccordPostO();
l = Tree.GetFirstPostO();
while (l != nullptr)
{
cout << l->data << endl;
l = Tree.GetNextPostO(l);
}
cout << "中序遍历线索二叉树为" << endl;
Tree.ClearThread();
Tree.CreateBTreeAccordPT((char*)o);
Tree.CreateThreadInBTreeAccordIO();
l = Tree.GetFirstIO();
while (l != nullptr)
{
cout << l->data << endl;
l = Tree.GetNextIO(l);
}
}
测试结果为