手撕链式栈+循环队列(动态分配长度)

本文详细介绍了链式栈和循环队列的数据结构及其在程序中的实现。通过C语言代码展示了如何初始化、入栈、出栈、遍历链式栈,以及如何初始化、入队、出队、遍历循环队列。此外,还讨论了这两种数据结构的满队和空队的判断方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链式栈

空栈示意图:
在这里插入图片描述
栈中有元素示意图:
在这里插入图片描述

#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>

//链式栈
typedef struct Node{
    int data;
    struct Node * next;
}NODE, * PNODE;

typedef struct Stack{
    PNODE pTop;   //栈顶
    PNODE pBottom;//栈底
}STACK, * PSTACK;

void init(PSTACK pS){//链栈的初始化
    PNODE pHead = (PNODE)malloc(sizeof(NODE));
    if (pHead == NULL)
    {
        printf("内存分配失败!\n");
    }
    pS->pBottom = pHead;  //初始栈顶栈底都指向头节点
    pS->pTop = pHead;
    pS->pTop->next = NULL;

}

void push(PSTACK pS, int val){ //原则:先入栈后变动栈顶指针
    PNODE pnew = (PNODE)malloc(sizeof(NODE));
    pnew->data = val;
    pnew->next = pS->pTop; //将新节点接在原栈顶上方
    pS->pTop = pnew;  //栈顶指针变动至最新位置
    return;
}

