c++ 二叉树的线索化(前中后序遍历)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ 二叉树的线索化(前中后序遍历)相关的知识,希望对你有一定的参考价值。

#pragma once//.hpp函数头文件

#include<iostream>

using namespace std;

enum BinTreeNodeChildType
{
	Thread,
	Link
};

template <class T>
struct BinaryTreeThrNode
{
public:
	T _data;  //数据域
	BinaryTreeThrNode<T>* _leftChild;//做孩子
	BinaryTreeThrNode<T>* _rightChild;//右孩子
	BinTreeNodeChildType _leftType;//左节点类型
	BinTreeNodeChildType _rightType;//右节点类型
	BinaryTreeThrNode<T>* _parent;//父节点  (后续线索化 遍历 用到)

public:
	BinaryTreeThrNode(const T& data)
		:_data(data)
		, _leftChild(NULL)
		, _rightChild(NULL)
		, _leftType(Link)
		, _rightType(Link)
		, _parent(NULL)
	{}

	~BinaryTreeThrNode()
	{}
};

template <class T>
class BinaryTreeThread
{
public:
	BinaryTreeThrNode<T>* _root;
public:
	BinaryTreeThread()
		:_root(NULL)
	{}

	BinaryTreeThread(T*a, size_t size)
	{
		size_t index = 0;
		_root = _CreateBiTree(a, index, size);
	}

	void InOrderThread()
	{
		BinaryTreeThrNode<T>* prev = NULL;
		BinaryTreeThrNode<T>* cur = _root;
		_InOrderThread(cur,prev );
	}

	void PreOrderThread()
	{
		BinaryTreeThrNode<T>* prev = NULL;
		_PreOrderThread(_root,prev);
	}



	void InOrderThe1()  //cur每次循环跳一次
	{
		BinaryTreeThrNode<T>* cur = _root;
		BinaryTreeThrNode<T>*prev = _root;
		while (cur)
		{
			if (cur->_leftChild&&prev->_rightChild != cur&&cur->_leftType == Link)
				cur = cur->_leftChild;
			else
			{
				cout << cur->_data << ‘ ‘;
				if (cur->_rightType == Thread)
					prev = cur;
				cur = cur->_rightChild;
			}
		}
	}
	void InOrderThe()  //cur每次循环中有循环
	{
		BinaryTreeThrNode<T>* cur = _root;
		while (cur)
		{
			while (cur&&cur->_leftType == Link)
			{
				cur = cur->_leftChild;
			}
			cout << cur->_data << ‘ ‘;
			while (cur&&cur->_leftType== Thread)
			{
				cur = cur->_rightChild;
				cout << cur->_data<<‘ ‘;
			}
			cur = cur->_rightChild;
		}
	}

	//前序线索遍历
	void PreOrderThe()
	{
		BinaryTreeThrNode<T>* cur = _root;
		while (cur&&cur->_rightChild)
		{
			while (cur->_leftType != Thread)
			{
				cout << cur->_data << ‘ ‘;
				cur = cur->_leftChild;
			}
			while (cur->_rightType == Thread)
			{
				cout << cur->_data << ‘ ‘;
				cur = cur->_rightChild;
				if (cur->_rightChild == NULL)
					cout << cur->_data << ‘ ‘;
					
			}
		}

	}
        //后续线索遍历
	void PostOrderThe1()//老师的方法
	{
		if (_root == NULL)
			return;

		BinaryTreeThrNode<T>* cur = _root->_left;
		BinaryTreeThrNode<T>* prev = NULL;

		while (cur != _root)
		{
			// 1.找最左节点
			while (cur && cur->_leftTag == LINK)
				cur = cur->_left;

			while (cur && cur->_rightTag == THREAD)
			{
				cout << cur->_data << " ";
				prev = cur;
				cur = cur->_right;
			}

			// 当跳到root则遍历完成
			if (cur == _root)
			{
				cout << _root->_data << " ";
				break;
			}

			// 一个节点的右树已经访问完成,则跳转到根节点
			if (cur && cur->_rightTag == LINK
				&& cur->_right == prev)
			{
				cout << cur->_data << " ";
				prev = cur;

				cur = cur->_parent;
			}

			// 往右树跳转
			if (cur && cur->_rightTag == LINK)
			{
				cur = cur->_right;
			}
		}

		cout << endl;
	}


