后缀表达式转换为中缀表达式

yzl14 2015-10-18 05:09:37
是一道作业题,在OJ平台上提交,有效率要求。OJ平台会进行十次测试。我的第一个版本是C++写的,主要用string类型,只能通过七次,同学都说string类型可能效率不够高。第二个版本用C写,我自己在VS2015上运行没问题,但是到OJ平台上却一次也通不过。要知道前三次都是很简单情形,只要程序正确就应该没错,可能是一些内存访问操作在平台上被判为非法。求前辈们帮忙改一下,指出一下问题或者效率改进方案。在这个题上耗了两天多了。初学者。
对了有同学说C用realloc好像通不过,那不用realloc该怎么改呢?
谢谢!

题目:中缀表达式与后缀表达式

Description

将一个后缀表达式转换为一个中缀表达式。
Input Description

一个合法的后缀表达式。它由一串连续的操作数与运算符的序列构成。操作数用英文小写字母表示,且运算符只有五种,每个运算符只有一种符号表示。相邻的操作数与运算符之间均没有任何分隔符。

输入中会出现的运算符
运算符 符号 优先级 备注
阶乘 ! 高 一元运算符
乘号 * 中
除号 / 中
加号 + 低
减号 - 低
Output Description

一个中缀表达式,它由一串连续的操作数与操作符的序列构成,它与输入的后缀表达式表达同一个算术表达式。由于中缀表达式会遇到运算符的优先级问题,你需要适当地插入左括号和右括号来调整运算的优先级。输出中允许出现的运算符有七种,每个运算符只有一种符号表示。除了操作数和运算符不允许输出任何空格、换行等分隔符。

输出中允许出现的运算符
运算符 符号 优先级 备注
左括号 ( 最高
右括号 ) 最高 与左括号搭配使用
阶乘 ! 高 一元运算符
乘号 * 中
除号 / 中
加号 + 低
减号 - 低
为了减少括号的数量以及保证输出唯一性,我们要求你尽可能地避免括号的使用,除非这样做将改变表达式中某些运算的发生次序。特别要注意,左右操作数的顺序是不可改变的,我们认为 a + b 和 b + a 是不同的表达式。对于满足 结合律的运算,运算发生次序不变的情况下应该省略括号,否则不能省略括号:我们认为 (a + b) + c 与 a + b + c 是同样的表达式,而 a + (b + c) 与 a + b + c是不同的。例如: (a + b) + (c + d) 中,如果删除第一对括号,运算结果和运算次序都没有变化;如果删除第二对括号,运算结果没有变化,但是 a + b 会首先与 c 相加,导致运算次序变化。所以这种情况下应该输出 a + b + (c + d)。

Input Sample

ab+cde*f*+fd+qp-!*-+

Output Sample

a+b+(c+d*e*f-(f+d)*(q-p)!)
Hint

你可以将生成的中缀表达式转换回后缀表达式,以验证中缀表达式的正确性。 请你自行想办法验证它是否是括号最少而不影响运算次序的结果。

