[英]infix to prefix using C/C++ (without using stack)
In compiler designing they gave us a project to write an "infix to prefix" program using C/C++ but we are not allowed to use the stack method.在编译器设计中,他们给了我们一个项目来使用 C/C++ 编写“中缀前缀”程序,但我们不允许使用堆栈方法。 i know it is possible to reverse the postfix to get prefix but the problem is that the program that is written in the book to convert infix to postfix doesn't work.我知道可以反转后缀以获取前缀,但问题是书中编写的将中缀转换为后缀的程序不起作用。 this it the "infix to postfix" in the book这是书中的“后缀中缀”
#include <stdio.h>
#include <ctype.h>
#define NUM 256
#define NONE -1
int lineno = 1;
int tokenval = NONE;
int lexan()
{
int t,
while (1)
{
t = getchar();
if (t = = 0)
| | (t = = '\t');
else if (t = = '\n')
lineno = lineno + 1;
else if (isdigit(t)) {
tokenval = t - '0';
t = getchar();
while (isdigit(t)) {
tokenval = tokenval * 10 + t - '0';
t = getchar();
}
ungetc(t, stdin) return NUM;
}
else {
tokenval = NONE;
return t;
}
}
}
So, no build in stack is allowed.因此,不允许内置堆栈。
Then let us build a different container.然后让我们构建一个不同的容器。 I will show you a dynamic array, with some special functions, to我将向您展示一个具有一些特殊功能的动态数组
Because obviously you are not allowed to use a C++ standard container, I created this dynamic container, with dynamic memory handling in it.因为显然不允许使用 C++ 标准容器,所以我创建了这个动态容器,其中包含动态 memory 处理。 In normal life, you should never use such a thing, but C++ elements.在正常的生活中,你不应该使用这样的东西,而是 C++ 元素。
It could look like:它可能看起来像:
// This is the thing that we need for our operation
struct TheOtherThing {
char* data{};
unsigned int numberOfElements{};
unsigned int capacity{ 2 };
~TheOtherThing() { delete[] data; }
TheOtherThing() { data = new char[capacity]; }
void atAtEnd(const char c) {
// First check, if this element still fits on the TheOtherThing
if (numberOfElements >= capacity) {
// Oh no, TheOtherThing capacity is exhausted. Allocate new memory. Now with double the capacity than before
capacity = capacity * 2;
// Allocate new temporary, but bigger memory
char* temp = new char[capacity];
// Copy all data from old memory to new temporary memory
for (unsigned int k = 0; k < numberOfElements; ++k) {
temp[k] = data[k];
}
// Release memory from old data
delete[] data;
// And assign new temporary data to old pointer
data = temp;
}
// And now, after having done all this memory handling, store the value at the end of the dynamic array.
data[numberOfElements] = c;
// Remember that we have one more element on the TheOtherThing
++numberOfElements;
}
// Typical Needed functions to deal with TheOtherThing
bool hasData() const { return numberOfElements != 0; }
char lastElement() const { return (hasData() ? data[numberOfElements - 1] : '\0'); }
void removeFromEnd() { if (hasData()) --numberOfElements; }
char getAndRemoveFromEnd() { char result = '\0'; if (hasData()) { --numberOfElements; result = data[numberOfElements]; } return result; }
};
The attentive reader will notice that this is nothing but a stack.细心的读者会注意到,这不过是一个堆栈。
Infix to postfix is a rather simple operation.后缀中缀是一个相当简单的操作。
Totally simple.完全简单。
Code could then look like this:代码可能如下所示:
#include <string>
#include <iostream>
// This is the thing that we need for our operation
struct TheOtherThing {
char* data{};
unsigned int numberOfElements{};
unsigned int capacity{ 2 };
~TheOtherThing() { delete[] data; }
TheOtherThing() { data = new char[capacity]; }
void atAtEnd(const char c) {
// First check, if this element still fits on the TheOtherThing
if (numberOfElements >= capacity) {
// Oh no, TheOtherThing capacity is exhausted. Allocate new memory. Now with double the capacity than before
capacity = capacity * 2;
// Allocate new temporary, but bigger memory
char* temp = new char[capacity];
// Copy all data from old memory to new temporary memory
for (unsigned int k = 0; k < numberOfElements; ++k) {
temp[k] = data[k];
}
// Release memory from old data
delete[] data;
// And assign new temporary data to old pointer
data = temp;
}
// And now, after having done all this memory handling, store the value at the end of the dynamic array.
data[numberOfElements] = c;
// Remember that we have one more element on the TheOtherThing
++numberOfElements;
}
// Typical Needed functions to deal with TheOtherThing
bool hasData() const { return numberOfElements != 0; }
char lastElement() const { return (hasData() ? data[numberOfElements - 1] : '\0'); }
void removeFromEnd() { if (hasData()) --numberOfElements; }
char getAndRemoveFromEnd() { char result = '\0'; if (hasData()) { --numberOfElements; result = data[numberOfElements]; } return result; }
};
std::string infixToPostfix(std::string& infix) {
// Here we will store the resulting postfix expession
std::string postfix{};
// This we will use as a helper
TheOtherThing tot{};
// Check all characters of the infix expression in a loop
for (const char c : infix) {
// Handle all kind of characters
if (c >= '0' and c <= '9') postfix += c; // Digit, take as is
else if (c == '+' or c == '-' or c == '*' or c == '/' or c == '^') { // Check for operator
// If this charcter (and as long) has a lower precedence then the operator on the top of the thing
while (tot.hasData() and ( (c == '+' or c == '-') or ((c == '*' or c == '/') and (tot.lastElement() == '^'))))
// Then add it to the resulting string
postfix += tot.getAndRemoveFromEnd();
// Put new operator on the thing
tot.atAtEnd(c);
}
else std::cerr << "Error: Invalid character '" << c << "' found. Ignoring . . .\n";
}
// If there is still something on the thing
while (tot.hasData())
postfix += tot.getAndRemoveFromEnd();
// And return resulting postfix expression
return postfix;
}
int main() {
std::string infix{ "1+2-3*4/5^6" };
std::cout << "\n\nInfix: '" << infix << "' --> postfix: '" << infixToPostfix(infix) << "'\n\n";
}
But, even a simple string has the functionality of a stack.但是,即使是简单的字符串也具有堆栈的功能。 It has all necessary functions.它具有所有必要的功能。
So, we could also write:所以,我们也可以这样写:
#include <string>
#include <iostream>
std::string infixToPostfix(std::string& infix) {
// Here we will store the resulting postfix expession
std::string postfix{};
// This we will use as a helper
std::string tot{};
// Check all characters of the infix expression in a loop
for (const char c : infix) {
// Handle all kind of characters
if (c >= '0' and c <= '9') postfix += c; // Digit, take as is
else if (c == '+' or c == '-' or c == '*' or c == '/' or c == '^') { // Check for operator
// If this charcter (and as long) has a lower precedence then the operator on the top of the thing
while (not tot.empty() and ((c == '+' or c == '-') or ((c == '*' or c == '/') and (tot.back() == '^')))) {
// Then add it to the resulting string
postfix += tot.back();
tot.pop_back();
}
// Put new operator on the thing
tot.push_back(c);
}
else std::cerr << "Error: Invalid character '" << c << "' found. Ignoring . . .\n";
}
// If there is still something on the thing
while (not tot.empty()) {
postfix += tot.back();
tot.pop_back();
}
// And return resulting postfix expression
return postfix;
}
int main() {
std::string infix{ "1+2-3*4/5^6" };
std::cout << "\n\nInfix: '" << infix << "' --> postfix: '" << infixToPostfix(infix) << "'\n\n";
}
But, oh shock.但是,哦,震惊。 Since we are still on C and not on C++, we do not even have a std::string
.由于我们仍在 C 而不是 C++ 上,我们甚至没有std::string
。 But, luckily, we have our other thing, which is also a dynamic string.但是,幸运的是,我们还有另一个东西,它也是一个动态字符串。
With that and without any C++ container, we can have:有了它并且没有任何 C++ 容器,我们可以拥有:
#include <iostream>
// This is the thing that we need for our operation
struct TheOtherThing {
char* data{};
unsigned int numberOfElements{};
unsigned int capacity{ 2 };
~TheOtherThing() { delete[] data; }
TheOtherThing() { data = new char[capacity]; }
void atAtEnd(const char c) {
// First check, if this element still fits on the TheOtherThing
if (numberOfElements >= capacity) {
// Oh no, TheOtherThing capacity is exhausted. Allocate new memory. Now with double the capacity than before
capacity = capacity * 2;
// Allocate new temporary, but bigger memory
char* temp = new char[capacity];
// Copy all data from old memory to new temporary memory
for (unsigned int k = 0; k < numberOfElements; ++k) {
temp[k] = data[k];
}
// Release memory from old data
delete[] data;
// And assign new temporary data to old pointer
data = temp;
}
// And now, after having done all this memory handling, store the value at the end of the dynamic array.
data[numberOfElements] = c;
// Remember that we have one more element on the TheOtherThing
++numberOfElements;
}
// Typical Needed functions to deal with TheOtherThing
bool hasData() const { return numberOfElements != 0; }
char lastElement() const { return (hasData() ? data[numberOfElements - 1] : '\0'); }
void removeFromEnd() { if (hasData()) --numberOfElements; }
char getAndRemoveFromEnd() { char result = '\0'; if (hasData()) { --numberOfElements; result = data[numberOfElements]; } return result; }
void operator += (const char c) {
atAtEnd(c); }
};
void infixToPostfix(char* infix, TheOtherThing *postfix) {
// This we will use as a helper
TheOtherThing tot{};
char c;
// Check all characters of the infix expression in a loop
while (c = *infix++) { // Be very carefule here. That is dirty with side effect
// Handle all kind of characters
if (c >= '0' and c <= '9') *postfix += c; // Digit, take as is
else if (c == '+' or c == '-' or c == '*' or c == '/' or c == '^') { // Check for operator
// If this charcter (and as long) has a lower precedence then the operator on the top of the thing
while (tot.hasData() and ((c == '+' or c == '-') or ((c == '*' or c == '/') and (tot.lastElement() == '^'))))
// Then add it to the resulting string
*postfix += tot.getAndRemoveFromEnd();
// Put new operator on the thing
tot.atAtEnd(c);
}
else std::cerr << "Error: Invalid character '" << c << "' found. Ignoring . . .\n";
}
// If there is still something on the thing
while (tot.hasData())
*postfix += tot.getAndRemoveFromEnd();
*postfix += '\0';
}
int main() {
char infix[]="1+2-3*4/5^6";
TheOtherThing postfix{};
infixToPostfix(infix, &postfix);
std::cout << "\n\nInfix: '" << infix << "' --> postfix: '" << postfix.data << "'\n\n";
}
Nice?好的? Isn't it?不是吗?
The approach for converting an infix to a prefix expression is:将中缀转换为前缀表达式的方法是:
If you would be allowed to use a std::stack
, then things would be easy.如果允许您使用std::stack
,那么事情会很容易。 Converting the infix to postfix is a well know algorithm.将中缀转换为后缀是一种众所周知的算法。
Using a stack you would:使用堆栈,您将:
Rather simple.相当简单。
But, you have no stack.但是,你没有堆栈。
So, we need to use a different algorithm.所以,我们需要使用不同的算法。 Basically, we can use any array.基本上,我们可以使用任何数组。 But since we do not know in advance, how many elements are in the array, we will use something dynamic.但是由于我们事先不知道数组中有多少元素,我们将使用动态的东西。 Normally you could use a std::vector
or a std::deque
or similar.通常你可以使用std::vector
或std::deque
或类似的。 Even a `std::string has´ all the functionality that you need.即使是 `std::string` 也有你需要的所有功能。
You always need the same functionality fromsuch a container您总是需要来自此类容器的相同功能
We can easily create a small class that fulfils all of the above requirements.我们可以轻松创建满足上述所有要求的小型 class。 It can be used to store dynamic length strings and also other data.它可用于存储动态长度字符串以及其他数据。 The mechanism is the same.机制是一样的。
Basic functionality:基本功能:
new
.如果需要 memory,我们通过new
分配新的 memory。 (And we double the capacity) (我们将容量翻倍)Putting things together, one of many possible solutions could be like the below把事情放在一起,许多可能的解决方案之一可能如下所示
#include <iostream>
// This is a dynamic array that we need for our operation
class DynamicArray {
private:
// This is a pointer to the dynmic allocated char array
char* data{};
// This is the number of Elements that are currently stored in our dynamic array
unsigned int numberOfElements = 0;
// This is the capacity of our dyanmic array. So many elements can be strored without any reallocation
unsigned int capacity = 8;
// Some helpwer functions for swapping 2 data
void swap(char& c1, char& c2) { char temp = c1; c1 = c2; c2 = temp; }
public:
// --------------------------------------------------------------------------------------------------------
// Constructor / destructor
//
// Default constructor
DynamicArray() { data = new char[capacity]; }
// Copy contructor. Copy data from other dynamic array
DynamicArray(const DynamicArray& da) { data = new char[capacity]; for (unsigned int i = 0; i < da.numberOfElements; ++i) *this += da.data[i]; };
// Special constructor to copy data from a C-style string
DynamicArray(const char* str) {data = new char[capacity]; for (unsigned int i = 0; str[i] != '\0'; ++i) *this += str[i]; };
// The destructor will release the dynamically allocated memory
~DynamicArray() { delete[] data; }
// --------------------------------------------------------------------------------------------------------
// Typical needed functions to deal with DynamicArray
// We will use this function to add data to our dynamic array. Here dynamic memory management will be done
void addAtEnd(const char c);
// Check, if we have data stored at allo in our dynmic array
bool hasData() const { return numberOfElements != 0; }
// Get a copy of the last element in the dynamic array
char lastElement() const { return (hasData() ? data[numberOfElements - 1] : '\0'); }
// Remove the last element from the dynamic array. In reality we will remove nothing, but just decrease the number of elements
void removeFromEnd() { if (hasData()) --numberOfElements; }
// Make a copy of the last element and then remove the last element
char getAndRemoveFromEnd() { char result = '\0'; if (hasData()) { --numberOfElements; result = data[numberOfElements]; } return result; }
// Reverse the data in the internal respresentation of or dynamic memory
void reverse() { for (unsigned int k = 0; k < numberOfElements / 2; ++k) swap(data[k], data[numberOfElements-k-1]); }
// Indicates, how many elements are currently stored in our dynamic array
unsigned int length() const { return numberOfElements; }
// --------------------------------------------------------------------------------------------------------
// Overwrite some operators for easier handling
// Index operator. Access element at position k. Attention: No range check
char& operator [](unsigned int k) { return data[k]; }
// Assignment operator for a whole dynamic array
DynamicArray& operator = (DynamicArray& t) {this->numberOfElements = 0; for (unsigned int k = 0; k < t.numberOfElements; ++k) *this += t.data[k]; return*this; }
// operator to add element at end. Convinience function
void operator += (const char c) { addAtEnd(c); }
// Output the data to a stream
friend std::ostream& operator << (std::ostream& os, const DynamicArray& t) { for (unsigned int k = 0; k < t.numberOfElements; ++k) std::cout << t.data[k]; return os; }
};
void DynamicArray::addAtEnd(char c) {
// First check, if this element still fits on the DynamicArray
if (numberOfElements >= capacity) {
// Oh no, DynamicArray capacity is exhausted. Allocate new memory. Now with double the capacity than before
capacity = capacity * 2;
// Allocate new temporary, but bigger memory
char* temp = new char[capacity];
// Copy all data from old memory to new temporary memory
for (unsigned int k = 0; k < numberOfElements; ++k) {
temp[k] = data[k];
}
// Release memory from old data
delete[] data;
// And assign new temporary data to old pointer
data = temp;
}
// And now, after having done all this memory handling, store the value at the end of the dynamic array.
data[numberOfElements] = c;
// Remember that we have one more element on the DynamicArray
++numberOfElements;
}
// --------------------------------------------------------------------------------
// Main conversion function
void infixToPrefix(DynamicArray& infix, DynamicArray *prefix) {
// This we will use as a helper
DynamicArray da{};
char c;
// ---------------------------------------------------------------------------
// 1. We want toreverse the string given as input
DynamicArray infixReversed( infix );
infixReversed.reverse();
// Invert brackets: Exchange '(' and ')', becuase we reversed the string
for (unsigned int k = 0; k < infixReversed.length(); ++k) {
if (infixReversed[k] == '(') infixReversed[k] = ')';
else if (infixReversed[k] == ')') infixReversed[k] = '(';
}
// ---------------------------------------------------------------------------
// 2. Convert to postfix
// Here we will store the the resultr of post fix expression
DynamicArray postfix;
// Check all characters of the reveresed infix expression in a loop
for (unsigned int k = 0; k < infixReversed.length(); ++k) {
// Get current character
c = infixReversed[k];
// Handle all kind of characters
if (c == ' ') continue; // Ignore spaces
// Literal, take as is
if ((c >= '0' and c <= '9') or (c>='A' and c <= 'Z') or (c >= 'a' and c <= 'z')) postfix += c;
else if (c == '(') da.addAtEnd(c); // Opening bracket, store
else if (c == ')') { // Find matching opening bracket
while (da.hasData() and (da.lastElement() != '('))
postfix += da.getAndRemoveFromEnd();
da.removeFromEnd();
}
else if (c == '+' or c == '-' or c == '*' or c == '/' or c == '^') { // Check for operator
// If this character (and as long as) has a lower precedence then the last operator strored in our dynamic array
while (da.hasData() and (da.lastElement() != '(') and ((c == '+' or c == '-') or ((c == '*' or c == '/') and (da.lastElement() == '^'))))
// Then add it to the resulting string
postfix += da.getAndRemoveFromEnd();
// Store new operator at the end of the dynamic array
da.addAtEnd(c);
} // Ignore all invalid characters
else std::cerr << "Error: Invalid character '" << c << "' found. Ignoring . . .\n";
}
// If there is still data in our dynamic array, then remove it and add to output
while (da.hasData())
postfix += da.getAndRemoveFromEnd();
// ---------------------------------------------------------------------------
// 3. Reverse the postfix expression to get the prefix expression
// Reverse the data
postfix.reverse();
// And copy to output parameter
*prefix = postfix;
}
// Test
int main() {
DynamicArray infix ("1 + ( 2 - 3) * 4 / 5 ^ 6");
DynamicArray prefix{};
infixToPrefix(infix, &prefix);
std::cout << "\n\nInfix: '" << infix << "' --> prefix: '" << prefix << "'\n\n";
}
Of course this is for a 1 digit (letter) length only.当然,这仅适用于 1 位(字母)长度。 But can be easily adapted.但可以很容易地适应。
Have fun.玩得开心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.