【数据结构】堆栈

目录

一、堆栈的基本概念

1.1 堆栈定义

1.2 堆栈操作

1.3 堆栈应用

二、顺序栈

2.1 定义

2.2 操作

2.3 C语言实现

三、共享栈

3.1 定义

3.2 操作

3.3 C语言实现

四、链式栈

4.1 定义

4.2 操作

4.3 C语言实现

五、总结


        堆栈(Stack)重要的数据结构,它们在计算机科学和软件开发中都有广泛的应用。下面我将分别解释这种数据结构的特点和用途。

一、堆栈的基本概念

1.1 堆栈定义

        堆栈是一种后进先出(LIFO,Last In First Out)的数据结构。它只允许在一端(称为栈顶)进行插入和删除操作。顺序栈和共享栈是最经典的堆栈方式

1.2 堆栈操作

        压栈(Push):向堆栈中添加一个元素,该元素被放置在栈顶。

        弹栈(Pop):从堆栈中移除一个元素,该元素总是栈顶的元素。

        查看栈顶(Peek):查看栈顶的元素,但不移除它。

1.3 堆栈应用

        函数调用和返回:在大多数编程语言中,函数调用和返回都使用堆栈来实现。当一个函数被调用时,它的局部变量和返回地址被压入堆栈。当函数返回时,这些信息从堆栈中弹出。

        表达式求值:在编译器和解释器中,堆栈用于存储中间结果和操作符,以支持算术和逻辑表达式的求值。

        后退/前进功能:在图形用户界面(GUI)中,如浏览器或文本编辑器,堆栈可以用来实现后退和前进功能。

        内存管理:在某些编程语言和系统中,堆栈也用于管理内存。例如,在 C 和 C++ 中,局部变量和函数参数通常存储在堆栈上。

        浏览器历史记录:在网页浏览器中,后退和前进按钮通常使用堆栈来管理历史记录。当用户浏览新的网页时,该网页的 URL 被推入堆栈。当用户点击后退按钮时,最近的 URL 从堆栈中弹出并显示。

这些只是堆栈的一些基本应用,实际上堆栈在计算机科学中的用途远不止这些。

二、顺序栈

2.1 定义

        栈的顺序存储即使用连续的空间存储栈中的元素,顺序方式存储的栈称顺序栈。

2.2 操作

2.3 C语言实现

#include <stdio.h>
#include <stdlib.h>
 
#define STACK_SIZE 100
 
typedef struct {
    int data[STACK_SIZE];
    int top;
} SeqStack;
 
// 初始化顺序栈
void initStack(SeqStack *s) {
    s->top = -1;
}
 
// 判断栈是否为空
int isEmpty(SeqStack *s) {
    return s->top == -1;
}
 
// 判断栈是否已满
int isFull(SeqStack *s) {
    return s->top == STACK_SIZE - 1;
}
 
// 入栈操作
int push(SeqStack *s, int value) {
    if (isFull(s)) {
        printf("栈已满,无法进行入栈操作。\n");
        return 0;
    }
    s->data[++s->top] = value;
    return 1;
}
 
// 出栈操作
int pop(SeqStack *s, int *value) {
    if (isEmpty(s)) {
        printf("栈为空,无法进行出栈操作。\n");
        return 0;
    }
    *value = s->data[s->top--];
    return 1;
}
 
// 打印栈内元素
void printStack(SeqStack *s) {
    if (isEmpty(s)) {
        printf("栈为空。\n");
        return;
    }
    for (int i = s->top; i >= 0; i--) {
        printf("%d ", s->data[i]);
    }
    printf("\n");
}
 
int main() {
    SeqStack stack;
    initStack(&stack);
 
    // 入栈操作
    push(&stack, 1);
    push(&stack, 2);
    push(&stack, 3);
 
    // 出栈操作
    int value;
    pop(&stack, &value);
    printf("出栈元素: %d\n", value);
 
    // 打印栈内元素
    printStack(&stack);
 
    return 0;
}

        这段代码定义了一个简单的顺序栈,并实现了初始化、判断空满、入栈、出栈以及打印栈内元素的基本操作。在main函数中演示了如何使用这些操作。

三、共享栈

3.1 定义

        当需要同时使用多个栈时,可以在同一块连续的空间中设置多个栈,形成多个栈共享栈空间。当其中的某个栈满时,可能其它栈尚余许多空间,这时可以让其它的堆栈进行左右移动,然后让该栈继续获得一些新的空间,从而可以继续进行进栈活动。