我的两个版本:
c++版本:
#include<iostream>
#include<string>
//#define STACK_SIZE 7000//栈的大小,可以容纳1000个表达式 使用宏定义全局变量,方便修改
//#define StringNode_SIZE 7000//StringNode 类对象中的字符串数组大小
using namespace std;
// 定义栈的数据结构。
int JudgePriority(char c);//向前引用声明 判断运算符c的优先级
int Length;//全局变量
class StringNode {//Stringnode节点,存储每一个表达式及其优先级
private:
string STring;
int priority;//优先级
public:
StringNode() {
// STring = "\0";
priority = 10;//默认初始状态
}
StringNode(char Char1) {//单个字符建立对象,只有字母是需要这种情况
STring = Char1;
priority = 4;//设定字母优先级为4,是最高,括号4与单个字母等价,阶乘3
}
StringNode(string ExpressionString, int Priority1) {//表达式字符串建立对象
// STring.at(0) = '\0';//防止栈访问出错
STring = ExpressionString;
priority = Priority1;
}
friend StringNode Compose(StringNode &SN1, char Operator, StringNode &SN2) {//由两个表达式和一个运算符组成一个新的表达式 加括号也是在这一步
AutoAddBrackets(SN1, Operator, SN2);//如果需要的话自动给SN1,2加括号
return StringNode(SN1.STring + Operator + SN2.STring, JudgePriority(Operator));
}
friend StringNode Compose(StringNode &SN1, char Operator) {//由一个表达式和一个单目运算符(!)组成一个新的表达式 加括号也是在这一步
AutoAddBrackets(SN1, Operator);//如果需要的话自动给SN1加括号
SN1.STring += Operator;
return StringNode(SN1.STring, 3);//这个运算符的优先级就给了合成的表达式(必然是阶乘的3)
}
friend void AutoAddBrackets(StringNode &SN1, char Operator, StringNode &SN2) {//使用引用!为了修改实参
if (SN1.priority >= JudgePriority(Operator) && JudgePriority(Operator) >= SN2.priority) {
SN2.AddBrackets();return;
}
else if (SN1.priority == 1 && (Operator=='*'|| Operator == '/') && SN2.priority >= 3) {
SN1.AddBrackets();return;
}
else if (SN1.priority == 1 && (Operator == '*' || Operator == '/') && SN2.priority <= 2) {
SN1.AddBrackets();SN2.AddBrackets();return;
}
else//两边都不加括号情况,最多
return;
}
friend void AutoAddBrackets(StringNode &SN1, char Operator) {
if (SN1.priority<3 ) {//如果是!
SN1.AddBrackets();
}
}
void AddBrackets() {
STring = STring.insert(0,1,'(') + ")";
priority = 4;//加括号以后,优先级变得和数字一样高
}
void PrintString() {//输出本对象中的STring字符串
cout << STring;
}
};
class Stack {
private:
StringNode *Buffer; //保存栈中的数据,指向栈首
int top; //栈的深度
public:
Stack(int Len) {
Buffer = new StringNode[Len];//这个数组只能用Buffer来指示,不能起一个数组名
top = 0;//初始没有元素,top指代第零个
}
void push(StringNode val) { //压栈操作
Buffer[top++] = val;
}
StringNode pop() { //出栈操作
top--;//由于top总是指向下一个还没有值的位置,因此先要把top后退一位
return Buffer[top];
}
void PrintStack() {//最终的输出
Buffer[0].PrintString();
}
};
bool IsCharacter(char c) {//判字母函数
return c >= 'a'&&c <= 'z';
}
bool IsBiOperator(char c) {//判二元运算符
return c == '+' || c == '*' || c == '/' || c == '-';
}
bool IsSingleOperator(char c) {//判一元运算符(!)
return c == '!';
}
int JudgePriority(char c) {//返回操作符号的优先级
if (c == '+' || c == '-')//if判断必须加括号,return可以不用
return 1;
else if (c == '*' || c == '/')
return 2;
else if (c == '!')
return 3;
else
return 10;//出错情况
}
int main()
{
int c = 0;//用于一个一个读取字符
string Str;
cin >> Str;
Length = Str.size();
Stack StackObject(Length);//建立栈对象
while (c < Str.size()) {//通过c读取一个字符
if (IsCharacter(Str.at(c))) {//如果是字母就入栈
StackObject.push(StringNode(Str.at(c)));
}
else if (IsBiOperator(Str.at(c))) {//如果是二目运算符,出栈两个节点后合成再入栈
StringNode TempSN1 = StackObject.pop();
StringNode TempSN2 = StackObject.pop();//注意出栈后的顺序
StackObject.push(Compose(TempSN2, Str.at(c), TempSN1));//2在前面
}
else if (IsSingleOperator(Str.at(c))) {//如果是一目运算符
StringNode TempSN = StackObject.pop();
StackObject.push(Compose(TempSN, Str.at(c)));
}
c++;
}
StackObject.PrintStack();
}

