首先是写栈的习惯:一定要在创建完栈后 就立即写上销毁栈的函数 否则很容易遗忘销毁 导致内存泄露
在唐老师讲的符号配对检测的程序时 有一个小细节 老师并没有提出来 但是后来发现了 :
char* c = (char*)LinkStack_Pop(stack);
//进行检测 格外注意 一定要先c==NULL
if( (c == NULL) || !match(*c,code[i]) )
{
printf("is error");
ret = 0;
break;
}
所以导致不发找到该地址 最终导致程序崩溃;
然后是计算器的运行:人类习惯的运算式是中缀表达式例如: 3+5、3+4+4、3*(3+3)*4;
而机器习惯的运算表达式是:35+,34+4+;等等
以下是唐老师给出的例子:
中缀表达式:后缀表达式:
5 + 3 =5 3 +
1 + 2 * 3 = 1 2 3 * +
9 + ( 3 – 1 ) * 5= 9 3 1 – 5 * +
而如何将人们习惯的中缀表达式转成后缀表达式呢??这个老师给出了答案:
而计算机又是如何对后缀表达式进行运算的呢??这个老师也给出了答案:
对于顺序链表唐老师用的是链表的尾作为栈顶,而普通的链表做栈是用的是表头作为栈顶;
我觉得对于顺序链表表尾作为栈顶很正确,毕竟顺序链表是数组,如果以表头作为栈顶,在进行插入的时候,要将所有数据都进行后移,这样过于浪费运行时间
而用普通的链表作为栈时,用表头或者标尾作为栈顶就没有什么区别,用表头作为栈顶是,不论是取元素还是删除元素时,直接将函数中需要操作的节点位置写零即可,而标尾还要检测长度;
对于第四专题四的课后习题里唐老师让将整个计算器的算法不全,可以识别两位数还有能够自己进行中缀转后缀,然后进行后缀计算;
这里就需要设置两个栈了:1:符号栈 2:数字栈
当为数字是,直接进入数字栈,而为符号时,就进入符号栈
而进入符号栈时,什么情况入栈,什么情况出栈和中缀转后缀的方法一样,当符号要进行出栈时,数字栈就要同时进行左右操作时出栈,然后进行运算,再将结果数字栈中;
这样就可以实现中缀转后缀,后缀进行计算了;
但这里有一个小细节就是当数字入栈是一定要先把字符的数字转成数字int型 然后在进行压栈,否则如果在后面的计算结果进行压栈时,如果结果是两位数,然么用字符表示就会出错,然后也没法将两位数转成数字(因为不确定生成的是几位数)所以最好的方法就是在数字压栈时就直接转成int型的数字然后压栈,就不会涉及到结果是几位数了;
//判断是否是数字
int isnumber(char c)
{
return ( c >= '0' ) && ( c <= '9' );
}
//输出字符函数
void output(char c)
{
printf("%c",c);
}
//判断是否是左括号
int isLeft(char c)
{
return (c == '(');
}
//判断是否是右括号
int isRight(char c)
{
return (c == ')');
}
//判断是否是操作符
int isOperator(char c)
{
return ( c == '+' ) || ( c == '-' ) || ( c == '*' ) || ( c == '/' );
}
//判断操作符的优先级
int priority(char c)
{
int ret = 0;
if( (c == '+') || (c == '-') )
{
ret = 1;
}
if( (c == '*') || (c == '/') )
{
ret = 2;
}
return ret;
}
//字符转成数字
int value( char c )
{
return ( c - '0' );
}
int express(int left, int right, char op)
{
int ret = 0;
switch(op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
}
return ret;
}
//转后缀与后缀计算结合体
int arithmic(const char* exp)
{
//存储数字的栈
LinkStack* num = LinkStack_Creat();
//存储运算符的栈
LinkStack* ope = LinkStack_Creat();
int i = 0;
int right = 0; //读取数字栈时 存储右值
int left = 0; //读取数字栈时 存储右值
int result = 0;
char name = '\0'; //存放符号栈出栈时的符号
int ret = 0;
while( exp[i] != '\0')
{
// 是数字
if( isnumber(exp[i]) )
{
int tem = 0;
int r = 0;
int q = 0;
while( isnumber(exp[i + r]))//这里的循环是实现多位数字的运算
{
for(q=0; q0 && exp[i]=='\0' )
{
while( LinkStack_Size(ope) > 0 )
{
printf("size=%d\n",LinkStack_Size(num));
right = (int)LinkStack_Pop(num);
printf("right:%d\n",right);
left = (int)LinkStack_Pop(num);
printf("left:%d\n",left);
name = (char)(int)LinkStack_Pop(ope);
printf("%c\n",name);
result = express(left,right,name);
LinkStack_Push(num,(void*)(result));
// LinkStack_Push(num,(void*)result);
}
if( LinkStack_Size(num) > 1)
{
printf("is error");
// break;
}
ret = (int)LinkStack_Pop(num);
}
//一定要记得销毁栈
LinkStack_Destroy(num);
LinkStack_Destroy(ope);
return ret;
}