C++ - 表达式二叉树

问题描述与解题思路与我之前用C语言写过的博客一模一样,这里这不过是用面向对象的思想以C++语言的方式再次呈现一遍。

C语言版本:点击打开链接

https://blog.csdn.net/y_16041527/article/details/79835727

So......这里直接上C++的完整代码

注意:这里采用多文件编程、不要将BinaryTree.h头文件和ExpTFTree.cpp文件按照前后顺序直接放到一起,会导致编译错误,分开放。

头文件声明:

//BinaryTree.h

#include <iostream>
const int MaxSize = 100;
using namespace std;

//链式二叉树节点的抽象数据类型定义
template <class T>
class BinaryTreeNode
{
public:
	T data;         //数据域
	BinaryTreeNode<T> *left, *right;    //指向二叉树节点的指针

	BinaryTreeNode() {}      //无参构造函数
	BinaryTreeNode(const T d, BinaryTreeNode<T> *l = NULL, BinaryTreeNode<T> *r = NULL)
		:data(d), left(l), right(r) {}            //给定数据域和指针域的构造函数
};

//表达式二叉树的抽象数据类型定义
template <class T>
class ExpTFTree:public BinaryTreeNode<T>
{
public:
	BinaryTreeNode<T> *root;  //二叉树根节点
	T s[MaxSize];          //存储表达式的数组

public:
	ExpTFTree() { root = NULL; }       //构造函数
	~ExpTFTree()         //析构函数
	{
		DeleteExpTFTree(root);
		cout << "释放成功" << endl;
	}   
	void PerCreateTree();  //前缀表达式建树
	void PostCreateTree();  //后缀表达式建树过程
	BinaryTreeNode<T>* InCreateTree(T s[], int i, int j);  //中缀表达式建树过程

	void DispTree(BinaryTreeNode<T> *root);   //凹入表示法输出一棵二叉树
	void PerOrder(BinaryTreeNode<T> *root);  //前序周游给定二叉树
	void InOrder(BinaryTreeNode<T> *root);   //中序周游
	void PostOrder(BinaryTreeNode<T> *root);  //后序周游

	void DeleteExpTFTree(BinaryTreeNode<T> *root);  //删除给定的二叉树
};

Cpp文件

//ExpTFTree.cpp - 表达式二叉树

#include "stdafx.h"
#include "BinaryTree.h"
#include <string.h>
using namespace std;

//ExpTFTree类相关成员函数的实现
//删除给定的二叉树
template <class T>
void ExpTFTree<T>::DeleteExpTFTree(BinaryTreeNode<T> *root)
{
	if (root)
	{
		DeleteExpTFTree(root->left);
		DeleteExpTFTree(root->right);
       
		delete root;
		root = NULL;
	}
}

//凹入表示法输出二叉树
template <class T>
void ExpTFTree<T>::DispTree(BinaryTreeNode<T> *root)
{
	cout << "凹入表示法输出一棵二叉树" << endl;
	BinaryTreeNode<T> *stack[MaxSize], *p;          //stack[top]为指针数组,其中每一个元素存放的是指向树节点的指针 
	int level[MaxSize][2], top, i, n, width = 4;
	//top为stack栈指针、levle[MaxSize][2]为二维数组,0维度-width(输出空格数)、1维度-不同节点
	T type;

	if (root != NULL)
	{
		top = 1;                  //左节点之前输出(0)
		stack[top] = root;        //根节点入栈
		level[top][0] = width;
		level[top][1] = 2;     //2代表根节点

		while (top > 0)        //栈不为空时,循环继续 
		{
			p = stack[top];        //退栈并凹入显示该节点值
			n = level[top][0];

			switch (level[top][1])
			{
			case 0:
				type = '0';         //左节点之前输出(0)
				break;
			case 1:
				type = '1';        //右节点之前输出(1) 
				break;
			case 2:
				type = 'r';        //根节点之前输入(r)
				break;
			}

			for (i = 1; i <= n; i++)           //n为输出的空格数,字符以右对齐显示 
				cout << " ";
			cout << p->data << " (" << type << ")";
			for (i = n + 1; i <= MaxSize; i += 2)
				cout << "-";
			cout << endl;
			top--;                     //根节点出栈

									   //因为使用的栈、所以先将右子树根入栈,后将左子树根入栈
									   //然后出栈时,按照后进先出的原则先输出左子树根,后输出右子树根 
			if (p->right != NULL)
			{
				top++;
				stack[top] = p->right;          //将右子树根节点入栈 
				level[top][0] = n + width;        //输出空格数增加width 
				level[top][1] = 1;              //1表示是右子树 
			}
			if (p->left != NULL)
			{
				top++;
				stack[top] = p->left;          //将左子树根节点入栈 
				level[top][0] = n + width;        //输出空格数增加width  
				level[top][1] = 0;              //0代表左子树 
			}
		}
	}
	cout << endl;
}

