c++线索二叉树的实现 复制可运行

线索二叉树

优点:充分利用了空指针来存储更多的信息 在拿到起始节点后遍历会比普通递归遍历更快(除后序线索树外 后序线索树必须还要从根结点去找父亲 是相当耗时的)

缺点:在插入新结点或者删除节点后 又需要重新建立线索 这是一个非常耗时的过程

具体实现代码

#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);
	}
}

测试结果为

猜你喜欢

转载自blog.csdn.net/qq_16401691/article/details/128046661