3.2 操作

        共享栈初始状态:

        共享栈中间某状态:

3.3 C语言实现

#include <stdio.h>
#include <stdlib.h>
 
typedef struct {
    int *elements; // 存储元素的数组
    int top_index; // 栈顶索引
    int capacity;  // 栈的容量
} SharedStack;
 
// 初始化共享栈
SharedStack* init_shared_stack(int capacity) {
    SharedStack* stack = (SharedStack*)malloc(sizeof(SharedStack));
    stack->elements = (int*)malloc(capacity * sizeof(int));
    stack->top_index = -1;
    stack->capacity = capacity;
    return stack;
}
 
// 释放共享栈占用的内存
void free_shared_stack(SharedStack* stack) {
    free(stack->elements);
    free(stack);
}
 
// 判断共享栈是否为空
int is_shared_stack_empty(SharedStack* stack) {
    return stack->top_index == -1;
}
 
// 判断共享栈是否已满
int is_shared_stack_full(SharedStack* stack) {
    return stack->top_index + 1 == stack->capacity;
}
 
// 向共享栈中添加元素
void push_shared_stack(SharedStack* stack, int element) {
    if (is_shared_stack_full(stack)) {
        printf("Stack is full.\n");
        return;
    }
    stack->elements[++stack->top_index] = element;
}
 
// 从共享栈中移除元素
int pop_shared_stack(SharedStack* stack) {
    if (is_shared_stack_empty(stack)) {
        printf("Stack is empty.\n");
        return -1;
    }
    return stack->elements[stack->top_index--];
}
 
// 主函数示例
int main() {
    SharedStack* stack = init_shared_stack(10); // 初始化容量为10的共享栈
 
    push_shared_stack(stack, 1); // 添加元素
    push_shared_stack(stack, 2);
    printf("Pop element: %d\n", pop_shared_stack(stack)); // 移除元素
    printf("Pop element: %d\n", pop_shared_stack(stack));
 
    free_shared_stack(stack); // 释放栈占用的内存
 
    return 0;
}

        这个简单的共享栈实现包括初始化、释放内存、判断栈满或空、进栈和出栈的基本操作。在主函数中,我们创建了一个容量为10的共享栈,添加了两个元素,然后移除并打印了这两个元素,最后释放了栈占用的内存。

四、链式栈

4.1 定义

        链式栈是一种数据存储结构,可以通过单链表的方式来实现,使用链式栈的优点在于它能够克服用数组实现的顺序栈空间利用率不高的特点,但是需要为每个栈元素分配额外的指针空间用来存放指针域。

4.2 操作

        每个结点存储元素和指针,栈顶指针top用于指向处于栈顶的结点,即单链表中的首结点。链式栈的进、出栈总是在首结点位置进行。

4.3 C语言实现

#include <stdio.h>
#include <stdlib.h>
 
typedef struct Node {
    int data;
    struct Node* next;
} Node;
 
typedef struct Stack {
    Node* top;
    int size;
} Stack;
 
Stack* createStack() {
    Stack* stack = (Stack*)malloc(sizeof(Stack));
    stack->top = NULL;
    stack->size = 0;
    return stack;
}
 
int isEmpty(Stack* stack) {
    return stack->top == NULL;
}
 
void push(Stack* stack, int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = stack->top;
    stack->top = newNode;
    stack->size++;
}
 
int pop(Stack* stack) {
    if (isEmpty(stack)) {
        fprintf(stderr, "Stack is empty\n");
        exit(1);
    }
 
    Node* topNode = stack->top;
    int data = topNode->data;
    stack->top = stack->top->next;
    free(topNode);
    stack->size--;
    return data;
}
 
int peek(Stack* stack) {
    if (isEmpty(stack)) {
        fprintf(stderr, "Stack is empty\n");
        exit(1);
    }
    return stack->top->data;
}
 
int main() {
    Stack* stack = createStack();
 
    push(stack, 1);
    push(stack, 2);
    push(stack, 3);
 
    printf("Top element: %d\n", peek(stack));
    printf("Popped element: %d\n", pop(stack));
    printf("Top element: %d\n", peek(stack));
 
    return 0;
}

        在这个实现中,我们定义了两个结构体:Node和Stack。Node用来表示链表的节点,每个节点包含一个整数和一个指向下一个节点的指针。Stack结构体包含一个指向顶部节点的指针和一个表示栈中元素数量的整数。

        我们实现了几个基本的操作:

  • createStack:创建一个新的空栈。

  • isEmpty:检查栈是否为空。

  • push:将一个元素添加到栈顶。

  • pop:移除并返回栈顶元素。

  • peek:返回栈顶元素但不移除它。

        在main函数中,我们创建一个新的空栈,然后进行入栈、查看栈顶元素、出栈和再次查看栈顶元素的操作。