c版本:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Node {
char NodeChar;
struct Node *next;//每个节点存储一个字符和指向下一个节点的指针
};
struct HeadNode {//头结点记录表达式信息,有指向后续节点的头指针,后续节点数(字符数),以及表达式的优先级。一个头结点后面跟着一串结点链表代表一个表达式
struct Node *head;
int CharNum;
int priority;
};
void Bracket(struct HeadNode *H) {//给头结点指针H指向的头结点表示的表达式加括号
int i;
struct Node *p = (*H).head;
struct Node *q;
for (i = 0;i < ((*H).CharNum) - 1;i++) {//一直把p移动到尾节点的前一个节点(指向尾节点)
p = p->next;
}
p->next = malloc(sizeof(struct Node));//尾指针新开辟一个节点
p = p->next;//p指向这个新的尾节点
(*p).NodeChar = ')';//尾节点上的字符时右括号
p->next = NULL;//尾节点的尾指针为NULL
q = malloc(sizeof(struct Node));//用一个指向节点的指针q申请一个节点
q->next = (*H).head;
q->NodeChar = '(';
H->head = q;
(H->CharNum) += 2;
H->priority = 4;
}
void AddChar(struct HeadNode *H, char c) {
int i;
struct Node *p = (*H).head;
for (i = 0;i < (*H).CharNum - 1;i++) {//只移动到上一项,这样才能修改指针的值
p = p->next;
}
p->next = malloc(sizeof(struct Node));//这样才能真正改动Stack数组中的值
p = p->next;
p->NodeChar = c;
p->next = NULL;
(H->CharNum)++;
if (c == '+' || c == '-') {
H->priority = 1;
}
else if (c == '*' || c == '/') {
H->priority = 2;
}
else if (c == '!') {
H->priority = 3;
}
}
void Merge(struct HeadNode *H1, struct HeadNode *H2) {
int i;
struct Node *p = (*H1).head;
struct Node *q;
for (i = 0;i < (*H1).CharNum - 1;i++) {
p = p->next;
}
p->next = H2->head;
(H1->CharNum) = (H1->CharNum) + (H2->CharNum);
free(H2);
}
void DeleteHeadNode(struct HeadNode *H) {
struct Node *j = (*H).head;
struct Node *q = (*H).head;
int i = (*H).CharNum;

for (;i > 0;i--) {
q = q->next;
free(j);
j = q;
}
free(H);

}
main() {
int i;
char c;
struct HeadNode ** Stack = NULL;
int top = 0;
while (c = getchar()) {//getchar连回车都读入
if (c == '\n')
break;
if (c >= 'a'&&c <= 'z') {
struct HeadNode *H = malloc(sizeof(struct HeadNode));
if (H) {
H[0].priority = 4;
H[0].head = malloc(sizeof(struct Node));
H[0].CharNum = 1;
H[0].head->NodeChar = c;
H[0].head->next = NULL;
if (!Stack) {
Stack = malloc(sizeof(struct HeadNode *));
}
else {
Stack = realloc(Stack, sizeof(struct HeadNode *)*(top+1));
}
Stack[top] = H;
top++;
}
else {
exit(0);
}
}
else if (c == '!') {
int i;
struct Node *p = (*(Stack[top - 1])).head;
if ((*(Stack[top - 1])).priority < 3) {
Bracket(Stack[top - 1]);
}
AddChar(Stack[top - 1], '!');
}
else {
int cc;
if (c == '+' || c == '-')
cc = 1;
else if (c == '*' || c == '/')
cc = 2;
if ((*(Stack[top - 2])).priority == 1 && (*(Stack[top - 1])).priority <= 2 && cc == 2) {
Bracket(Stack[top - 2]);
Bracket(Stack[top - 1]);
AddChar(Stack[top - 2], c);
Merge(Stack[top - 2], Stack[top - 1]);
top--;
}
else if ((*(Stack[top - 2])).priority >= cc&&cc >= (*(Stack[top - 1])).priority) {
Bracket(Stack[top - 1]);
AddChar(Stack[top - 2], c);
Merge(Stack[top - 2], Stack[top - 1]);
top--;
}
else if ((*(Stack[top - 2])).priority < cc&&cc < (*(Stack[top - 1])).priority) {
Bracket(Stack[top - 2]);
AddChar(Stack[top - 2], c);
Merge(Stack[top - 2], Stack[top - 1]);
top--;
}
else {
AddChar(Stack[top - 2], c);
Merge(Stack[top - 2], Stack[top - 1]);
top--;
}
}
}
struct Node *pp = (*(Stack[0])).head;
for (i = 0;i < (*(Stack[0])).CharNum;i++, pp = pp->next) {
printf("%c", pp->NodeChar);
}
DeleteHeadNode(Stack[0]);
}
...全文
4376 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
楼主最后是怎么改的?能否贴一下代码
yzl14 2015-10-24
  • 打赏
  • 举报
回复
引用 6 楼 mLee79 的回复:
这样应该够快, 就是内存多用点 ...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#define MAX_INPUT_SIZE (1 << 12)
#define MAX_STACK_SIZE (MAX_INPUT_SIZE / 2 + 64)

enum {
kET_Atom,
kET_High,
kET_Mid,
kET_Low
};

