# 栈

### 基本定义

栈是一种基本的数据结构，它遵循“先进后出”的原则，即最后压入栈的元素最先弹出。栈可以用数组或链表来实现，常见的栈操作包括：

1. 压栈（Push）：将一个元素放入栈顶，成为新的栈顶。
2. 弹栈（Pop）：将栈顶元素取出，并将其从栈中删除。
3. 获取栈顶元素（Top）：返回当前栈顶元素，但不删除它。
4. 判断栈是否为空（IsEmpty）：判断栈中是否有元素。

<figure><img src="https://3592525301-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0gIiIxAsL9ZSPsdiNLSd%2Fuploads%2FN1fqFG4ru3NVmVuYEPiT%2Fimage.png?alt=media&#x26;token=5a62dabc-209d-49d3-a4ac-79cf54de6f7e" alt=""><figcaption><p>Stack Data Structure</p></figcaption></figure>

栈可以由顺序和链式两种存储结构实现

### 顺序栈

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

```cpp
/**
 * @file array_stack.cpp
 * @author icecreamovo (www.icecreamovo.top)
 * @brief 顺序栈：使用数组实现的栈
 * @version 0.1
 * @date 2023-04-23
 *
 * @copyright Copyright (c) 2023
 *
 */
#include <bits/stdc++.h>
#define N 5
#define MAX_SIZE 5
using namespace std;
typedef struct
{
    int data[MAX_SIZE];
    int top; // 栈顶指针
} Stack;
void initStack(Stack *stack)
{
    stack->top = -1;
}
/**
 * 函数“push”将一个整数值添加到堆栈数据结构中，并打印一条消息指示操作是否成功。
 *
 * @param stack 指向 Stack 结构的指针，它包含一个整数数组和一个指示堆栈顶部索引的变量。
 * @param val val 是需要压入堆栈的整数值。
 *
 * @return 如果条件 `stack->top == MAX_SIZE - 1` 为真，函数返回而不将值压入堆栈。否则，该函数会将值压入堆栈并打印一条成功消息，但不会显式返回任何内容。
 */
void push(Stack *stack, int val)
{
    if (stack->top == MAX_SIZE - 1)
    {
        cout << "栈满，无法入栈" << endl;
        return;
    }
    stack->data[++(stack->top)] = val;
    cout << "入栈成功" << endl;
}
/**
 * 如果栈为空，则打印错误信息并返回-1；否则，返回栈顶元素并递减栈顶指针
 *
 * @param stack 要操作的栈
 *
 * @return 栈顶元素。
 */
int pop(Stack *stack)
{
    if (stack->top == -1)
    {
        cout << "栈空，无法出栈" << endl;
        return -1;
    }
    return stack->data[(stack->top)--];
}
/**
 * 如果栈顶等于-1，则栈为空
 *
 * @param stack 要检查的堆栈。
 *
 * @return 栈顶
 */
bool empty(Stack *stack)
{
    return stack->top == -1;
}
void destroy(Stack *stack)
{
    free(stack);
}
int main()
{
    Stack *stack = (Stack *)malloc(sizeof(Stack));
    initStack(stack);
    for (int i = 0; i < 10; i++)
    {
        push(stack, i + 1);
    }
    while (!empty(stack))
    {
        cout << pop(stack) << endl;
    }
    destroy(stack);
    system("pause");
    return 0;
}
```

### 共享栈

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

<figure><img src="https://3592525301-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0gIiIxAsL9ZSPsdiNLSd%2Fuploads%2FZRhtuYQvy0iZEcfTOWNi%2Fimage.png?alt=media&#x26;token=64f2748d-259e-4f3f-91b1-b3b013245021" alt=""><figcaption><p>Shared-Stack Diagram</p></figcaption></figure>

