二叉树的基本操作

#include <iostream>
#include <algorithm> // max()
#include <queue>
using namespace std;

typedef char ElemType; // 树存储的值得类型
#define STACKMAXSIZE 15 // 创建树中用到栈的最大值

// 树的存储结构
typedef struct Node
{
	Node* lchild;
	ElemType date;
	Node* rchild;
}Node, LinkBTree; 

//创建树,将括号表达式转换为树
void CreatBTree(LinkBTree*& Tree, char* str)
{
	Node* nodeStack[STACKMAXSIZE];
	int top = -1; // 栈顶标志
	Node* tmp = NULL;
	int leftOrRight; // 用来标记是左孩子(1),右孩子(2)

	while (*str != '\0')
	{
		switch (*str)
		{
		case '(': 
			top++;
			nodeStack[top] = tmp;
			leftOrRight = 1;
			break;
		case ')':
			top--;
			break;
		case ',':
			leftOrRight = 2;
			break;
		default:
			tmp = new Node;
			tmp->date = *str;
			tmp->lchild = tmp->rchild = NULL;
			if (Tree == NULL) {
				Tree = tmp;
			}
			else {
				if (leftOrRight == 1)
					nodeStack[top]->lchild = tmp;
				else if (leftOrRight == 2)
					nodeStack[top]->rchild = tmp;
			}
			break;
		}
		str++;
	}
}

// 销毁树
void destoryTree(LinkBTree*& Tree)
{
	if (!Tree)
		return;
	destoryTree(Tree->lchild); // 销毁左边的树
	destoryTree(Tree->rchild); // 销毁右边的树
	delete Tree; // 删除当前树的根节点
}

// 找到值为e的结点,返回该地址
Node *findNode(LinkBTree*& Tree, ElemType e)
{
	if (Tree == NULL)
		return NULL;

	if (Tree->date == e)
		return Tree;

	Node* p = findNode(Tree->lchild, e); // 先搜索做左边的树
	if (p != NULL)
		return p;
	else
		return findNode(Tree->rchild, e); // 左边没有就找右边
}

// 求树的深度
int BTNodeDepth(LinkBTree* Tree)
{
	if (!Tree)
	{
		return 0;
	}

	return max(BTNodeDepth(Tree->lchild), BTNodeDepth(Tree->rchild)) + 1;
}

// 按括号表示法输出树
void displayTree(LinkBTree* Tree)
{
	if (!Tree)
		return;

	cout << Tree->date;
	if(Tree->lchild != NULL || Tree->rchild != NULL)
	{
		cout << '(';
		displayTree(Tree->lchild);
		if(Tree->rchild != NULL)
			cout << ',';
		displayTree(Tree->rchild);
		cout << ')';
	}
}

// 先序遍历
void preOrder(LinkBTree* Tree)
{
	if (Tree == NULL)
		return;
	cout << Tree->date;
	preOrder(Tree->lchild);
	preOrder(Tree->rchild);
}

// 中序遍历
void inOrder(LinkBTree* Tree)
{
	if (Tree == NULL)
		return;
	inOrder(Tree->lchild);
	cout << Tree->date;
	inOrder(Tree->rchild);
}

// 后序遍历
void postOrder(LinkBTree* Tree)
{
	if (Tree == NULL)
		return;
	postOrder(Tree->lchild);
	postOrder(Tree->rchild);
	cout << Tree->date;
}

// 先序遍历(带NULL)
void preOrderWithNULL(LinkBTree* Tree)
{
	if (Tree == NULL) {
		cout << '^';
		return;
	}
	cout << Tree->date;
	preOrderWithNULL(Tree->lchild);
	preOrderWithNULL(Tree->rchild);
}

// 中序遍历(带NULL)
void inOrderWithNULL(LinkBTree* Tree)
{
	if (Tree == NULL) {
		cout << '^';
		return;
	}
	inOrderWithNULL(Tree->lchild);
	cout << Tree->date;
	inOrderWithNULL(Tree->rchild);
}

// 后序遍历(带NULL)
void postOrderWithNULL(LinkBTree* Tree)
{
	if (Tree == NULL) {
		cout << '^';
		return;
	}
	postOrderWithNULL(Tree->lchild);
	postOrderWithNULL(Tree->rchild);
	cout << Tree->date;
}

// 输出结点值为e的左右孩子
void printRightAndLeftSonOf(LinkBTree *Tree, ElemType e) {
	Node *node = findNode(Tree, e); // 找值为e的结点

	// 没找到
	if (node == NULL) {
		cout << "树中没有结点的值为" << e << endl;
	}

	// 输出左右结点
	if (node->lchild != NULL)
		cout << "左孩子的值是:" << node->lchild->date << endl;
	else
		cout << "左孩子的值是:NULL" << endl;

	if (node->rchild != NULL)
		cout << "右孩子的值是:" << node->rchild->date << endl;
	else
		cout << "右孩子的值是:NULL" << endl;
}

// 返回一棵二叉树的结点个数
int countNode(LinkBTree *Tree) {
	if (Tree == NULL)
		return 0;

	return countNode(Tree->lchild) + countNode(Tree->rchild) + 1;
}

// 返回一棵二叉树的双分支结点的个数
int countDoubleNode(LinkBTree *Tree) {
	if (Tree == NULL) {
		return 0;
	}

	if (Tree->lchild != NULL && Tree->rchild != NULL) // 是否同时有左右结点
		return countDoubleNode(Tree->lchild) + countDoubleNode(Tree->rchild) + 1;
	else
		return countDoubleNode(Tree->lchild) + countDoubleNode(Tree->rchild);
}

