数据结构学习——栈/两栈共享空间/栈的实际应用(四则运算)

关于栈的定义什么的不多赘述,直接上代码:
用链表实现动态栈
//栈
#include<iostream>
using namespace std;

//使用链表实现动态栈
struct Node {
	int data;
	Node* next;
};

struct Stack{
    Node* top;
};

//初始化栈
void initStack(Stack& s) {
    s.top = NULL;
}

//入栈

void pushStack(Stack& s, int data) {
	Node* newnode=new Node;
	newnode->data = data;
    
    //就是链表的next指针的指向s.top,也就是原本的栈顶
	newnode->next = s.top;
    //更新栈顶
	s.top = newnode;
}

//出栈
void popStack(Stack& s) {
	if (s.top == NULL) {
		cout << "栈为空" << endl;
		return;
	}
    Node* temp=s.top;
    int data=s.top->data;

    //这里的s.top->next就是原本的栈顶的下一个元素
    s.top=s.top->next;
    delete temp;
    cout << "出栈元素为:" << data << endl;
}

void readTop(Stack& s) {
	if (s.top == NULL) {
		cout << "栈为空" << endl;
		
	}
	cout  << "栈顶元素为:" << s.top->data << endl;
}

int main(){
    Stack s;
    initStack(s);
    pushStack(s, 1);
    pushStack(s, 2);
    pushStack(s, 3);
    readTop(s);
    //删
    popStack(s);
    readTop(s);
    //删
    popStack(s);
    readTop(s);

    return 0;
}
两栈实现共享空间
//两栈共享空间
#include <iostream>
#define MAXSIZE 10 //数组最大容量
using namespace std;  

//就是用一个数组作为两个栈的共同储存空间
struct TwoStacks
{
    int data[MAXSIZE]; //数组
    int top1, top2; //栈顶指针
};

//初始化

//因为数组的第一个变量对应的位数为0,所以我们空栈取-1
void initStacks(TwoStacks& s) {
    s.top1 = -1; //栈1的栈顶指针
    s.top2 = MAXSIZE; //栈2的栈顶指针
}

//判断栈是否为空/满
int judgeStacks(TwoStacks& s){
    if(s.top1==-1&&s.top2==MAXSIZE){
        cout<<"两个栈都为空"<<endl;
        return 1;   
    }
    if(s.top1+1==s.top2){
        cout<<"两个栈都满了"<<endl;
        return 2;
    }
    if(s.top1==-1&&s.top2!=MAXSIZE){
        cout<<"栈1为空"<<endl;
        return 3;   
    }
    if(s.top2==MAXSIZE&&s.top1!=-1){
        cout<<"栈2为空"<<endl;
        return 4;      
    }
    else{
        return 0;
    }
}

//入栈(左侧)
void pushlift(TwoStacks& s,int data){
    if(judgeStacks(s)==2)
    {
        cout<<"无法插入数据"<<endl;     
    }
    else
    {
        s.data[++s.top1]=data;
    }
}

//入栈(右侧)
void pushright(TwoStacks& s,int data){
    if(judgeStacks(s)==2)
    {
        cout<<"无法插入数据"<<endl;
    }
    else{
        s.data[--s.top2]=data;
    }
}

//出栈(左侧)
void poplist(TwoStacks& s){
    if(judgeStacks(s)==1||judgeStacks(s)==3)
    {
        cout<<"无法删除数据"<<endl;
    }
    else
    {

        cout<<"要删除的数据为"<<s.data[s.top1]<<endl;
        s.data[s.top1]=0;//删除数据,置0
        s.top1--;
    }

}


//出栈(右侧)
void popright(TwoStacks& s){
    if(judgeStacks(s)==1||judgeStacks(s)==4){
        cout<<"无法删除数据"<<endl;
    }
    else{
        cout<<"要删除的数据为"<<s.data[s.top2]<<endl;
        s.data[s.top2]=0;
        s.top2++;
    }
}

void printTwoStacks(TwoStacks& s){
    for(int i=0;i<=s.top1;i++){
        cout<<"这是栈左侧的第"<<i+1<<"个数据"<<endl;
        cout<<s.data[i]<<endl;
    }
    for(int i=MAXSIZE-1;i>=s.top2;i--){

        cout<<"这是栈右侧的第"<<MAXSIZE-i<<"个数据"<<endl;
        cout<<s.data[i]<<endl;
    }
    for(int i=0;i<MAXSIZE;i++){
        cout<<"这是栈的第"<<i+1<<"个数据"<<endl;
        cout<<s.data[i]<<endl;
    }
}