	void PosOrderThe()//后续线索遍历(借助 父节点)
	{
		BinaryTreeThrNode<T>* cur = _root;
		BinaryTreeThrNode<T>* prev = NULL;//防止死循环的记录指针
		while (cur)
		{

			while (prev!=cur->_leftChild&&cur!=prev&&cur->_leftType != Thread)//左支不为Thread且 prev不为cur坐支且prev!=cur 循环压左
				cur = cur->_leftChild;
			if (prev==cur&&cur->_rightType == Link)//右支不为Thread类型 压右
				cur = cur->_rightChild;
			else
			{
				while (cur->_rightType == Thread)  //右支为Thread类型 循环压右  输出
				{
					
					cout << cur->_data << ‘ ‘;
					cur = cur->_rightChild;
					prev= cur; 
				}
				cout << cur->_data << ‘ ‘;
				cur = cur->_parent;
				if (cur&&cur->_rightType == Link&&cur->_leftChild==prev)
				{
					prev = cur;//prev始终为右支返回的父节点
				}
			}
			if (cur == _root&&prev != cur)//prev是从右支返回的并且 cur为根节点结束循环
			{
				cout << cur->_data << ‘ ‘;
				break;
			}	
		}
	}
        //后续线索化
	void PosOrderThread()
	{
		BinaryTreeThrNode<T>* prev = NULL;
		_PosOrderThread(_root,prev);
	}