// 返回一棵二叉树的单分支结点的个数
int countSingleNode(LinkBTree *Tree) {
	if (Tree == NULL) {
		return 0;
	}

	if ((Tree->lchild != NULL && Tree->rchild == NULL) || (Tree->lchild == NULL && Tree->rchild != NULL)) // 当前根节点是否只有一个子节点
		return countSingleNode(Tree->lchild) + countSingleNode(Tree->rchild) + 1;
	else
		return countSingleNode(Tree->lchild) + countSingleNode(Tree->rchild);
}

// 返回一棵二叉树叶子结点的个数
int countLeafNode(LinkBTree* Tree) {
	if (Tree == NULL) {
		return 0;
	}
	if (Tree->lchild == NULL && Tree->rchild == NULL) {
		return 1;
	}
	return countLeafNode(Tree->lchild) + countLeafNode(Tree->rchild);
}

//求二叉树的宽度  
int treeWidth(LinkBTree * Tree) {
	if (Tree == NULL)
		return 0;

	int nLastLevelWidth = 0;//记录上一层的宽度  
	int nCurLevelWidth = 0;//记录当前层的宽度  

	queue<LinkBTree*> myQueue;
	myQueue.push(Tree);//将根节点入队列  
	int nWidth = 1;//二叉树的宽度  
	nLastLevelWidth = 1;
	LinkBTree* pCur = NULL;

	while (!myQueue.empty())//队列不空  
	{
		while (nLastLevelWidth != 0) {
			pCur = myQueue.front();//取出队列头元素  
			myQueue.pop();//将队列头元素出对  

			if (pCur->lchild != NULL)
				myQueue.push(pCur->lchild);

			if (pCur->rchild != NULL)
				myQueue.push(pCur->rchild);
			nLastLevelWidth--;
		}

		nCurLevelWidth = myQueue.size();
		nWidth = nCurLevelWidth > nWidth ? nCurLevelWidth : nWidth;
		nLastLevelWidth = nCurLevelWidth;
	}
	return nWidth;
}

Node* findLowestCommonAscestor(LinkBTree *Tree, ElemType e1, ElemType e2) {
	if (Tree == NULL) {
		return NULL;
	}

	// 存储findNode的结果,减少重复计算
	Node* tmp1 = new Node;
	Node* tmp2 = new Node;

	// 判断左边的树是不是都同时含有e1, e2,是的话就往左边的子树找
	tmp1 = findNode(Tree->lchild, e1);
	tmp2 = findNode(Tree->lchild, e2);
	if (tmp1 != NULL && tmp2 != NULL) {
		return findLowestCommonAscestor(Tree->lchild, e1, e2);
	}

	// 判断右边的树是不是都同时含有e1, e2,是的话就往右边的子树找
	tmp1 = findNode(Tree->rchild, e1);
	tmp2 = findNode(Tree->rchild, e2);
	if (tmp1 != NULL && tmp2 != NULL) {
		return findLowestCommonAscestor(Tree->rchild, e1, e2);
	}
	
	// 左边、右边的树都不能同时含有e1、e2, 那他们共同的祖先就是当前的根节点
	return Tree;
}

int main()
{
	ElemType e, e1, e2;
	LinkBTree* Tree = NULL;
	char Treestr[100];
	Node* node;

	// "A(B(D(,G)),C(E(H),F(,I))"
	cout << "输入你要创建树的括号表示法:";
	cin >> Treestr;
	CreatBTree(Tree, Treestr);

	//1,括号表示法输出该树。
	cout << "该树的括号表示法:";
	displayTree(Tree);
	cout << endl;

	//2,输入一个结点的值,输出该结点的左,右孩子的值。(要能测试错误数据)
	cout << "输入你要查找的值,我们会输出她的左右孩子" << endl; cin >> e;
	printRightAndLeftSonOf(Tree, e);

	//3,输出该二叉树的高度。
	cout << "该树的高度:" << BTNodeDepth(Tree) << endl;

	//4,输出该二叉树结点的个数。
	cout << "二叉树结点的个数:" << countNode(Tree) << endl;

	//5,输出该二叉树双分支结点的个数。
	cout << "二叉树双结点的个数:" << countDoubleNode(Tree) << endl;

	//6,输出该二叉树单分支结点的个数。
	cout << "二叉树单结点的个数:" << countSingleNode(Tree) << endl;

	//7,输出该二叉树叶子结点的个数。
	cout << "二叉树叶子结点的个数:" << countLeafNode(Tree) << endl;

	//8,输出该二叉树的宽度。(宽度为每层结点数的最大值)
	cout << "二叉树的宽度:" << treeWidth(Tree) << endl;

	//9,(选做题)任意给定该二叉树的两个结点,输出它们的最近的公共祖先。
	//(例:对P247图7.33,输入J,N,它们的祖先是H,E,B,A,最近的祖先是H。)
	cout << "输入你要找出他们共同祖先的两个节点的值:"; cin >> e1 >> e2;
	node = findLowestCommonAscestor(Tree, e1, e2);
	cout << "他们最近的共同祖先是:" << node->date << endl;

	//10,销毁该二叉树。
	destoryTree(Tree);

	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值