栈的基本概念、顺序栈链栈的C++详细实现

栈的基本概念

栈(Stack)是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作,如图所示。

image-20220707215028353

栈顶(Top)。线性表允许进行插入删除的那一端。

栈底(Bottom)。固定的,不允许进行插入和删除的另一端。

空栈:不含任何元素的空表

栈的基本操作

image-20220705234241361

栈的顺序存储结构

1.顺序栈的实现

采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶元素的位置。

栈的顺序存储类型可描述为:

#define MaxSize 50 //定义栈中元素的最大个数

template<typename T>
struct SqStack {
    T data[MaxSize]; //存放栈中元素
    int top; //栈顶指针
};

栈顶指针: s.top,初始时设置s.top=-1;栈顶元素:s.data [s.top]。

进栈操作:栈不满时,栈顶指针先加1,再送值到栈顶元素。

出栈操作:栈非空时,先取栈顶元素值,再将栈顶指针减1。

栈空条件:s.top==-1;

栈满条件:s.top==MaxSize-1;栈长:s.top+1。

由于顺序栈的入栈操作受数组上界的约束,当对栈的最大使用空间估计不足时,有可能发生栈上溢,此时应及时向用户报告消息,以便及时处理,避免出错。

2.顺序栈的基本运算

栈操作的示意图如图所示,图(a)是空栈,图©是A、B、C、D、E共5个元素依次入栈后的结果,图(d)是在图©之后E、D、C的相继出栈,此时栈中还有2个元素,或许最近出栈的元素C、D、E仍在原先的单元存储着,但top指针已经指向了新的栈顶,元素C、D、E已不在栈中,读者应通过该示意图深刻理解栈顶指针的作用。

image-20220707151312079

下面是顺序栈上常用的基本运算的实现。

#include <iostream>

using namespace std;

#define MaxSize 8 //定义栈中元素的最大个数

template<class T>
class SqStack {
private:
    T data[MaxSize];
    int top;

public:
    //缺省构造函数
    SqStack() {
        this->top = -1;
    }

    //初始化
    void InitStack() {
        this->top = -1;//初始化栈顶指针
    }

    //栈判空
    bool StackEmpty() {
        if (this->top == -1)    //栈空
            return true;
        else                    //不空
            return false;
    }

    //进栈
    bool Push(T x) {
        if (this->top == MaxSize - 1)   //栈满,报错
            return false;
        this->data[++this->top] = x;    //指针先加1,再入栈
        return true;
    }

    //出栈
    bool Pop(T &x) {
        if (this->top == -1)            //栈空,报错
            return false;
        x = this->data[this->top--];    //先出栈,指针再减1
        return true;
    }

    //读取栈顶元素
    bool GetTop(T &x) {
        if (this->top == -1)            //栈空,报错
            return false;
        x = this->data[this->top];      //x记录栈顶元素
        return true;
    }
    //仅为读取栈顶元素,并没有出栈操作,因此原栈顶元素依然保留在栈中。

    //查看栈中所有元素
    void display() {
        if (this->StackEmpty())
            return;
        cout << "all elements in SqStack:\t";
        for (int i = 0; i <= this->top; i++)
            cout << this->data[i] << "\t";
    }
};

int main() {
    //测试
    SqStack<int> sqStack;
    int x;

    //进栈测试
    for (int i = 0; i < 10; i++)
        if (sqStack.Push(i))
            cout << "push " << i << " ok!" << endl;
        else
            cout << "push " << i << " error! The SqStack is full!" << endl;

    sqStack.display();
    cout << endl;

    //出栈测试
    for (int i = 0; i < 10; i++)
        if (sqStack.Pop(x))
            cout << "pop " << x << " ok!" << endl;
        else
            cout << "pop error! The SqStack is empty!" << endl;

    sqStack.display();
    cout << endl;


    return 0;
}

运行结果:

push 0 ok!
push 1 ok!
push 2 ok!
push 3 ok!
push 4 ok!
push 5 ok!
push 6 ok!
push 7 ok!
push 8 error! The SqStack is full!
push 9 error! The SqStack is full!
all elements in SqStack:        0       1       2       3       4       5       6       7
pop 7 ok!
pop 6 ok!
pop 5 ok!
pop 4 ok!
pop 3 ok!
pop 2 ok!
pop 1 ok!
pop 0 ok!
pop error! The SqStack is empty!
pop error! The SqStack is empty!

