二叉树相关操作(遍历、路径、最近公共父节点、重构)

这篇博客详细介绍了二叉树的各种操作,包括插入、前序、中序、后序、层序遍历(递归与非递归方式)、寻找节点路径、最近公共父节点查找以及根据遍历结果重构二叉树的方法。文中提供了具体的实现代码,并展示了实际执行结果。
摘要由CSDN通过智能技术生成

本文总结了二叉树的相关操作,并在最后附上所有操作的实现。还有不足之处,以后会及时更新~

 

相关操作包括:

1、插入:InsertBTree

2、遍历

1)前序遍历(递归):PreOrderTraverse

2)前序遍历(非递归):PreOrderTraverseNoRec

3)中序遍历(递归):InOrderTraverse

4)中序遍历(非递归):InOrderTraverseNoRec

5)后序遍历(递归):PostOrderTraverse

6)后序遍历(非递归):PostOrderTraverseNoRec

7)层序遍历:LevelOrderTraverse

3、寻找从根节点到某一节点的路径:FindNodePath

4、寻找两个节点的最近公共父节点:FindNearestParent

5、重构二叉树

1)根据前序和中序遍历结果重构:RebuildFromPreAndInOrder

2)根据后序和中序遍历结果重构:RebuildFromPostAndInOrder

 

程序如下:

 

#include <iostream>
#include <stack>
#include <queue>
#include <vector>

using namespace std;

// 将节点保存的数据类型设为整型
typedef int ElemType;

struct BTreeNode
{
	ElemType elem;		// 当前节点元素
	BTreeNode *left;	// 左孩子结点
	BTreeNode *right;	// 右孩子节点
};

// 往二叉树中插入节点,该方法实际上最后生成的是二叉查找树
void InsertBTree(BTreeNode **root, ElemType elem)
{
	// 如果树为空,则创建
	if (*root == NULL)
	{
		*root = new BTreeNode;
		(*root)->elem  = elem;
		(*root)->left  = NULL;
		(*root)->right = NULL;
		return ;
	}

	BTreeNode *node = *root;
	while (node != NULL)
	{
		if (elem < node->elem)
		{
			if (node->left == NULL)
			{
				BTreeNode *temp = new BTreeNode;
				temp->elem  = elem;
				temp->left  = NULL;
				temp->right = NULL;
				node->left  = temp;
				return ;
			} 
			else
			{
				node = node->left;
			}
		} 
		else
		{
			if (node->right == NULL)
			{
				BTreeNode *temp = new BTreeNode;
				temp->elem  = elem;
				temp->left  = NULL;
				temp->right = NULL;
				node->right = temp;
				return ;
			} 
			else
			{
				node = node->right;
			}
		}
	}
}


// 前序遍历(递归方式)
void PreOrderTraverse(BTreeNode *root)
{
	if (root != NULL)
	{
		cout<<root->elem<<" ";			// 输出该节点值
		PreOrderTraverse(root->left);	// 递归遍历左子树
		PreOrderTraverse(root->right);	// 递归遍历右子树
	}
}

// 前序遍历(非递归方式)
void PreOrderTraverseNoRec(BTreeNode *root)
{
	stack<BTreeNode *> s;

	while (root!=NULL || !s.empty())
	{
		if (root != NULL)
		{
			cout<<root->elem<<" ";
			s.push(root);
			root = root->left;
		} 
		else
		{
			root = s.top()->right;
			s.pop();
		}
	}
}

// 中序遍历(递归方式)
void InOrderTraverse(BTreeNode *root)
{
	if (root != NULL)
	{
		InOrderTraverse(root->left);	// 递归遍历左子树
		cout<<root->elem<<" ";			// 输出该节点值
		InOrderTraverse(root->right);	// 递归遍历右子树
	}
}

// 中序遍历(非递归方式)
void InOrderTraverseNoRec(BTreeNode *root)
{
	stack<BTreeNode *> s;
	
	while (root!=NULL || !s.empty())
	{
		if (root != NULL)
		{
			s.push(root);
			root = root->left;
		} 
		else
		{
			cout<<s.top()->elem<<" ";	// 打印出当前节点值
			root = s.top()->right;		// 将root指向当前节点的右孩子节点
			s.pop();					// 弹出当前节点
		}
	}
}