void traverse(PSTACK pS){
    PNODE p = pS->pTop;  //遍历指针获取到栈顶
    while(p != pS->pBottom){
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
    return;
}

//出栈一次,并将元素输出在val中
bool pop(PSTACK pS, int * p){
    if(pS->pBottom == pS->pTop){  //栈空报错
        return false;
    }
    *p = pS->pTop->data;  //保存删去的值
    PNODE q = pS->pTop;
    pS->pTop = q->next;  //移动栈顶指针
    free(q);
    return true;
}

void clear(PSTACK pS){  //清空表中数据
    if(pS->pBottom == pS->pTop){  //栈空直接返回
        return ;
    }
    PNODE p = pS->pTop;
    while(p != pS->pBottom){
        PNODE q = p;
        p = p->next;
        free(q);
    }
    pS->pTop = pS->pBottom;
    return ;
}

int main(){
    STACK S;  //STACK等价于 struct Stack
    int val;  //保存出栈的元素
    init(&S);
    push(&S, 1);
    push(&S, 2);
    push(&S, 3);
    push(&S, 4);
    push(&S, 5);
    traverse(&S);
    if(pop(&S, &val)){
        printf("出栈元素为:%d\n", val);
    }else{
        printf("出栈失败");
    }
    traverse(&S);
    clear(&S);
    printf("将栈清空!\n");
    if(pop(&S, &val)){
        printf("出栈元素为:%d\n", val);
    }else{
        printf("出栈失败");
    }
    return 0;
}

循环队列

空队示意图:
在这里插入图片描述
队满判断方法:
牺牲一个元素空间,来区别队空或队满。入队前,先判Q.rear+1是否等于Q.front,若是则为队满。

# include <stdio.h>
# include <malloc.h>
# include <stdbool.h>

#define MAX_SIZE 6   //宏定义  数组长度为6,最多能保存5个元素

typedef struct Queue
{
    int * pBase;  //数组的首地址
    int front;
    int rear;
}QUEUE;

void init(QUEUE * pQ){ //初始化一个长度为6的队列
    pQ->pBase = (int *)malloc(sizeof(int) * MAX_SIZE);
    pQ->front = 0;
    pQ->rear = 0;
}

//判断队列是否为空(引入一个空单元作为牺牲)
bool is_full(QUEUE * pQ){
    if((pQ->rear + 1) % MAX_SIZE == pQ->front){
        printf("该循环队列已满!\n");
        return true;
    }
    return false;
}

bool en_queue(QUEUE * pQ, int val){  //入队:入队一个元素,队尾向后移动一下
    if(is_full(pQ)){
        printf("队列已满,无法添加元素!\n");
        return false;
    }else{
        pQ->pBase[pQ->rear] = val;
        pQ->rear = (pQ->rear + 1) % MAX_SIZE;
        return true;
    }
}

bool de_queue(QUEUE * pQ, int * val){
    if(pQ->front == pQ->rear){
        printf("该队列为空,无法出队!\n");
        return false;
    }else{
        *val = pQ->pBase[pQ->front];
        pQ->front = (pQ->front + 1) % MAX_SIZE;
        return true;
    }
}

void traverse_queue(QUEUE * pQ){
    int i = pQ->front;  //找到队首
    if (pQ->front == pQ->rear)
    {
        printf("该循环队列为空!\n");
        return;
    }
    while((pQ->rear + MAX_SIZE - i) % MAX_SIZE > 0){
        printf("%d ", pQ->pBase[i]);
        i++;
    }
    printf("\n");
}

int main(){
    QUEUE Q;  //实例化一个队列
    int val; //保存出队元素
    init(&Q);
    en_queue(&Q, 1);
    en_queue(&Q, 2);
    en_queue(&Q, 3);
    if(de_queue(&Q, &val)){
        printf("出队伍成功!出队元素为:%d", val);
        printf("\n");
    }
    en_queue(&Q, 4);
    en_queue(&Q, 5);
    if(de_queue(&Q, &val)){
        printf("出队伍成功!出队元素为:%d", val);
        printf("\n");
    }
    en_queue(&Q, 6);
    traverse_queue(&Q);
    return 0;
}
### 如何从零开始实现队列数据结构 #### 基于数组的动实现队列 队列是一种遵循先进先出(FIFO, First In First Out)原则的线性数据结构。可以通过数组来动实现一个简单的队列,其中需要定义两个指针 `front` 和 `rear` 来分别表示队列的头部和尾部。 以下是基于数组实现有界队列的核心逻辑[^1]: - **初始化**:创建一个固定大小的数组,并设置初始状态为 `front = rear = -1`。 - **入队操作 (`enqueue`)**:当向队列中添加元素时,如果当前队列为满,则抛出异常;否则更新 `rear` 并将新元素放入该位置。 - **出队操作 (`dequeue`)**:移除并返回位于队列前端的元素。如果当前队列为空,则抛出异常;否则更新 `front` 的值。 需要注意的是,在上述简单实现中可能会遇到“假溢出”的问题,即虽然还有可用空间但由于未正确管理索引而导致无法继续插入新的元素。为了克服这一缺陷,可以采用循环队列的方式重新设计队列的操作方法[^2]。 #### 循环队列的设计与优化 在循环队列中,通过取模运算使得数组看起来像是首尾相接的一个圆圈形式存在,从而有效利用了存储资源避免了之前提到过的那种情况发生。具体来说就是每当某个下标超出边界范围的时候就让它回到起点处继续计算其余数作为实际访问地址即可完成转换过程[^3]。 下面是使用 Python 编写的一个基本版本的循环队列类示例代码: ```python class CircularQueue: def __init__(self, capacity): self.queue = [None] * capacity # 初始化固定长度的列表用于保存数据项 self.front = 0 # 表示队头的位置 self.rear = 0 # 表示下一个待加入元素应放置的位置 self.size = 0 # 当前队列中的元素数量 def is_empty(self): # 判断是否为空的方法 return self.size == 0 def is_full(self): # 判断是否已满的方法 return self.size >= len(self.queue) def enqueue(self, item): # 添加元素至队尾的功能函数 if not self.is_full(): self.queue[self.rear] = item self.rear = (self.rear + 1) % len(self.queue) self.size += 1 else: raise Exception('The queue is full.') def dequeue(self): # 移除并获取队头元素的过程描述 if not self.is_empty(): value = self.queue[self.front] self.front = (self.front + 1) % len(self.queue) self.size -= 1 return value else: raise Exception('The queue is empty.') ``` 此段程序展示了如何构建一个具有特定容量限制的循环缓冲区对象实例化之后便能够执行标准意义上的排队行为比如增加删除项目等等功能[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值