递归输出去括号的中缀表达式
1. 定义一棵简化的 Linked Binary Tree
1.1. Binary Tree Node
假设元素类型为 std::string
,
include 如下几个头文件.
#include <iostream>
#include <string>
先定义 Node.
元素类型为 std::string
struct binaryTreeNode
{
std::string element;
binaryTreeNode* leftChild, * rightChild;
// Constructor 1.
binaryTreeNode() { leftChild = rightChild = nullptr; }
// Constructor 2.
binaryTreeNode(const std::string& theElement) :
element(theElement), leftChild(nullptr), rightChild(nullptr) {}
// Constructor 3.
binaryTreeNode(const std::string& theElement, binaryTreeNode* theLeft, binaryTreeNode* theRight) :
element(theElement), leftChild(theLeft), rightChild(theRight) {}
};
1.2. Linked Binary Tree
再利用 binaryTreeNode
写一个简单的 linked binary tree.
这里初始化树的方法是用户输入以空格划分的树的前序遍历结果, 同时指出何处为 nullptr.
e.g.
假设指定了 "#" 表示 nullptr, 即将"#"
传入形参 stop.
用户输入:+ * 1 # # - 2 # # 3 # # / 4 # # 5 # #
;
所表示的表达式应为: 1*(2-3)+4/5 ;
其中 "+" 为树的 root.
class linkedBinaryTree
{
public:
// Constructor, initialize {root} with nullptr.
linkedBinaryTree() : root(nullptr) {};
// Get private member {root}.
binaryTreeNode* getRoot() const { return root; }
// Initialize the tree with pre-order-output string of an expression;
// {stop} indicates nullptr.
void createTree(binaryTreeNode* root, const std::string& stop)
{
std::string element;
std::cin >> element;
if (element == stop) { return; }
root = new binaryTreeNode(element);
createTree(root->leftChild, stop);
createTree(root->rightChild, stop);
}
private:
binaryTreeNode* root;
};
2. 输出去括号的中缀表达式
2.1. 两个辅助函数
判断元素是否为运算符.
inline bool isOperator(const std::string& op)
{
if (op == "+" || op == "-" || op == "*" || op == "/") { return true; }
return false;
}
返回运算符优先级.
运算符优先级按照这种特殊的方式设定值,
是考虑到将返回值 除以 2 后能形成一层新的 加减 与 乘除 的划分
inline int getOperPri(const std::string& op)
{
switch (op[0]) {
case '+': return 2;
case '-': return 3;
case '*': return 4;
case '/': return 5;
default: return -1;
}
}
2.2. 递归输出中缀表达式同时去括号
为了去括号, 递归的时候还要传入一个 prePri
, 表示上层的优先级.
顺手枚举个 direction
类型, 表示本层递归是前一层走哪个方向进来的.
具体实现并不复杂, 注释得比较清晰了.
关于加减遇到负数的变号, 实现起来也比较轻松, 大致方法写在注释里了.
enum direction { start = -1, left, right };
void infix(binaryTreeNode* t, int prePri, direction dir)
{
if (t == nullptr) { return; }
int curPri = 0; // Mark current operator priority (0 if element is a number).
bool flag = true; // <true> to print brakets; <false> not to.
if (isOperator(t->element)) { // IF current element is an operator.
curPri = getOperPri(t->element); // Get current priority.
if (dir == left) {
if (curPri / 2 >= prePri / 2) { flag = false; }
} else if (dir == right) {
if (curPri > prePri || curPri == prePri && !(prePri & 1)) { flag = false; }
} else { // IF {dir} is start, do not print brakets.
flag = false;
}
} else { // IF element is a number.
// IF the number is possitive, does not need brackets.
if (std::stoi(t->element) > 0) { flag = false; }
// If you wish, you can also add some codes here to change '+' and '-' operator when meeting a negative number.
// e.g. When the current element is <-3>, and {prePri} indicates that the operator before is '+';
// Send a signal back to last level with return value in order to change '+' to '-'.
}
if (flag) { std::cout << '('; }
// Recurse to left subtree.
infix(t->leftChild, curPri, left);
// Print element.
std::cout << t->element;
// Recurse to right subtree.
infix(t->rightChild, curPri, right);
if (flag) { std::cout << ')'; }
}
3. 方法使用示例
在 有 2.2. 中定义的枚举类型 direction
的情况下,
函数 void infix(binaryTreeNode* t, int prePri, direction dir)
的第四个参数必须是 direction
的变量 start
(表示递归第一层);
第三个参数 prePri
在 start
的限制下, 调用函数是可以传入任意值 (因为 prePri
在递归的第一层不会参与比较).
int main()
{
std::string stop;
std::cin >> stop; // User define {stop} to indicate nullptr.
linkedBinaryTree tree; // Define an empty tree.
tree.createTree(tree.getRoot(), stop); // Create the tree.
// Output the result.
// The 4th parameter must be <start>, while the 3rd does not matter.
infix(tree.getRoot(), 0, start);
system("pause");
}
4. 后记
潇潇给我的这题还挺有意思的.
深知目前自己的能力还非常不足. 哈哈.
不过 <欢迎来到实力至上主义的教室> 小说真的好看呢.
一之濑真好呀, 和天使一样!
第二季动画做的... 呃呃... 感觉不太好.
04/08/2022 17:37