	BinaryTreeThrNode<T>* _CreateBiTree(const T* tmp,  size_t& index, size_t size)
	{
		BinaryTreeThrNode<T>* root = NULL;
		BinaryTreeThrNode<T>* parent = NULL;
		if (index < size&&tmp[index] != ‘#‘)
		{
			
			root = new BinaryTreeThrNode<T>(tmp[index]);	
			parent=_CreateBiTree(tmp, ++index, size);
			if (parent)
			{
				root->_leftChild = parent;
				parent->_parent = root;
			}
			parent = _CreateBiTree(tmp, ++index, size);
			
		}
		if (parent)
		{
			root->_rightChild = parent;
			parent->_parent = root;
		}
		return root;
	}


	//中序线索化

	void _InOrderThread(BinaryTreeThrNode<T>*cur,BinaryTreeThrNode<T>* & prev)
	{
		if (cur ==NULL)
			return;
		_InOrderThread(cur->_leftChild,prev);//向左树遍历
		if (cur->_leftChild==NULL)            //左为空  改变左类型 左指向prev
		{
			cur->_leftType = Thread;
			cur->_leftChild = prev;
		
		}
		if (prev&&prev->_rightChild == NULL) //prev!=NULL 且prev右不空 改变右类型 让右指向当前
		{
			prev->_rightType = Thread;			
			prev->_rightChild = cur;
		}
		prev = cur;                          //prev指向递归返回前的节点
		_InOrderThread(cur->_rightChild, prev);  //指向右数节点
		
}


	//前序线索化 自己的笨办法
	void _PreOrderThread1(BinaryTreeThrNode<T>* cur, BinaryTreeThrNode<T>* &prev)
	{
		if (cur == NULL)
			return;
		if (prev&&prev->_rightType == Thread&&prev->_rightChild==NULL)//给右为空的左节点
			prev->_rightChild = cur;
		if (cur->_leftChild)//左不空  压左
		{	
			prev = cur;   //prev=上个节点
			_PreOrderThread(cur->_leftChild, prev);
		}
		else
		{
			cur->_leftType = Thread;//左空  左节点类型为线索类型
			cur->_leftChild = prev;//线索指向prev
		}
		if (cur->_rightChild)//右不为空
		{
			_PreOrderThread(cur->_rightChild, prev);//压右
		}
		else
		{
			
			if (prev&&prev->_rightType==Thread&&cur->_leftType==Link&&cur->_rightChild==NULL)
				cur->_rightChild =prev;//判断是否该节点为只有左分支 是的话使右线索指向左分支
			cur->_rightType = Thread;//右分支为线索类型
			if (cur->_rightChild==NULL)//不连续压左情况  右分支为空  使prev=cur
				prev = cur;
		}		
	}

	void _PreOrderThread(BinaryTreeThrNode<T>* cur, BinaryTreeThrNode<T>* &prev)//老师方法
	{
		if (cur == NULL)//空返回
			return;
		if (cur->_leftChild == NULL)//左植线索化  当前递归中
		{
			cur->_leftType = Thread;
			cur->_leftChild = prev;		
		}
		if (prev&&prev->_rightChild == NULL)//右植线索化 返回上次递归中
		{
			prev->_rightType = Thread;
			prev->_rightChild = cur;		
		}

		prev = cur; //prev为上次递归cur

		if (cur->_leftType==Link)//cur左值类型为节点类型 继续递归
			_PreOrderThread(cur->_leftChild, prev);
		if (cur->_rightType==Link)//cur右植类型为节点类型 继续递归
		_PreOrderThread(cur->_rightChild, prev);		
	}

	//后续线索化
	void _PosOrderThread(BinaryTreeThrNode<T>* cur,BinaryTreeThrNode<T>*& prev)
	{
		if (cur == NULL)
			return;
		
		if (cur->_leftChild == NULL)//作为空左支线索化=prev
		{
			cur->_leftType = Thread;
			cur->_leftChild = prev;
		}
		
		
		if (cur->_leftType==Link)//cur左支类型为节点类型  递归左
			_PosOrderThread(cur->_leftChild,prev);
			
		if (cur->_rightType==Link)//cur右植为节点类型  递归右
			_PosOrderThread(cur->_rightChild,prev);
		if (prev&&prev->_rightChild == NULL)  //prev右植为空  prev指向当前
		{
			prev->_rightType = Thread;
			prev->_rightChild = cur;
		}
		prev = cur;  //子树递归结束 prev=cur  
		
	}
};

//测试用例
#include"bintreethread.hpp"
#include"BinaryTreeThreading.h"

using namespace std;

void test()
{
	int a[10] = { 1, 2, 3, ‘#‘, ‘#‘,4, ‘#‘, ‘#‘, 5, 6 };
	int s[18] = { 1, 2, 3, 4, ‘#‘, ‘#‘, 5, ‘#‘, ‘#‘, 6, ‘#‘, ‘#‘, 7, 8, ‘#‘, ‘#‘, 9, 10 };
	int k[14] = { 1, 2, 3, 4, ‘#‘,‘#‘,‘#‘,5,‘#‘,‘#‘, 6, 7,‘#‘,‘#‘ };
	BinaryTreeThread<int> s1;
	BinaryTreeThread<int> s2(s,18);
	//BinaryTreeThread<int> s2(k, 14);
	//BinaryTreeThread<int> s2(a, 10);
	
	/*s2.InOrderThread();
	s2.InOrderThe();*/
	//s2.PreOrderThread();
	
	s2.PosOrderThread();
	s2.PosOrderThe();
}

int main()
{
	test();
	return 0;
}


以上是关于c++ 二叉树的线索化(前中后序遍历)的主要内容,如果未能解决你的问题,请参考以下文章

二叉树的前中后序遍历全世界

C++实现二叉树 前中后序遍历(递归与非递归)非递归实现过程最简洁版本

二叉树的前中后序遍历

二叉树的前中后序遍历简单的递归

学习数据结构笔记 --- [二叉树学习(BinaryTree)]

二叉树的前中后序遍历(非递归实现)