typedef struct
{
int kExprType, kExprLen;
char kExprValue[2*MAX_INPUT_SIZE - 2*sizeof(int)];
} ST_expr;

int solve(const char* input_expr, ST_expr* stack)
{
int top = 0, c;
ST_expr *curr, *left, *right;

while(0 != (c = *input_expr++))
{
assert(top >= 0);

if(top >= MAX_STACK_SIZE - 1)
return -2;

switch(c)
{
case ' ':
case '\t':
case '\r':
case '\n':
case '\f':
/* ignore space */
break;

case '+':
case '-':
if(top < 2) return -1;
left = curr = &stack[top - 2];
right = &stack[top - 1];
--top;

curr->kExprValue[curr->kExprLen++] = c;
if(right->kExprType == kET_Low)
{
curr->kExprValue[curr->kExprLen++] = '(';
memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
curr->kExprLen += right->kExprLen;
curr->kExprValue[curr->kExprLen++] = ')';
}
else
{
memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
curr->kExprLen += right->kExprLen;
}
curr->kExprValue[curr->kExprLen] = 0;
curr->kExprType = kET_Low;
break;

case '*':
case '/':
if(top < 2) return -1;
left = curr = &stack[top - 2];
right = &stack[top - 1];
--top;

if(curr->kExprType == kET_Low)
{
memmove(curr->kExprValue + 1, curr->kExprValue, curr->kExprLen);
curr->kExprValue[0] = '(';
curr->kExprValue[1 + curr->kExprLen] = ')';
curr->kExprLen += 2;
}

curr->kExprValue[curr->kExprLen++] = c;
if(right->kExprType >= kET_Mid)
{
curr->kExprValue[curr->kExprLen++] = '(';
memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
curr->kExprLen += right->kExprLen;
curr->kExprValue[curr->kExprLen++] = ')';
}
else
{
memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
curr->kExprLen += right->kExprLen;
}
curr->kExprValue[curr->kExprLen] = 0;
curr->kExprType = kET_Mid;
break;

case '!':
if(top < 1) return -1;
curr = &stack[top - 1];

if(curr->kExprType >= kET_Mid)
{
memmove(curr->kExprValue + 1, curr->kExprValue, curr->kExprLen);
curr->kExprValue[0] = '(';
curr->kExprValue[1 + curr->kExprLen] = ')';
curr->kExprValue[2 + curr->kExprLen] = '!';
curr->kExprLen += 3;
}
else
{
curr->kExprValue[curr->kExprLen++] = '!';
}

curr->kExprValue[curr->kExprLen] = 0;
curr->kExprType = kET_High;
break;

default:
stack[top].kExprLen = 1;
stack[top].kExprType = kET_Atom;
stack[top].kExprValue[0] = c;
stack[top].kExprValue[1] = 0;
++top;
break;
}
}

return top;
}

int main()
{
int err = 0, r;
char* input_expr;
ST_expr* stack;

input_expr = (char*)calloc(1, MAX_INPUT_SIZE + 16);
stack = (ST_expr*)malloc(sizeof(ST_expr)*MAX_STACK_SIZE);

while(NULL != fgets(input_expr, MAX_INPUT_SIZE, stdin))
{
r = solve(input_expr, stack);
switch(r)
{
case 0:
/* empty line */
break;

case 1:
printf("%s\n", stack[0].kExprValue);
break;

default:
fprintf(stderr, "%d, ERROR(%d): %s\n", ++err, r, input_expr);
}
}

free(input_expr);
free(stack);

return err;
}

嘻嘻,您的方法通过了前四个,挂了后六个测试,可能是哪里没太符合题目要求的细节吧,还是感谢啦!我用同学的方法通过了
yzl14 2015-10-20
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
stack overflow! 我猜。
为啥溢出?
mLee79 2015-10-20
  • 打赏
  • 举报
回复
这样应该够快, 就是内存多用点 ...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#define MAX_INPUT_SIZE		(1 << 12)
#define MAX_STACK_SIZE		(MAX_INPUT_SIZE / 2 + 64)

enum {
	kET_Atom,
	kET_High,
	kET_Mid,
	kET_Low
};

typedef struct
{
	int		kExprType, kExprLen;
	char	kExprValue[2*MAX_INPUT_SIZE - 2*sizeof(int)];
} ST_expr;