// 后序遍历(递归方式)
void PostOrderTraverse(BTreeNode *root)
{
	if (root != NULL)
	{
		PostOrderTraverse(root->left);		// 递归遍历左子树
		PostOrderTraverse(root->right);		// 递归遍历右子树
		cout<<root->elem<<" ";				// 输出该节点值
	}
}

// 后序遍历(非递归方式)
void PostOrderTraverseNoRec(BTreeNode *root)
{
	vector<BTreeNode *> v;
	v.push_back(root);
	vector<BTreeNode *>::iterator iter = v.end()-1;	// 此时iter指向根节点

	do 
	{
		if (root != NULL)
		{
			if (root->left != NULL)
			{
				iter = v.insert(iter, root->left) + 1;
			}
			if (root->right != NULL)
			{
				iter = v.insert(iter, root->right) + 1;
			}
		}

		iter--;
		root = *iter;

	} while (iter != v.begin()-1);

	// 输出后序遍历结果
	for (iter=v.begin(); iter!=v.end(); iter++)
	{
		cout<<(*iter)->elem<<" ";
	}

}

// 分层遍历
void LevelOrderTraverse(BTreeNode *root)
{
	queue<BTreeNode *> q;

	while (root != NULL)
	{
		// 输出当前节点,并把当前节点的左右子节点放入队列中
		cout<<root->elem<<" ";
		if (root->left != NULL)
		{
			q.push(root->left);
		} 
		if (root->right != NULL)
		{
			q.push(root->right);
		}

		if (!q.empty())
		{
			root = q.front();
			q.pop();
		} 
		else
		{
			break;
		}
		
	}
}

// 根据前序遍历结果和中序遍历结果重构二叉树
void RebuildFromPreAndInOrder(BTreeNode **root, ElemType preOrder[], ElemType inOrder[], int size)
{
	if (size <= 0)
	{
		return ;
	}

	// 为新节点申请内存空间
	*root = new BTreeNode;
	(*root)->elem  = preOrder[0];
	(*root)->left  = NULL;
	(*root)->right = NULL;

	for (int num=0; num<size; num++)
	{
		if (inOrder[num] == preOrder[0])
		{
			break;
		}
	}

	RebuildFromPreAndInOrder(&((*root)->left), preOrder+1, inOrder, num);
	RebuildFromPreAndInOrder(&((*root)->right), preOrder+num+1, inOrder+num+1, size-num-1);
}

// 根据后序遍历结果和中序遍历结果重构二叉树
void RebuildFromPostAndInOrder(BTreeNode **root, ElemType postOrder[], ElemType inOrder[], int size)
{
	if (size <=0 )
	{
		return ;
	}

	// 为新节点申请内存空间
	*root = new BTreeNode;
	(*root)->elem  = postOrder[size-1];
	(*root)->left  = NULL;
	(*root)->right = NULL;

	for (int num=0; num<size; num++)
	{
		if (inOrder[num] == postOrder[size-1])
		{
			break;
		}
	}

	RebuildFromPostAndInOrder(&((*root)->left), postOrder, inOrder, num);
	RebuildFromPostAndInOrder(&((*root)->right), postOrder+num, inOrder+num+1, size-num-1);
}


// 找出从根节点到某一节点的路径,保存到 vector<BTreeNode *> path 中
bool FindNodePath(BTreeNode *root, ElemType elem, vector<BTreeNode *> &path)
{
	// 在这个函数中用 vector 实现 stack 的功能

	if (root != NULL)
	{
		path.push_back(root);

		if (root->elem == elem)
		{
			// 找到该节点
			path.assign(path.begin(), path.end());
			return true;
		} 
		else
		{
			if (FindNodePath(root->left, elem, path) == true)
			{
				return true;
			}
			if (FindNodePath(root->right, elem, path) == true)
			{
				return true;
			}
			path.pop_back();
		}
	} 
	
	return false;
}