3.共享栈

利用栈底位置相对不变的特性,可让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸,如图所示。

image-20220707162901768

两个栈的栈顶指针都指向栈顶元素,top0=-1时О号栈为空,top1=Maxsize时1号栈为空;仅当两个栈顶指针相邻(top1-top0=1)时,判断为栈满。当0号栈进栈时top0先加1再赋值,1号栈进栈时top1先减1再赋值;出栈时则刚好相反。

共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被占满时才发生上溢。其存取数据的时间复杂度均为O(1),所以对存取效率没有什么影响。

栈的链式存储结构

采用链式存储的栈称为链栈,链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。这里规定链栈没有头结点,Lhead指向栈顶元素,如图所示。

image-20220707163203869

栈的链式存储结构可描述为:

template<typename T>
struct LinkNode {
    T data;             //数据域
    LinkNode *next;     //指针域
};

采用链式存储,便于结点的插入与删除。链栈的操作与链表类似,入栈和出栈的操作都在链表的表头进行。需要注意的是,对于带头结点和不带头结点的链栈,具体的实现会有所不同。

下面是链栈上常用的基本运算的实现。

#include <iostream>

using namespace std;

template<typename T>
struct LinkNode {
    T data;                 //数据域
    LinkNode<T> *next;      //指针域
};

template<class T>
class LinkStack {
private:
    LinkNode<T> *Lhead;
public:
    //缺省构造函数
    LinkStack() {
        this->Lhead = nullptr;
    }

    //初始化
    void InitStack() {
        this->Lhead = nullptr;//初始化栈顶指针
    }

    //栈判空
    bool StackEmpty() {
        if (this->Lhead == nullptr)     //栈空
            return true;
        else                            //不空
            return false;
    }

    //进栈
    bool Push(T x) {
        //新建一个结点
        LinkNode<T> *p = new LinkNode<T>;
        p->data = x;

        //将结点插入到链栈的头部
        p->next = this->Lhead;
        this->Lhead = p;

        return true;
    }

    //出栈
    bool Pop(T &x) {
        if (this->StackEmpty())             //栈空,报错
            return false;

        x = this->Lhead->data;              //先出栈,再从链表中删除结点
        LinkNode<T> *p = this->Lhead;
        this->Lhead = this->Lhead->next;
        delete p;

        return true;
    }

    //读取栈顶元素
    bool GetTop(T &x) {
        if (this->StackEmpty())             //栈空,报错
            return false;
        x = this->Lhead->data;              //x记录栈顶元素
        return true;
    }

    //查看栈中所有元素
    void display() {
        if (this->StackEmpty()) {
            cout << "The LinkStack is empty!";
            return;
        }

        cout << "all elements in LinkStack:\t";
        LinkNode<T> *p = this->Lhead;
        while (p != nullptr) {
            cout << p->data << "\t";
            p = p->next;
        }
    }
};

int main() {
    LinkStack<int> linkStack;
    int x;

    //进栈测试
    for (int i = 0; i < 10; i++) {
        linkStack.Push(i);
        cout << "push " << i << " ok!" << endl;
    }

    linkStack.display();
    cout << endl;

    //读取栈顶元素测试
    if (linkStack.GetTop(x))
        cout << "top element of LinkStack:" << x << endl;

    //出栈测试
    for (int i = 0; i < 11; i++)
        if (linkStack.Pop(x))
            cout << "pop " << x << " ok!" << endl;
        else
            cout << "pop error! The LinkStack is empty!" << endl;

    linkStack.display();
    cout << endl;
    return 0;
}

运行结果:

push 0 ok!
push 1 ok!
push 2 ok!
push 3 ok!
push 4 ok!
push 5 ok!
push 6 ok!
push 7 ok!
push 8 ok!
push 9 ok!
all elements in LinkStack:      9       8       7       6       5       4       3       2       1       0
top element of LinkStack:9
pop 9 ok!
pop 8 ok!
pop 7 ok!
pop 6 ok!
pop 5 ok!
pop 4 ok!
pop 3 ok!
pop 2 ok!
pop 1 ok!
pop 0 ok!
pop error! The LinkStack is empty!
The LinkStack is empty!
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值