int solve(const char* input_expr, ST_expr* stack)
{
	int top = 0, c;
	ST_expr *curr, *left, *right;

	while(0 != (c = *input_expr++))
	{
		assert(top >= 0);

		if(top >= MAX_STACK_SIZE - 1)
			return -2;

		switch(c)
		{
		case ' ':
		case '\t':
		case '\r':
		case '\n':
		case '\f':
			/* ignore space */
			break;

		case '+':
		case '-':
			if(top < 2)	return -1;
			left  = curr = &stack[top - 2];
			right = &stack[top - 1];
			--top;

			curr->kExprValue[curr->kExprLen++] = c;
			if(right->kExprType == kET_Low)
			{
				curr->kExprValue[curr->kExprLen++] = '(';
				memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
				curr->kExprLen += right->kExprLen;
				curr->kExprValue[curr->kExprLen++] = ')';
			}
			else
			{
				memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
				curr->kExprLen += right->kExprLen;
			}
			curr->kExprValue[curr->kExprLen] = 0;
			curr->kExprType = kET_Low;
			break;

		case '*':
		case '/':
			if(top < 2)	return -1;
			left  = curr = &stack[top - 2];
			right = &stack[top - 1];
			--top;

			if(curr->kExprType == kET_Low)
			{
				memmove(curr->kExprValue + 1, curr->kExprValue, curr->kExprLen);
				curr->kExprValue[0] = '(';
				curr->kExprValue[1 + curr->kExprLen] = ')';
				curr->kExprLen += 2;
			}

			curr->kExprValue[curr->kExprLen++] = c;
			if(right->kExprType >= kET_Mid)
			{
				curr->kExprValue[curr->kExprLen++] = '(';
				memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
				curr->kExprLen += right->kExprLen;
				curr->kExprValue[curr->kExprLen++] = ')';
			}
			else
			{
				memcpy(curr->kExprValue + curr->kExprLen, right->kExprValue, right->kExprLen);
				curr->kExprLen += right->kExprLen;
			}
			curr->kExprValue[curr->kExprLen] = 0;
			curr->kExprType = kET_Mid;
			break;

		case '!':
			if(top < 1)	return -1;
			curr = &stack[top - 1];

			if(curr->kExprType >= kET_Mid)
			{
				memmove(curr->kExprValue + 1, curr->kExprValue, curr->kExprLen);
				curr->kExprValue[0] = '(';
				curr->kExprValue[1 + curr->kExprLen] = ')';
				curr->kExprValue[2 + curr->kExprLen] = '!';
				curr->kExprLen += 3;
			}
			else
			{
				curr->kExprValue[curr->kExprLen++] = '!';
			}

			curr->kExprValue[curr->kExprLen]   = 0;
			curr->kExprType = kET_High;
			break;

		default:
			stack[top].kExprLen   = 1;
			stack[top].kExprType  = kET_Atom;
			stack[top].kExprValue[0] = c;
			stack[top].kExprValue[1] = 0;
			++top;
			break;
		}
	}

	return top;
}

int main()
{
	int err = 0, r;
	char*		input_expr;
	ST_expr*	stack;

	input_expr = (char*)calloc(1, MAX_INPUT_SIZE + 16);
	stack	   = (ST_expr*)malloc(sizeof(ST_expr)*MAX_STACK_SIZE);

	while(NULL != fgets(input_expr, MAX_INPUT_SIZE, stdin))
	{
		r = solve(input_expr, stack);
		switch(r)
		{
		case 0:
			/* empty line */
			break;

		case 1:
			printf("%s\n", stack[0].kExprValue);
			break;

		default:
			fprintf(stderr, "%d, ERROR(%d): %s\n", ++err, r, input_expr);
		}
	}

	free(input_expr);
	free(stack);

	return err;
}

赵4老师 2015-10-19
  • 打赏
  • 举报
回复
stack overflow! 我猜。
yzl14 2015-10-18
  • 打赏
  • 举报
回复
引用 1 楼 ri_aje 的回复:
1. profile 一下,看看到底慢在哪里。 2. 如果确实是 string 慢,再想办法,比如用 string_view 之类的技术。
不好意思,技术小白,profile和string_view都不会啊
ri_aje 2015-10-18
  • 打赏
  • 举报
回复
1. profile 一下,看看到底慢在哪里。 2. 如果确实是 string 慢,再想办法,比如用 string_view 之类的技术。
中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素中缀表达式转换后缀表达式,删除堆栈元素

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