int main(){
    TwoStacks s;
    initStacks(s);

    pushlift(s,1);
    pushlift(s,2);
    pushlift(s,3);
    

    pushright(s,4);
    pushright(s,5);
    pushright(s,6);


    printTwoStacks(s);

    cout<<"从左侧出栈"<<endl;
    poplist(s);
    cout<<"从右侧出栈"<<endl;
    popright(s);

    printTwoStacks(s);

    return 0;
}

判断写的有点不成熟,但是基本的功能是有了,这里发现了一个很有思意的东西

我设定的数组max为10,但是我填充的时候只填充了4个值,那么我便利输出整个数组的时候,

中间没有赋值的会显示什么呢?

307696905、32759、59 等数据是未初始化的内存中的随机值,在 C/C++ 中访问未赋值的数组元素时会读取这些“垃圾值”

操作系统和编译器为了性能优化,不会每次分配局部变量时都清空内存

so,你访问到的是前一次程序运行后遗留的数据,每次运行程序时这些值可能不同,甚至在同一台机器上重启调试也可能变化

四则运算

这里是通过把中缀表达式转化为后缀表达式

//四则运算
#include<iostream>
#include<stack>
#include<string>
#include<sstream>
#include<cctype>
using namespace std;

//可以通过栈来实现,这里直接调用stack库
//举个例子:比如   1+(4-3)*5+6/2   我们称之为中缀表达式
//我们可以将其转化为后缀表达式:1 4 3 - 5 * + 6 2 / +

//首先来看看怎么转化吧:

//判断是否为数字
bool is_digit(char c) { 
    //indigit传入的不能是char,我们要先把他转化为unsigned char类型
    return isdigit(static_cast<unsigned char>(c));
}

//判断运算符优先级
int judge_prior(char c){
    if (c == '+' || c == '-')
        return 1;
    else if (c == '*' || c == '/')
        return 2;
    else
        return 0;
}

//infix:中缀
//postfix:后缀
string infix_to_postfix(string infix) { 

    stack<char> s;
    //记录输出
    stringstream output;

    for(int i = 0; i < int(infix.length()); i++){

        char c = infix[i];

        if(c==' ')
        {
            continue;
        }
        //如果是数字,直接输出
        if(is_digit(c)){
            
            output << c << " ";
        }
        //如果是左括号,直接入栈
        if(c=='('){
            
            s.push(c);
        }
        //如果是右括号,将栈中的元素弹出,直到遇到左括号
        if(c==')'){
            while(!s.empty()&&s.top()!='('){
                output<<s.top()<<" ";
                s.pop();
            }
            s.pop();//弹出左括号
        }
        //操作符处理
        //如果栈顶元素大于当前的元素,则将栈中元素弹出,直到新的栈顶小于当前元素或为空,然后将当前元素入栈
        if(c=='+'||c=='-'||c=='*'||c=='/'){
            while(!s.empty()&&judge_prior(c)<=judge_prior(s.top())){
                output<<s.top()<<" ";
                s.pop();

            }
            s.push(c);//将操作符入栈
            
        }
    }
    //最后将栈中的元素弹出
    while(!s.empty()){
        output<<s.top()<<" ";
        s.pop();
    }
    return output.str();
}


/*通过后缀表达式来计算,原理就是每碰到一个数字就把数字入栈,每碰到一个操作符就从栈中弹出靠经栈顶的两个数字,进行运算,
然后再把结果入栈,以此类推,知道后缀表达式结束,最后栈中剩下的就是结果
*/

int calculate(string postfix){
    stack<int> s;
    for(int i=0;i<int(postfix.length());i++){

        char c=postfix[i];
        if(c==' '){
            continue;
        }
        //如果是数字,直接入栈
        if(is_digit(c)){
            //把字符转化为数字,没有这一步存的是ascii码
            s.push(c-'0');
        }
        if(c=='+'||c=='-'||c=='*'||c=='/'){
            //外面
            int num2=s.top();
            s.pop();
            //里面
            int num1=s.top();
            s.pop();
            switch(c){
                case '+':
                    s.push(num1+num2);
                    break;
                case '-':
                    s.push(num1-num2);
                    break;
                case '*':
                    s.push(num1*num2);
                    break;
                case '/':
                    s.push(num1/num2);
                    break;
            }
            
        }
    }
    return s.top();

}
int main(){
    string infix=" 1+(4-3)*5+6/2";

    cout<<"原始表达式为:"<<infix<<"结果为:"<<"9"<<endl;

    string postfix=infix_to_postfix(infix);
    //1 4 3 - 5 * + 6 2 / +
    cout<<"后缀表达式为:"<<postfix<<endl;

    int result=calculate(postfix);

    cout<<"结果为:"<<result<<endl;

    return 0;

}

这里我截取程杰老师的《大话数据结构》书中的这部分讲解内容来方便理解:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值