栈的介绍以及c和c++中数组栈和链表栈的实现 及利用c++中stack的计算后缀表达式的值


写在前面
在开始前,请牢记这句话:栈是一种后进先出的数据结构,也可简单的理解为一个只能访问顶部的逆序容器。

栈(stack)是限定仅在表的一端进行操作的数据结构,设想一个头插法的单链表且我们只能够对其链表的头结点进行操作,而操作也只能够进行插入(头插法)一个头结点和删除头结点(表中最后一个进去的结点)的数据结构就是
由于栈只能对一端就行操作,因此栈最重要的操作 也就是push(添加元素),top(返回顶元素),pop(顶元素出栈)
栈的主要用处:
①– 深度优先搜索;
②表达式求值;
③子程序/函数调用的管理;
④消除递归

一:栈的介绍

(1)栈分为两种:(1)顺序栈;(2)链式栈
顺序栈定义如下:
在这里插入图片描述

链式栈(Linked Stack) – 用单链表方式存储,其中指针的方向是从栈顶向下链接(也就是头插法
定义如下
在这里插入图片描述
顺序栈和链式栈的比较
• 时间效率(两者相近)
– 所有操作都只需常数时间
– 顺序栈和链式栈在时间效率上难分伯仲
• 空间效率(链式稍多开销)
– 顺序栈须说明一个固定的长度
– 链式栈的长度可变,但增加结构性开销
实际应用中,顺序栈比链式栈用得更广泛
– 顺序栈容易根据栈顶位置,进行相对位移,快速定
位并读取
栈的内部元素
– 顺序栈读取内部元素的时间为O(1),而链式栈则需
要沿着指针链游走,显然慢些,读取第𝑘个元素需要
时间为𝐎(𝑘)
顺序栈 (Array-based Stack)
使用向量(数组)实现,本质上是顺序表的简化版
栈的大小的定义
②关键是确定哪一端作为栈顶 – 上溢,下溢问题
在stack中声明一个链表成员。
(2)添加元素的方法
栈就是一个只有单一出(入)口的容器插入元素**
顺序栈 就是一直往后添加元素,但是top 一直指向最后添加元素的位置,即可达到后进先出
在这里插入图片描述
则push可这样实现在这里插入图片描述
顺序表的push 就是一个头插法的链表(一直在头结点插入节点)
在这里插入图片描述
具体实现:在这里插入图片描述
(3)pop弹出最后一个进去的结点(top)
①顺序栈::由于全靠 top下标控制top的位置,所以直接top自减一,虽然这样那个元素还在数组中,但是已经不属于栈了,之后添加元素会覆盖它。
具体实现:在这里插入图片描述
链式栈由于是头插法插入的(且头结点保存数据),则直接删掉头结点即可
具体实现:在这里插入图片描述
(4)top返回顶元素
顺序表:直接返回top对应的下标(下标不需要自减1(不用出栈))元素即可在这里插入图片描述
链式栈:返回头结点的数据即可

在这里插入图片描述
(5)出栈和返回栈顶元素总是分开的,毕竟有些时候是不需要出栈的(例如检测栈顶元素),但有时候为了方便也可以在多做一个top_pop();
调用上述两个函数就好(保存一个中间变量用于返回)
在这里插入图片描述

二顺序栈的c实现

//顺序栈
#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;
const unsigned int size = 100; //预留的size大小
typedef struct stack
{
    int msize;      //容量
    int top_pos;    //顶的下标
    ElementType *Top;   //数组栈
} Stack;
int IsEmpty( Stack *stack ) //判断栈是否为空
{
    return stack->top_pos == -1;  //即判断顶的下标是否为-1;
}
int IsFull( Stack *stack ) //判断栈是否满了
{
    return stack->top_pos == stack->msize - 1; //即判断顶的下标是否为 msize-1;
}

Stack *CreatStack(unsigned int maxsize) //创建一个空栈
{
    Stack *stack = malloc(sizeof(Stack));
    if (stack == NULL)   //查看是否有内存
        printf("Out of space!!!\n");
    stack->Top = malloc(sizeof( ElementType) * maxsize);
    if (stack->Top == NULL)     //查看是否有内存
        printf("Out of space!!!\n");
    stack->msize = maxsize;  //输入容量
    stack->top_pos = -1; //顶下标为-1 制造空栈
    return stack;
}

void push(Stack *stack, ElementType value) //压如元素进栈
{
    if (IsFull(stack)) //满栈不能再添加元素了
        printf("Full stack!!!");
    stack->Top[++stack->top_pos] = value; //顶下标 自增1并写入顶元素
}
ElementType top(Stack *stack) //返回顶元素
{
    if (!IsEmpty(stack)) //不能为空栈
        return stack->Top[stack->top_pos];
    printf("Empty stack!!!");
    return 0;
}
void pop(Stack *stack) //顶元素出栈
{
    if (!IsEmpty(stack)) //不能为空
    {
        --stack->top_pos; //top下标自减-即可
        return;
    }
    printf("Empty stack!!!");
}
ElementType top_pop(Stack *stack) //输出出栈的顶元素
{
    if (!IsEmpty(stack)) {
        ElementType temp = top(stack);
        pop(stack);
        return temp;
    }
    printf("Empty stack!!!");
    return 0;
}
void MakeEmpty(Stack *stack) //将栈“制空”
{
    stack->top_pos = -1;
}
void DisposeStack( Stack *stack )   //删掉整个栈
{
    if ( stack != NULL )
    {
        free( stack->Top );
        free( stack );
    }
}
int main()
{
    Stack *stack = CreatStack(size);
    int i = 0;
    for (; i < 101; ++i)
    {
        push(stack, i);
    }
    for (i = 0; i < 100; ++i) {
        printf("%d ", top_pop(stack));
    }
    printf("\n");
    MakeEmpty(stack);
    for (i = 101; i < 110; ++i)
    {
        push(stack, i);
    }
    for (i = 0; i < 10; ++i) {
        printf("%d ", top_pop(stack));
    }
    return 0;
}

三.链式栈的c++实现

//链式栈
#include<iostream>
using namespace std;
template <class T>
class Link
{
public:
    T data; //用于保存结点元素的内容
    Link<T> *next; //指向后继结点的指针
    Link(const T info, Link<T> *nextValue = nullptr): data(info), next(nextValue) { }
    Link(Link<T> *nextValue = nullptr ): next(nextValue) {}
};
template <class T>
class Stack
{
public:
    Stack(): Top(nullptr) {} //Top需要保存元素,先制空
    bool IsEmpty() { // 栈是否为空
        return Top == nullptr;
    }
    T top() {       //返回栈顶元素
        if (IsEmpty()) {      //空栈没有顶
            cout << "Error,this is a blank stack!";
            return T(0);
        }
        else
            return Top->data; //返回栈顶元素
    }
    bool pop() {     //栈顶元素出栈
        if (IsEmpty()) {    //空栈没有顶
            cout << "Error,this is a blank stack!";
            return false;
        }
        else {                   //像链表删除一样的操作,只不过 这里一直删除头结点(Top)
            auto temp = Top;
            Top = Top->next; //把头结点从栈中去除
            delete temp;   //释放头结点的空间
            return true;
        }
    }
    bool push(T value) { //把元素压进栈中
        Top = new Link<T>(value, Top);  //头插法连一个链表,相当于一直在top前面接链条
        //top一直后退,达到后进先出的效果
        return true;
    }//头插法插入一个元素,也就是压进栈中
    T top_pop() {           // 返回出栈了的元素
        if (!IsEmpty())  //对非空栈仍然进行操作
        {
            auto temp = top();
            pop();
            return temp;
        }
        cout << "Error,this is a blank stack!" ;
        return T(0);
    }
    void MakeEmpty() { //将整个栈制空,其实也就是析构掉栈
        while (!IsEmpty()) {
            auto temp = Top; //保存一下要删掉的结点
            Top = temp->next;
            delete temp;
        }
    }
    ~Stack() {
        MakeEmpty();
    }
private:
    Link<T> *Top; //链表栈
};
int main()
{
    Stack<int> stack;
    for (int i = 0; i < 1000; ++i) {
        stack.push(i);
    }
    for (int i = 0; i < 1000; ++i) {
        cout << stack.top_pop() << " ";
    }
    cout << endl;
    stack.MakeEmpty();
    if (stack.top_pop())
        cout << stack.top_pop();
    for (int i = 222; i < 232; ++i) {
        stack.push(i);
    }
    cout << endl;
    for (int i = 0; i < 10; ++i) {
        cout << stack.top_pop() << " ";
    }
    return 0;
}

四.c++上应用stack实现后缀表达式的计算

要解决这个问题得先了解什么是后缀表达式****以及c++中stack怎么用
什么是后缀表达式?
(1)•后缀表达式是类似于
4 x * 2 x * a + * c
例子:10 2 / 3 + 5 * 6 == 34== (10/2+3) * 5-6
这种运算符运算符在后面
** 完全不需要括号的计算式**
在这里插入图片描述
c++中的stack: stack默认由deque实现,但也可自行修改,主要操作和我们写的是类似的,但是没有清空栈的操作,可以自己写一个(全部pop)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体实现:

#include<iostream>
using namespace std;
#include<stack> //链式栈
class Calculate
{
public:
    Calculate(void) {} //开辟一个空栈
    void Run(void); //计算器启动函数
private:
    stack<double> stack;              //c++上的stack 默认deque实现,也可以改成list实现
    //stack<double,list<double>> stack;
    bool two_pop( double &oper1,  double &oper2); //弹出两个要操作的数
    void compulate(char oper); //计算两个数的值并压进栈
    double top_pop() {          //栈顶元素出栈,并返回其值
        double temp = stack.top();
        stack.pop();
        return temp;
    }
    void MakeEmpty() { //把栈制空,以备下次使用
        while (!stack.empty())
            stack.pop();
    }
};
bool Calculate::two_pop( double &oper_front, double &oper_back)//弹出两个要操作的数
{
    if (stack.empty()) { //先考虑特殊情况
        cerr << "error,Missing operand!" << endl;
        return false;
    }
    oper_back = top_pop(); //操作数的后者先出栈(后进先出)
    if (stack.empty()) {
        cerr << "error,Missing operand!" << endl;
        return false;
    }
    oper_front = top_pop(); //操作数前者出栈
    return true;
}
void Calculate:: compulate(char oper) //计算两个数的值并压进栈
{
    double oper_front, oper_back; //操作数 前者和后者
    bool flag = two_pop(oper_front, oper_back); //弹出两个操作数
    if (flag) {
        switch (oper) { //符号转换为运算 并把值压进栈
        case '+': stack.push(oper_front + oper_back); break;
        case '-': stack.push(oper_front - oper_back); break;
        case '*': stack.push(oper_front * oper_back); break;
        case '/': if (oper_back == 0) {
                MakeEmpty(); //stack制空
                cerr << "The divisor cannot be ";//除数不能为0
            } else {
                stack.push(oper_front / oper_back);
            }
            break;
        }
    }
    else {
        MakeEmpty();//没有两个操作数,所以输入有些问题 制空
    }
}
void Calculate::Run(void ) //计算器启动函数
{
    char c;
    double value;
    while (cin >> c, c != '=') { //采用cin不接受空格的特点分开读取,并遇到'='结束
        switch (c) {
        case '+': case '-': case '*': case '/': compulate(c); break;
        default:
            cin.putback(c);   //cin.putback(c)是将字符c放回到输入流中
            cin >> value;     //这样再 用double的 value cin>>value  可以读完整的数字。
            stack.push(value); //数字进栈
            break;
        }
    }
    if (!stack.empty()) { //输出栈中的最后结果
        cout << "The result  of this calclate is: " << top_pop() << endl;
    }
}
int main()
{
    Calculate c;
    c.Run();//   10 2 / 3 + 5 * 6 -       例如输出此式得到34==(10/2+3)*5-6
    return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值