用基础的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;