学习了数据结构的第三章二叉树后,实验是用二叉树来储存表达式。
首先是类的定义。
struct Node{
char ch; //结点存储数字或者运算符
Node* lchild;
Node* rchild;
};
class BinaryTree {
private:
Node* root;
public:
Node* getroot(); //获得根节点
BinaryTree(); //构造函数
void destoryTree(Node* bt); //销毁树
void preOrder(Node* bt); //前序遍历
void inOrder(Node* bt); //中序遍历
void postOrder(Node* bt); //后序遍历
};
然后是类函数的实现。
Node* BinaryTree::getroot() {
return this->root;
}
BinaryTree::BinaryTree() {
this->root = new Node;
root->ch = '0';
root->lchild = nullptr;
root->rchild = nullptr;
}
void BinaryTree::preOrder(Node* bt) {
if (bt == nullptr)
return;
else {
cout << bt->ch;
preOrder(bt->lchild);
preOrder(bt->rchild);
}
}
void BinaryTree::inOrder(Node* bt) { //用中缀形式输出表达式
if (bt == nullptr)
return;
else {
if (!isNumber(bt->ch))
cout << "("; //添加左括号
inOrder(bt->lchild);
cout << bt->ch;
inOrder(bt->rchild);
if (!isNumber(bt->ch))
cout << ")"; //添加右括号
}
}
void BinaryTree::postOrder(Node* bt) {
if (bt == nullptr)
return;
else {
postOrder(bt->lchild);
postOrder(bt->rchild);
cout << bt->ch;
}
}
void BinaryTree::destoryTree(Node* bt) {
Node* lTree = bt->lchild;
Node* rTree = bt->rchild;
delete bt;
if(lTree != nullptr)
destoryTree(lTree);
if(rTree != nullptr)
destoryTree(rTree);
return;
}
然后是判断字符是否是数字的函数和判断运算符优先级的函数。
bool isNumber(char ch) {
return (ch > 47 && ch < 58);
}
bool isPrior(char a, char b) {
//1.任何运算符优先级高于(2.当a是乘除且b是加减时算优先级高
return (b == '(' || ((a == '*' || a == '/') && (b == '+' || b == '-')));
}
要用二叉树储存表达式,首先需要将中缀表达式转化为逆波兰式,这里只实现了简单的功能,即数字只可以是0~9。
std::queue<char> toRPN(char* array) {
int i = 0;
int cnt = 0; //字符个数
while (array[i++] != '\0') //记录输入了几个字符
cnt++;
std::stack<char> stk; //转化时用栈储存暂时数据
std::queue<char> RPN; //RPN队列用于储存最后的逆波兰式
i = 0; //重置i
for (i = 0; i < cnt; i++) {
if (isNumber(array[i])) //c是数字时直接入队
RPN.push(array[i]);
else if (array[i] == '(') //c是(时入栈
stk.push(array[i]);
else if (array[i] == ')') { //c是)时,将()中的字符逐个出栈入队
while (stk.top() != '(') {
RPN.push(stk.top());
stk.pop();
}
stk.pop(); //最后将(出栈
}
else { //c是运算符时
if (!stk.empty() && !isPrior(array[i], stk.top())) { //栈不空且当前运算符优先级低时
while (!isPrior(array[i], stk.top())) { //循环出栈直到当前运算符优先级高于栈顶
RPN.push(stk.top());
stk.pop();
if (stk.empty()) //栈空时停止出栈
break;
}
}
stk.push(array[i]); //栈为空或当前运算符优先级高时直接入栈,否则循环后入栈
}
}
while (!stk.empty()) { //将栈中剩下的字符入队
RPN.push(stk.top());
stk.pop();
}
return RPN;
}
将toRPN返回的队列转化成二叉树:
BinaryTree creatTree(std::queue<char> RPN) {
BinaryTree* TreeArray = new BinaryTree[RPN.size()]; //把每个字符储存为一棵只有根的树
int cnt = RPN.size(); //字符数
std::stack<BinaryTree> NodeStk; //结点栈
for (int i = 0; i < cnt; i++) {
TreeArray[i].getroot()->ch = RPN.front(); //出队字符赋给当前结点
if (!isNumber(RPN.front())) { //c是数字时直接入栈,否则进行如下操作
//逆波兰式的第一个数字是左操作数,第二个数字是右操作数
TreeArray[i].getroot()->rchild = NodeStk.top().getroot(); //栈顶的结点作为右孩子
NodeStk.pop();
TreeArray[i].getroot()->lchild = NodeStk.top().getroot(); //然后作为左孩子
NodeStk.pop();
}
NodeStk.push(TreeArray[i]); //所有循环后栈中只剩一个结点
RPN.pop();
}
BinaryTree tree = NodeStk.top(); //将最后的结点作为根结点构造树
NodeStk.pop();
return tree;
}