五、总结

        堆栈和队列都是重要的数据结构,但它们的特性和用途是不同的。堆栈遵循后进先出的原则,主要用于需要保存和恢复临时状态的情况,如函数调用和表达式求值。队列遵循先进先出的原则,主要用于需要按顺序处理元素的情况,如打印任务、线程调度和消息传递。

### 数据结构堆栈与队列的概念及区别 #### 堆栈 (Stack) ##### 定义 堆栈是一种**后进先出(LIFO,Last In First Out)** 的线性数据结构。所有的插入和删除操作都在同一端进行,这一端被称为栈顶[^1]。 ##### 基本操作 - **压栈(Push)**: 将一个元素添加到栈顶。 - **出栈(Pop)**: 移除并返回栈顶的元素。 - **查看栈顶(Peek/Top)**: 获取栈顶元素而不移除它[^4]。 ##### 应用场景 - 函数调用管理:编程语言的运行时环境使用堆栈来跟踪函数调用和返回地址。 - 表达式求值:在编译器设计中,堆栈常用于处理算术表达式的求值和语法分析。 - 深度优先搜索(DFS):在图或树的遍历中,堆栈可以用来实现深度优先搜索算法[^1]。 --- #### 队列 (Queue) ##### 定义 队列是一种**先进先出(FIFO,First In First Out)** 的线性数据结构。新元素总是从队尾加入,旧元素总是从队头移除[^2]。 ##### 基本操作 - **入队(Enqueue)**: 将一个元素添加到队列的尾部。 - **出队(Dequeue)**: 从队列的头部移除并返回一个元素。 - **查看队头(Front/Poll)**: 获取队列头部的元素而不移除它[^3]。 ##### 应用场景 - 任务调度:操作系统中的任务调度通常依赖队列来按顺序执行任务。 - 消息队列:分布式系统中常用队列来传递消息。 - 广度优先搜索(BFS):在图或树的遍历中,队列可用于实现广度优先搜索算法[^2]。 --- ### 堆栈与队列的主要区别 | 特性 | 堆栈 | 队列 | |---------------------|-------------------------------|--------------------------------| | 插入位置 | 栈顶 | 队尾 | | 删除位置 | 栈顶 | 队头 | | 访问顺序 | 后进先出(LIFO) | 先进先出(FIFO) | | 主要操作 | Push、Pop、Peek | Enqueue、Dequeue、Poll | | 使用场景 | 函数调用、表达式求值 | 任务调度、消息传递 | --- ### 堆栈与队列的联系 虽然堆栈和队列具有不同的特性,但它们也有一些相似之处: 1. **都是线性数据结构**:堆栈和队列都是一维的数据集合,按照一定的顺序排列元素。 2. **支持受限访问模式**:两种数据结构都不允许随机访问任意位置的元素,而是通过固定的规则进行插入和删除操作。 3. **基础实现方法相同**:无论是堆栈还是队列,都可以基于数组或链表实现其底层存储结构[^5]。 --- ```python # Python 示例代码展示堆栈和队列的基本操作 # 堆栈实现 class Stack: def __init__(self): self.items = [] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() def peek(self): return self.items[-1] if self.items else None def is_empty(self): return not bool(self.items) # 队列实现 class Queue: def __init__(self): self.items = [] def enqueue(self, item): self.items.insert(0, item) def dequeue(self): return self.items.pop() if self.items else None def front(self): return self.items[-1] if self.items else None def is_empty(self): return not bool(self.items) if __name__ == "__main__": stack = Stack() queue = Queue() # 测试堆栈 stack.push(10) stack.push(20) print(f"Stack Top: {stack.peek()}") # 输出 20 print(f"Popped from Stack: {stack.pop()}") # 输出 20 # 测试队列 queue.enqueue(10) queue.enqueue(20) print(f"Queue Front: {queue.front()}") # 输出 10 print(f"Dequeued from Queue: {queue.dequeue()}") # 输出 10 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大雨淅淅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值