用基础的C语言实现一个顺序栈:表尾做栈顶
1. 栈的操作
栈的操作主要有三个:
①push:元素入栈
②pop:元素出栈(此元素会从栈内删除) C++的pop无返回值,而Java的pop有返回值
③top(Java为peek):查看栈顶元素(仅查看)
具体实现方式如下:(详细描述请看注释)
(1)创建Stack结构体存储数据:
struct Stack{ int *data; //数据,动态分配大小 int capacity;//栈容量 ,数组最高元素下标是capacity-1 int top; //栈顶位置 };
(2)栈的初始化函数:栈顶top有两种初始化方式,这里我们选择ps->top = 0;
void init(struct Stack *ps,int capacity){ ps->capacity = capacity; ps->data = (int *)malloc(sizeof(int)*capacity); ps->top = 0; //top初始化可以是0或-1,栈内刚开始时是没有元素的, // 所以可以用top初始化为-1来使之始终指向栈里最高位的元素 // 或者初始化为0来指向数组最高下标之后的空位 }
(3)下面是几个经常用到的函数,其中isEmpty()和isFull()是在push,pop,top操作中判断栈满栈空的,判断方式也可以直接写在这三个函数中,但是由于多次用到,就直接拿出来写成函数
destroy:销毁栈,释放空间
printStack:打印栈内元素
int isFull(const struct Stack *ps){//不会改变栈内元素,可以用const修饰 // 最高元素下标是capacity-1 //判断栈满:top == capacity//因为刚开始top = 0,top(栈顶)指向最高下标的后一位 return ps->top==ps->capacity; } int isEmpty(const struct Stack *ps){ return ps->top ==0; }
void printStack(struct Stack *ps){ for(int i = 0;i<ps->top-1;i++){ printf("%d->",ps->data[i]); } printf("%d\n",ps->data[ps->top-1]); } void destroy(struct Stack *ps){ free(ps->data); }
(4)三大操作的实现:
int push(struct Stack *ps,int x){ // if()//将判断栈满写为一个函数 if(isFull(ps)) return 0; else{ ps->data[ps->top]=x;//top是栈顶空位 ps->top++; return 1; } } int pop(struct Stack *ps,int *px){//这里的*px是为了得到pop删除的元素指,也可以直接使用top,将此函数改为int pop(struct Stack *ps) if(isEmpty(ps)) return 0; else{ ps->top--;//top-1的位置即为栈顶元素所在位置 *px = ps->data[ps->top]; return 1; } } int top(const struct Stack *ps) { if(isEmpty(ps)) return 0; else{ //top-1的位置即为栈顶元素所在位置 return ps->data[ps->top-1]; } }
整体代码:
//顺序栈:表尾做栈顶 #include<stdio.h> #include<stdlib.h> struct Stack{ int *data; //数据,用指针动态分配大小 int capacity;//栈容量 ,最高元素下标是capacity-1 int top; //栈顶位置 }; void init(struct Stack *ps,int capacity){ ps->capacity = capacity; ps->data = (int *)malloc(sizeof(int)*capacity); ps->top = 0; //top初始化可以是0或-1,刚开始时是没用元素的, // 所以可以用-1始终指向栈里最高位的元素 // 或者使用0来指向最高位之后的空位 } int isFull(const struct Stack *ps){//不会改变栈内元素,可以用const修饰 // 最高元素下标是capacity-1 //判断栈满:top == capacity//因为刚开始top = 0,栈顶指向最高下标的后一位 return ps->top==ps->capacity; } int isEmpty(const struct Stack *ps){ return ps->top ==0; } int push(struct Stack *ps,int x){ // if()//将判断栈满写为一个函数 if(isFull(ps)) return 0; else{ ps->data[ps->top]=x;//top是栈顶空位 ps->top++; return 1; } } int pop(struct Stack *ps,int *px){ if(isEmpty(ps)) return 0; else{ ps->top--;//top-1的位置即为栈顶元素所在位置 *px = ps->data[ps->top]; return 1; } } int top(const struct Stack *ps) { if(isEmpty(ps)) return 0; else{ //top-1的位置即为栈顶元素所在位置 return ps->data[ps->top-1]; } } void printStack(struct Stack *ps){ for(int i = 0;i<ps->top-1;i++){ printf("%d->",ps->data[i]); } printf("%d\n",ps->data[ps->top-1]); } void destroy(struct Stack *ps){ free(ps->data); } int main() { struct Stack st; init(&st,5);//改变st的内容//栈初始化 push(&st,22);//压栈,需要改变结构体内数据 push(&st,33); push(&st,44); push(&st,55); push(&st,66); printStack(&st); int x; //也可以写一个top函数返回栈顶元素; pop(&st,&x);//弹出栈,栈空时不成功; printf("%d\n",x); int y = top(&st); printf("%d\n",y); printStack(&st); //销毁栈 destroy(&st); return 0; }
Stack应用:
我们人类习惯于书写“中缀式”,如 3 + 5 * 2
,其值为13
。 (p.s. 为什么人类习惯中缀式呢?是因为中缀式比后缀式好用么?)
而计算机更加习惯“后缀式”(也叫“逆波兰式”,Reverse Polish Notation)。上述中缀式对应的后缀式是: 3 5 2 * +
现在,请对输入的后缀式进行求值。
输入格式:
在一行中输入一个后缀式,运算数
和运算符
之间用空格分隔,运算数长度不超过6
位,运算符仅有+ - * /
四种。
输出格式:
在一行中输出后缀式的值,保留一位小数。
输入样例:
3 5.4 2.2 * +
输出样例:
14.9
数据输入时要注意的:
scanf("%s")....不接收空格,部分编译器可以使用gets(不建议,c++11,14已经被移除)
C++中可以用cin>>str 来获取输入的字符串,录入的字符串中如果包含空格,则会根据空格将字符串分割成多段,如果想要输入带空格的字符串,可以使用getline()
cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入。(比如用空格将两段数据隔开)
getchar/cin.get()接收的是输入str之后的回车,以此来判断输入是否结束:以便跳出循环
C++string的size函数就是其实际长度,和length函数无区别,且string中无'\0'
要考虑到负数的存在
#include<iostream> #include<string> #include<stack> using namespace std; int main() { double a , b ; string str; stack<double> num; while (cin >> str) { char c = getchar(); // 负数和小数size>1,但是操作符的一定=1 ,C++string的size就是其实际长度,和length函数无区别 if ((str[0]>='0'&&str[0]<='9')/*isdigit(str[0])*/||str.size()>1) { num.push(stod(str)); } else { switch (str[0]) { case '+': a = num.top(); num.pop(); b = num.top(); num.pop(); num.push(a + b); break; case '-': a = num.top(); num.pop(); b = num.top(); num.pop(); num.push(b-a); break; case '*': a = num.top(); num.pop(); b = num.top(); num.pop(); num.push(b*a); break; case '/':a = num.top(); num.pop(); b = num.top(); num.pop(); num.push(b / a); break; } } if (c == '\n') { break; } } printf("%.1f\n", num.top()); return 0;