//前缀表达式建树
template <class T>
void ExpTFTree<T>::PerCreateTree()
{
	cout << "前缀表达式建树" << endl;
	cout << "前缀表达式:";
	cin >> s;
	int len = strlen(s);
	//	cout << "len:" << len << endl;
	//计数变量 
	int i;
	BinaryTreeNode<T> *p;
	//临时栈 - 用来存放指向树节点的指针
	struct stack
	{
		BinaryTreeNode<T> *vec[MaxSize];
		int top;
	};
	struct stack q;
	q.top = 0;

	//遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数
	//节点的指针,并指向该运算符节点并将其入栈
	for (i = len - 1; i >= 0; i--)
	{
		//为操作符 
		if (s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-')
		{
			p = new BinaryTreeNode<T>(s[i]);
			p->left = q.vec[q.top--];    //先弹出的为左节点 
			p->right = q.vec[q.top--];     //后弹出的为右节点 
			q.vec[++q.top] = p;           //将根节点入栈 
		}
		else   //s[i]为操作数 
		{
			p = new BinaryTreeNode<T>(s[i]);
			q.vec[++q.top] = p;      //将指向操作数节点的指针入栈 
		}
	}

	root = q.vec[q.top--];        //这一步很关键,因为该二叉树的根节点最后被保留在了栈中 
}

//中缀表达式建树过程
template <class T>
BinaryTreeNode<T>* ExpTFTree<T>::InCreateTree(T s[], int i, int j)
{
	BinaryTreeNode<T> *p;
	int k, flag = 0, pos;

	//如果i == j,则说明字符串只有一个字符,即为叶子节点、则创建只有一个根节点的二叉树并返回
	if (i == j)
	{
		p = new BinaryTreeNode<T>(s[i]);
		return p;
	}
	//以下是 i != j的情况
	//从左往右找最后一个+或-,先找+或-为了体现先乘除后加减的原则 
	for (k = i; k <= j; k++)
	{
		if (s[k] == '+' || s[k] == '-')
		{
			flag = 1;
			pos = k;
		}
	}
	//若没有+或-,则寻找字符串中最后一个*或/ 
	if (flag == 0)
	{
		for (k = 0; k <= j; k++)
		{
			if (s[k] == '*' || s[k] == '/')
			{
				flag = 1;
				pos = k;
			}
		}
	}
	//若flag不等于0,则以pos为界将字符串分为左右两部分,分别对应表达式二叉树的左、右子树 
	//同样以最后的运算符为根,将串分为两部分
	//创建一个根节点、将找到的运算符放入 
	if (flag != 0)
	{
		p = new BinaryTreeNode<T>(s[pos]);
		p->left = InCreateTree(s, i, pos - 1);      //递归调用自身进入其左子树建树过程 
		p->right = InCreateTree(s, pos + 1, j);     //递归调用自身进入其右子树建树过程 
		return p;
	}
	else
		return NULL;
}

//后缀表达式建树
template <class T>
void ExpTFTree<T>::PostCreateTree()
{
	cout << "后缀表达式建树" << endl;
	cout << "后缀表达式:";
	cin >> s;

	int len = strlen(s);         //表达式长度
	int i;
	BinaryTreeNode<T>* p;
	//临时栈 - 用来存放指向树节点的指针
	struct stack
	{
		BinaryTreeNode<T> *vec[MaxSize];
		int top;
	};
	struct stack q;
	q.top = 0;

	//遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数
	//节点的指针,并指向该运算符节点并将其入栈
	for (i = 0; i < len; i++)
	{
		//为操作符 
		if (s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-')
		{
			p = new BinaryTreeNode<T>(s[i]);
			p->right = q.vec[q.top--];    //先弹出的为右节点 
			p->left = q.vec[q.top--];     //后弹出的为左节点 
			q.vec[++q.top] = p;           //将根节点入栈 
		}
		else
		{
			//s[i]为操作数 
			p = new BinaryTreeNode<T>(s[i]);
			q.vec[++q.top] = p;      //将指向操作数节点的指针入栈 
		}
	}

	root = q.vec[q.top--];        //这一步很关键,因为该二叉树的根节点最后被保留在了栈中 
}

//前序遍历
template <class T>
void ExpTFTree<T>::PerOrder(BinaryTreeNode<T>* root)
{
	if (root)
	{
		cout << root->data << " ";
		PerOrder(root->left);
		PerOrder(root->right);
	}
}

//中序遍历
template <class T>
void ExpTFTree<T>::InOrder(BinaryTreeNode<T>* root)
{
	if (root)
	{
		InOrder(root->left);
		cout << root->data << " ";
		InOrder(root->right);
	}
}

//后序遍历
template <class T>
void ExpTFTree<T>::PostOrder(BinaryTreeNode<T>* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		cout << root->data << " ";
	}
}

int main()
{
	ExpTFTree<char> A;
	char s[MaxSize];
	cout << "中缀表达式:";
	cin >> s;

	A.root = A.InCreateTree(s, 0, strlen(s) - 1);        //中缀表达式建树
	A.DispTree(A.root);

	cout << "前序周游:";
	A.PerOrder(A.root); cout << endl;  //前序周游

	cout << "中序周游: ";
	A.InOrder(A.root);  cout << endl;  //中序周游
	cout << "后序周游:";
	A.PostOrder(A.root); cout << endl; //后序周游

	A.PostCreateTree();     //后缀表达式建树
	A.DispTree(A.root);

	A.PerCreateTree();      //前缀表达式建树
	A.DispTree(A.root);    

	return 0;
}

运行结果:
中缀表达式:a+b*c-e/f
凹入表示法输出一棵二叉树
    - (r)------------------------------------------------
        + (0)----------------------------------------------
            a (0)--------------------------------------------
            * (1)--------------------------------------------
                b (0)------------------------------------------
                c (1)------------------------------------------
        / (1)----------------------------------------------
            e (0)--------------------------------------------
            f (1)--------------------------------------------
前序周游:- + a * b c / e f
中序周游: a + b * c - e / f
后序周游:a b c * + e f / -
后缀表达式建树
后缀表达式:abc*+ef/-
凹入表示法输出一棵二叉树
    - (r)------------------------------------------------
        + (0)----------------------------------------------
            a (0)--------------------------------------------
            * (1)--------------------------------------------
                b (0)------------------------------------------
                c (1)------------------------------------------
        / (1)----------------------------------------------
            e (0)--------------------------------------------
            f (1)--------------------------------------------
前缀表达式建树
前缀表达式:-+a*bc/ef
凹入表示法输出一棵二叉树
    - (r)------------------------------------------------
        + (0)----------------------------------------------
            a (0)--------------------------------------------
            * (1)--------------------------------------------
                b (0)------------------------------------------
                c (1)------------------------------------------
        / (1)----------------------------------------------
            e (0)--------------------------------------------
            f (1)--------------------------------------------
释放成功
请按任意键继续. . .

猜你喜欢

转载自blog.csdn.net/y_16041527/article/details/80017926