```cpp
#include <bits/stdc++.h>
#define MAX_SIZE 100
using namespace std;
// 实现共享栈
/**
 * 定义了一个名为 ShareStack 的结构，它表示一个具有两个顶部的共享堆栈。
 * @property {int} data - 存储堆栈元素的整数数组。
 * @property {int} top1 - 共享堆栈实现中第一个堆栈的顶部索引。
 * @property {int} top2 - “ShareStack”结构中的“top2”属性是共享堆栈实现中第二个堆栈的顶部指针。
 * 在共享堆栈中，两个堆栈共享同一个底层数组，“top1”和“top2”指针跟踪每个堆栈的顶部元素
 */
typedef struct Stack
{
    int data[MAX_SIZE];
    int top1;
    int top2;
} ShareStack;

/**
 * 该函数通过将顶部指针设置为 -1 和 MAX_SIZE 来初始化共享堆栈。
 *
 * @param stack 指向 ShareStack 结构的指针，其中包含两个整数变量 top1 和 top2。
 */
void initStack(ShareStack *stack)
{
    stack->top1 = -1;
    stack->top2 = MAX_SIZE;
}

void push(ShareStack *stack, int val, int stackNumber)
{
    if (stack->top1 + 1 == stack->top2)
    {
        cout << "栈满，无法入栈" << endl;
        return;
    }
    if (stackNumber == 1)
    {
        stack->data[++stack->top1] = val;
    }
    else if (stackNumber == 2)
    {
        stack->data[--stack->top2] = val;
    }
    else
    {
        cout << "请输入正确的栈号" << endl;
    }
}

void pop(ShareStack *stack, int stackNumber)
{
    if (stackNumber == 1)
    {
        if (stack->top1 == -1)
        {
            cout << "栈1空，无法出栈" << endl;
            return;
        }
        cout << "栈1出栈元素：" << stack->data[stack->top1--] << endl;
    }
    else if (stackNumber == 2)
    {
        if (stack->top2 == MAX_SIZE)
        {
            cout << "栈2空，无法出栈" << endl;
            return;
        }
        cout << "栈2出栈元素：" << stack->data[stack->top2++] << endl;
    }
    else
    {
        cout << "请输入正确的栈号" << endl;
    }
}

int main()
{
    ShareStack *stack = (ShareStack *)malloc(sizeof(ShareStack));
    initStack(stack);
    for (int i = 0; i < 10; i++)
    {
        push(stack, i, 1);
    }
    for (int i = 0; i < 10; i++)
    {
        push(stack, i, 2);
    }
    for (int i = 0; i < 10; i++)
    {
        pop(stack, 1);
    }
    for (int i = 0; i < 10; i++)
    {
        pop(stack, 2);
    }
    system("pause");
    return 0;
}
```

### 链栈

采用链式存储的栈称为链栈，链栈的优点是便于多个栈共享存储空间和提高其效率，并且不存在栈满上溢的情况。

```cpp
/**
 * @file linked_stack_head.cpp
 * @author icecreamovo (www.icecreamovo.top)
 * @brief 带头结点的单链表实现的链栈
 * @version 0.1
 * @date 2023-04-23
 *
 * @copyright Copyright (c) 2023
 *
 */
#include <bits/stdc++.h>
#define N 100
using namespace std;

/**
 * 上述类型定义了一个堆栈节点结构，其中包含整数数据和指向下一个节点的指针。
 * @property {int} data - 一个整型变量，存储栈中节点的数据。
 * @property next - “next”是指向链表中下一个节点的指针。在这种情况下，它指向堆栈中的下一个节点。
 */
typedef struct StackNode
{
    int data;
    struct StackNode *next;
} StackNode, LinkStack;

/**
 * 初始化堆栈。
 *
 * @param stack 要初始化的栈
 */
void initStack(LinkStack *stack)
{
    stack->next = NULL;
}

/**
 * 将值压入堆栈。
 *
 * @param stack 要压入的栈
 * @param val 要压入堆栈的值
 */
void push(LinkStack *stack, int val)
{
    StackNode *p = (StackNode *)malloc(sizeof(StackNode));
    p->data = val;
    p->next = stack->next;
    stack->next = p;
    cout << "元素：" << val << "入栈成功" << endl;
}

/**
 * 函数“pop”从链接的堆栈中删除顶部元素，如果堆栈为空则返回错误消息。
 *
 * @param stack 指向链接堆栈的顶部节点的指针。
 *
 * @return 什么都没有（无效）。
 */
void pop(LinkStack *stack)
{
    if (stack->next == NULL)
    {
        cout << "栈空，无法出栈" << endl;
        return;
    }
    StackNode *p = stack->next;
    stack->next = p->next;
    free(p);
}

bool empty(LinkStack *stack)
{
    return stack->next == NULL;
}

/**
 * 该函数通过释放其所有节点来销毁链接堆栈。
 *
 * @param stack 指向 LinkStack 结构的指针，它表示堆栈的链表实现。
 */
void destroy(LinkStack *stack)
{
    while (stack->next != NULL)
    {
        StackNode *p = stack->next;
        stack->next = p->next;
        free(p);
    }
}
int main()
{
    LinkStack *stack = (LinkStack *)malloc(sizeof(LinkStack));
    initStack(stack);
    for (int i = 0; i < 10; i++)
    {
        push(stack, i);
    }
    while (!empty(stack))
    {
        cout << stack->next->data << endl;
        pop(stack);
    }
    destroy(stack);
    system("pause");
    return 0;
}
```
