栈与队列的操作

栈与队列

具有的操作:

  • 初始化栈(队列)
  • 判断栈(队列)是否为空
  • 判断栈(队列)是否已满
  • 入栈(队列)
  • 出栈(队列)
  • 遍历栈(队列)

栈满足的特性

  • 先进后出 后进先出

队列满足的特性

  • 先进先出,后进后出

顺序栈(数组形式)

  • 定义数据类型 默认以int类型为主,可以使用模板封装任意类型的栈

    //存int类型数据的顺序栈
    int* pStack; //指向栈的指针
    int size; //存储栈中的元素个数
  • 栈的操作

    //初始化栈
    void InitStack();
    //入栈
    void push(int data);
    //出栈
    void pop();
    //判断栈是否为空
    bool isEmpty();
    //获取栈顶元素,只能获取栈顶元素
    int getTop();
    //遍历元素
    void _travel();
  • 初始化栈

    //初始化栈
    void InitStack()
    {
    pStack = NULL;
    }
  • 入栈操作: 分两种方式

    1. 当栈为空的时候,

      void push()
      {
      if (pStack == NULL)
      {
      //1. 开辟新的空间
      pNew = (int*)malloc(sizeof(int)* (size+1));
      //2. 原来的内存指向新的开辟的内存
      pStack = pNew;
      //3. 插入数据
      pStack[size++] = data;
      }
    2. 当栈不为空的时候

      • 即需要在数组的最后添加元素,首先要开辟一块新的内存区域,在新开辟的空间进行数组元素的增加
      //栈不为空 操作步骤:
      else
      {
      //1.为后面的开辟新的内存
      int* pNew = (int*)malloc(sizeof(int) * (size + 1));
      //2.将原有的内存数据的元素拷贝到新的内存里
      memcpy(pNew, pStack, sizeof(int) * size);
      //3.释放原有的内存空间
      free(pStack);
      //4.原来的内存指向新的开辟的内存
      pStack = pNew;
      //5.插入数据
      pStack[size++] = data;
      }
  • 出栈操作

    • 对于栈,先进的元素后出,后进的元素先出,即首先删除数组末尾的元素,然后依次往前删除

      void pop()
      {
      if (isempty())
      {
      printf("栈为空\n");
      return;
      }
      int* pNew = (int*)malloc(sizeof(int) * (size - 1));
      memcpy(pNew, pStack, sizeof(int) * (size - 1));
      free(pStack);
      pStack = pNew;
      size--;
      }
  • 栈的其他操作

    //判断栈是否为空
    bool isEmpty()
    {
    return (size == 0);
    }
    //获取栈顶元素,只能获取栈顶元素
    int getTop()
    {
    return pStack[size-1];
    }
    //遍历元素
    void _travel()
    {
    printf("size(%d):", size);
    for (int i = 0; i < size; i++)
    {
    printf("%d ", pStack[i]);
    }
    printf("\n");
    }
  • 栈的测试

    int main()
    {
    InitStack();
    //测试
    for (int i = 5; i < 15; i++)
    {
    push(i);
    _travel();
    }
    while (!isEmpty())
    {
    printf("当前栈顶:%d\n", getTop());
    pop(); //出栈
    }
    return 0;
    }

在这里插入图片描述



顺序队列(数组形式)

  • 队列的操作与栈基本一致 只有出队的时候与出栈不同

  • 队列先进先出 后进后出 先删除数组的第一个元素,在依次往后删除数组元素

  • 出队

    //出队
    int pop()
    {
    if (isEmpty())
    {
    printf("队列为空,出队失败\n");
    return -1;
    }
    /*
    队列: 先进先出 要删除第一个元素
    */
    //释放第一个元素
    int ret = pQueue[0];
    //1. 开辟一个新的内存段
    int* pNew = (int*)malloc(sizeof(int) * (size - 1));
    //2. 原有内存段的数据拷贝到新的内存段 要删除第一个 旧的内存区块跳过第一个元素
    memcpy(pNew, pQueue + 1, sizeof(int) * (size - 1));
    //3. 释放原有的内存段
    free(pQueue);
    //4. 原有的内存段指向新开辟的内存
    pQueue = pNew;
    //5. size减少
    size--;
    //6. 返回每次释放的元素
    return ret;
    }
  • 队列测试

int main()
{
InitQueue();
//测试
for (int i = 5; i < 15; i++)
{
push(i);
_travel();
}
int ret = 0;
while (ret != -1)
{
printf("队列顶:%d\n", ret = pop());
}
return 0;
}

``在这里插入图片描述



链式栈 (无头节点)

​ 链表的形式存储栈的节点 操作和链表的操作基本一致

  • 这里以结构体类型描述栈的结构

    //栈节点的数据类型
    struct Student
    {
    char name[50];
    int age;
    float score;
    };
    typedef struct Student STU;
    #define STU_SIZE sizeof(struct Student)
    //存储链式栈的链表
    struct List
    {
    STU data;
    struct List* next;
    };
    typedef struct List Node;
  • 链式栈的操作

    //创建节点
    Node* CreateNode(STU* data);
    //尾插法 入栈
    void push(Node** pHead,STU* data);
    //出栈
    Node* pop(Node** pHead);
    //遍历栈
    void travel(Node* head);
    //打印
    void Printf(STU* p);
  • 创建栈节点

    //创建节点
    Node* CreateNode(STU* data)
    {
    Node* pNew = (Node*)malloc(sizeof(Node));
    if (pNew == NULL)
    {
    printf("创建失败\n");
    return 0;
    }
    strcpy(pNew->data.name, data->name);
    pNew->data.age = data->age;
    pNew->data.score = data->score;
    pNew->next = NULL;
    //返回节点
    return pNew;
    }
  • 入栈 链表的尾插法入栈

    1. 分两种情况,看他是空链表还是非空链表
    //尾插法 入栈
    void push(Node** pHead, STU* data)
    {
    if (pHead == NULL)
    {
    return;
    }
    //创建新的节点
    Node* pNew = CreateNode(data);
    //空链表 新节点要成为当前节点的第一个几点
    if (*pHead == NULL)
    {
    *pHead = pNew;
    }
    else
    {
    //找到链表的尾部 插入节点
    Node* pTemp = *pHead;
    while (pTemp->next)
    {
    pTemp = pTemp->next;
    }
    //在尾部插入
    pTemp->next = pNew;
    }
    }
  • 出栈

    1. 删除链表的最后一个节点,依次往前删除
    //出栈 删除末尾节点
    Node* pop(Node** pHead)
    {
    if (pHead == NULL || *pHead == NULL)
    {
    return NULL;
    }
    //找到链表的最后一个节点
    Node* pTail = *pHead;
    while (pTail->next)
    {
    pTail = pTail->next;
    }
    //1. 如果链表只有一个节点,第一个就等于末尾节点
    if (pTail == *pHead)
    {
    *pHead = NULL;
    }
    //2. 如果有多个节点 找到最后一个的前一个并且删除最后一个
    else
    {
    Node* pPreTail = *pHead;
    while (pPreTail->next != pTail)
    {
    pPreTail = pPreTail->next;
    }
    //最后一个节点的前一个节点next置空 实现删除最后一个
    pPreTail->next = NULL;
    }
    return pTail;
    }
  • 遍历及打印

    //遍历栈
    void travel(Node* pHead)
    {
    if (pHead == NULL)
    {
    printf("栈为空\n");
    return;
    }
    Node* pTemp = pHead;
    while (pTemp)
    {
    //传入地址
    Printf(&(pTemp->data));
    pTemp = pTemp->next;
    }
    }
    //打印
    void Printf(STU* p)
    {
    printf("姓名:%s 年龄:%d 成绩:%.2f\n",
    p->name, p->age, p->score);
    }
  • 链式栈测试

    int main()
    {
    STU info[5] = {
    {"关羽",55,55.55},
    {"张飞",44,44.44},
    {"赵云",33,33.33},
    {"马超",22,22.22},
    {"黄忠",11,11.11},
    };
    Node* pHead = NULL;
    //入栈
    for (int i = 0; i < 5; i++)
    {
    push(&pHead, &info[i]);
    }
    travel(pHead);
    printf("\n\n");
    //出栈
    Node* pStackTemp = NULL;
    while (1)
    {
    pStackTemp = pop(&pHead);
    if (pStackTemp == NULL)
    {
    printf("出栈失败\n");
    break;
    }
    Printf(&pStackTemp->data);
    //释放内存
    free(pStackTemp);
    printf("\n\n");
    }
    return 0;
    }

    在这里插入图片描述



链式队列(无头节点)

  • 操作和链式栈基本一致,除了出栈和出队
  • 出队: 先进先出 后进后出 先删除首元节点,再依次往后删除节点
//出队 删除头节点
Node* pop(Node** pHead)
{
if (pHead == NULL || *pHead == NULL)
{
printf("出队失败\n");
return NULL;
}
Node* pTemp = *pHead;
//只有一个节点
if (( * pHead)->next == NULL)
{
*pHead = NULL;
}
else
{
//有多个节点,则跳过第一个
*pHead = ( * pHead)->next;
}
return pTemp;
}
  • 链式队列测试

    • 代码一致,只需要把出队和出栈的代码改一下

    在这里插入图片描述

  • 源码下载

数组链表栈与队列以及C++模板栈与队列

posted @   hugeYlh  阅读(11)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示