数据结构------栈(Stack)和队列(Queue)

简介: 数据结构------栈(Stack)和队列(Queue)

也是好久没写博客了,那今天就回归一下,写一篇数据结构的博客吧。今天要写的是栈和队列,也是数据结构中比较基础的知识。那么下面开始今天要写的博客了。


喜欢就点个赞吧。


栈(Stack)

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除 操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out) 的原则。


压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。


出栈:栈的删除操作叫做出栈。出数据也在栈顶。


简单描述栈的特点:栈数据的增删都是在一头进行,即在栈顶


那栈又该如何创建与使用呢?他的原理又是怎样的,这里我们就用C语言实现一下。


我们这里就要想这个栈是要用数组来实现还是用链表来实现呢?其实我们可以从其功能开始思考,这两者哪个更好去实现栈的功能,而且效率较高,其实说到这里,很多人可能已经有了结果,其实要说简洁与效率数组更适合来做栈。那么我们下面就来完成一下这个代码完成一个栈。


这里先给头文件因为其中有typedef来命名的类型,以免各位佬看得迷惑。


头文件


这里解释一下DataType是各位做栈时储存数据的类型,需要改变时只需要在头文件里改动一下即可,例如你想变成char类型的数据,即可将typedef int DataType; 改为 typedef char DataType;

然后栈的结构体我们就用ST来简化方便写代码。

然后top为栈的数据个数,capacity就表示栈的容量

 

#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
typedef int DataType;
 
typedef struct Stack
{
  DataType* a;
  int top;
  int capacity;
  
}ST;
 
 
void StackInit(ST* ps);
void StackDestory(ST* ps);
// 入栈
void StackPush(ST* ps, DataType x);
// 出栈
void StackPop(ST* ps);
DataType StackTop(ST* ps);
 
int StackSize(ST* ps);
bool StackEmpty(ST* ps);


栈的格式化

void StackInit(ST* ps)
{
  assret(ps);
  ps->a = (DataType)mallco(4 * (sizeof(DataType)));
  if (ps->a == NULL)
  {
    printf("malloc fail\n");
    exit(-1);
  }
  ps->capacity = 4;
  ps->top = 0;
 
}


先将数组a  mallco出四个数据的大小,然后将容量capacity改为4.


栈的销毁

void StackDestory(ST* ps)
 
{
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->top = ps->capacity = 0;
 
}

使用完栈后进行销毁得函数,防止内存泄露。 及时free掉,然后将a指向NULL。


入栈

void StackPush(ST* ps, DataType x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    DataType* tem = (DataType*)recalloc(ps->a, 2*ps->capacity*sizeof(DataType));
    if (tem == NULL)
    {
      printf("racallco fail\n");
    }
    else
    {
      ps->a = tem;
      ps->capacity = 2 * ps->capacity;
    }
 
  }
 
    ps->a[ps->top] = x;
    ps->top++;
  
}
 


第一个if,先判断数组a是否还有空间入栈,如果满了就进行recallco增容即可增容我们现在时增容两倍较为合适,recallco的用法在前面动态内存创建的文章已经讲过了。所以现在就不多解释了。入栈后记得将top++一下 。


出栈

void StackPop(ST* ps)
{
  assert(ps);
  assert(ps->top > 0);
 
  
  ps->top--;
}


这里就比较简单粗暴将top--,即可将原本栈顶得书局给屏蔽即可。


求栈的长度和判断栈是否为空

int StackSize(ST* ps)
{
  assert(ps);
  return ps->top;
}
 
 
bool StackEmpty(ST* ps)
{
  assert(ps);
 
  return ps->top == 0;
}

接下来我们就来看看队列


队列(Queue)

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先 进先出FIFO(First In First Out)

 

队列的特点:队列与栈的不同是他是在一头进行增数据,一头删数据,而栈数据的增删都是在一头。


然后我们思考一下队列的功能实现是要数组好还是链表好呢,这么一想是不是马上就发现了,如果们还是用数组来实现的话,那么其出队列的时间复杂度为O(N),那么效率太低了,而链表实现的话则是O(1),显而易队列还是用链表实现较好。


下面就是队列函数的实现了。

还是先给大家看看头文件

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
 
typedef int Type;
 
typedef struct Queuenode 
{
  Type* date;
  struct Queue* next;
 
}Node;
 
 
typedef struct Queue
{
  Node* head;
  Node* tail;
}Queue;
 
 
void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);
 
// 队尾入
void QueuePush(Queue* pq, Type x);
// 队头出
void QueuePop(Queue* pq);
 


这里解释一下为什么创建了两个结构体 ,因为其中一个作为链表的节点而另一个队列结构体。队列的结构体我们只需要要一个队头和队尾。


队列的格式化

 

void QueueInit(Queue* pq)
{
  assert(pq);
  pq->head = NULL;
  pq->tail = NULL;
 
 
 
}

很简单将队头和队尾指向空NULL即可。


队列的销毁

void QueueDestory(Queue* pq)
{
  assert(pq);
 
  Node* cur = pq->head;
  while (cur)
  {
    Node* next = cur->next;
    free(cur);
    cur = next;
 
  }
 
  pq->head = pq->tail = NULL;
 
 
}


这里我们运用一个while循环,创建一个辅助指针来保存节点的下一个。不断free 掉即可。

注意要将队头和队尾指空NULL。


进队

 

void QueuePush(Queue* pq, Type x)
{
  assert(pq);
  Node* new = (Node*)mallco(sizeof(Node));
  if (new == NULL)
  {
    printf("mallco fail\n");
  }
  new->date = x;
  new->next = NULL;
  if (pq->tail = NULL)
  {
    pq->tail = new;
        pq->head = new;
  }
 
 
  else
  {
    pq->tail->next = new;
    pq->tail = new;
 
  }
 
}


我们mallco一个空间,作为进队的一个节点,然后对节点进行赋值,然后对链表进行尾插就完成了一半了。


需要注意的是记得把原来的tail的next 指向新节点,也要把tail改为 新节点,因为尾插后new就为最后的节点也就是尾了。注意当前有没有节点那将head和tail至为new即可。

出队

void QueuePop(Queue* pq)
{
  assert(pq);
  assert(pq->head);
  
  if (pq->head->next == NULL)
  {
    free(pq->head);
    pq->head = NULL;
    pq->tail = NULL;
  }
 
 
  Node* next = pq->head->next;
  free(pq->head);
  pq->head = next;
 
 
 
}


这里也是根据队列的删数据特点,这里的出队就是头删了,我们先把head的next保存住,然后free掉head,再然后让next作为新的头。

 


今天就结束了,希望您能喜欢这篇文章。


目录
相关文章
|
4天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
142 77
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
38 7
|
1月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
44 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
46 9
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
99 5
|
3月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
72 0
|
3月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
55 1
|
3月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
116 21
|
3月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。

热门文章

最新文章