void FindNearestParent(BTreeNode *root, ElemType elem1, ElemType elem2)
{
	// 保存自根节点到elem1和elem2所在节点的路径
	vector<BTreeNode *> path1, path2;
	FindNodePath(root, elem1, path1);
	FindNodePath(root, elem2, path2);

	// 从两个路径中找出最后一个相同的节点,该节点即最近公共父节点
	vector<BTreeNode *>::iterator iter1 = path1.begin();
	vector<BTreeNode *>::iterator iter2 = path2.begin();
	while ((*iter1)->elem == (*iter2)->elem)
	{
		iter1++;
		iter2++;
	}
	
	cout<<"节点"<<elem1<<"和"<<elem2<<"的最近公共父节点是:"<<(*(iter1-1))->elem<<endl;
}

// 测试上述函数
void main()
{
	// 定义树的根节点
	BTreeNode *root = NULL;

	// 初始化树
	int tree[] = {36, 25, 57, 11, 30, 27};
	for (int i=0; i<sizeof(tree)/sizeof(int); i++)
	{
		InsertBTree(&root, tree[i]);
	}

	/************************************************************************/
	/* 遍历二叉树                                                           */
	/************************************************************************/
	cout<<"前序遍历(递归):\t";
	PreOrderTraverse(root);
	cout<<endl;

	cout<<"前序遍历(非递归):\t";
	PreOrderTraverseNoRec(root);
	cout<<endl;

	cout<<"中序遍历(递归):\t";
	InOrderTraverse(root);
	cout<<endl;

	cout<<"中序遍历(非递归):\t";
	InOrderTraverseNoRec(root);
	cout<<endl;

	cout<<"后序遍历(递归):\t";
	PostOrderTraverse(root);
	cout<<endl;

	cout<<"后序遍历(非递归):\t";
	PostOrderTraverseNoRec(root);
	cout<<endl;

	cout<<"层序遍历:\t";
	LevelOrderTraverse(root);
	cout<<endl;

	/************************************************************************/
	/* 重构二叉树                                                           */
	/************************************************************************/
	BTreeNode *root1 = NULL;
	BTreeNode *root2 = NULL;
	ElemType preOrder[]  = {36, 25, 11, 30, 27, 57};
	ElemType inOrder[]   = {11, 25, 27, 30, 36, 57};
	ElemType postOrder[] = {11, 27, 30, 25, 57, 36};
	RebuildFromPreAndInOrder(&root1, preOrder, inOrder, 6);
	RebuildFromPostAndInOrder(&root2, postOrder, inOrder, 6);
	// 前序遍历,已验证重建的正确性
	cout<<"根据前序和中序便利结果,重构后的二叉树前序遍历结果是:";
	PreOrderTraverse(root1);
	cout<<endl;
	cout<<"根据后序和中序便利结果,重构后的二叉树前序遍历结果是:";
	PreOrderTraverse(root2);
	cout<<endl;


	/************************************************************************/
	/* 查找某一元素是否在二叉树中,如果在打印自根节点到该节点的路径         */
	/************************************************************************/
	ElemType elem = 27;	// 假设要查找的元素是27
	vector<BTreeNode *> path;	// 保存该元素所在节点的路径
	if (FindNodePath(root, elem, path) == true)
	{
		cout<<"元素 "<<elem<<" 所在节点的路径是:";
		for (vector<BTreeNode *>::iterator iter=path.begin(); iter!=path.end(); iter++)
		{
			cout<<(*iter)->elem<<" ";
		}
		cout<<endl;
	}
	else
	{
		cout<<"元素 "<<elem<<" 不在该二叉树中"<<endl;
	}


	/************************************************************************/
	/* 查找某两个节点的最近公共父节点                                       */
	/************************************************************************/
	ElemType elem1 = 57, elem2 = 27;
	FindNearestParent(root, elem1, elem2);
}


实际使用的二叉树如下:

执行结果如下:

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值