栈和队列(C语言实现)

简介: 栈和队列(C语言实现)

分析

栈的数据是栈顶进,栈顶出。

我们用数组和链表都可以,但是链表因为尾插和尾删没有数组方便,所以我们用数组。

例子:如果进去的顺序是1234,出来的顺序就是4321。

我们可以用一个数组来储存数据,然后再定义一个指针指向栈顶的数据,方便出栈和入栈。

typedef int SD;//随时更改数据类型
typedef struct stack
{
  SD* a;//数组
  int top;//栈顶的后一个位置
  int capacity;//容量
}ST;

这里用指针定义的数组,后面我们可以用扩容增加容量,这样就变成了一个数组。

初始化与销毁栈

一定要初始化空间,不然容易造成野指针的问题。

初始化

void StackInit(ST* ps)//初始化
{
  assert(ps);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}

初始化就不开辟空间了。

销毁栈

这里和链表不一样,比较方便,释放掉起始地址就好了。

void StackDestroy(ST* ps)//销毁栈
{
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}

出栈入栈与判断栈为空

入栈

void StackPush(ST* ps, SD x)//入栈
{
  assert(ps);
  //扩容
  if (ps->capacity == ps->top)//判断是否需要扩容
  {
    int count = (ps->capacity == 0 ? ps->capacity = 4 : ps->capacity * 2);//第一次扩容4个,之后的扩容的容量二倍增加
    SD* y = (SD*)realloc(ps->a, count * sizeof(SD));
     if (y == NULL)
     {
       perror("realloc fail");
       exit(-1);
     }
     ps->a = y;
     ps->capacity = count;
  }
  ps->a[ps->top] = x;//赋值
  ps->top++;
}

例:

此时的top是4.

判断栈是否为空

bool StackEmpty(ST* ps)//判断
{
  assert(ps);
  return ps->top == 0;//如果为空就返回1,不为空返回0
}

出栈

void StackPop(ST* ps)//出栈
{
  assert(ps);
  assert(!StackEmpty(ps));
  ps->top--;
}

出栈就很简单了,因为top是末尾的数据,如果想再入栈,入栈的地方是top指向的地方,会覆盖掉原来的数据。

获取栈顶元素

SD StackTop(ST* ps)//获取栈顶元素
{
  assert(ps);
  assert(!StackEmpty(ps));
  return ps->a[ps->top - 1];
}

获取栈中有效元素个数

top也就等于栈中数据的数量。

int StackSize(ST* ps)//获取栈中有效的元素
{
  assert(ps);
  return ps->top;
}

队列

分析

队列是从队头出,队尾入,数组就没有链表好用了,所以我们用单向链表。

结点

typedef int SD;
typedef struct QListNode
{
  struct QListNode* next;
  SD data;
}QL;

因为我们需要的是头删尾插,所以不仅仅需要头结点,还需要一个尾结点,这样更方便操作。

typedef struct Queue
{
  QL* head;//头结点,指向队列的队头
  QL* tail;//尾结点,指向队列的队尾
  int siz;//计算有多少个结点
}Qu;

初始化与销毁队列

初始化

头结点和尾结点的指向空即可,siz初始化为0用来记录结点数量。

void QueueInit(Qu* q)//初始化
{
  assert(q);
  q->head = q->tail = NULL;
  q->siz = 0;
}

销毁队列

void QueueDestroy(Qu* q)//销毁队列 
{
  assert(q);
  QL* cur = q->head;//这里要注意数据类型
  while (cur)
  {
    QL* del = cur -> next;
    free(cur);
    cur = del;
  }
  q->head = q->tail = NULL;
  q->siz = 0;
}

入列,出列与判断队列是否为空

入列

这里需要考虑队列是否为空的尾插。

void QueuePush(Qu* q, SD x)//入队
{
  assert(q);
  QL* w = (QL*)malloc(sizeof(QL));//新开辟结点
  if (w == NULL)
  {
    perror("malloc tail");
    exit(-1);
  }
  else
  {
    w->data = x;
    w->next = NULL;
  }
  if (q->head == NULL)//如果队列为空
  {
    q->head = q->tail = w;
  }
  else//如果队列不为空
  {
    q->tail->next = w;
    q->tail = w;
  }
  q->siz++;
}

判断

不为空返回0,为空返回非零。

bool QueueEmpty(Qu* q)//判断
{
  assert(q);
  return q->head == NULL;
}

出列

这里就是典型的头删了,只不过需要注意的是,tail是不会在这个函数中移动的,所以当释放掉tail指向的结点时,要把tail置为空,不然会成为野指针。

void QueuePop(Qu* q)//出队
{
  assert(q);
  assert(!QueueEmpty(q));
  if (q->head == NULL)//防止tail成为野指针
  {
    free(q->head);
    q->head = q->tail = NULL;
  }
  QL* cur = q->head;
  q->head = q->head->next;
  free(cur);
  cur = NULL;
  q->siz--;
}

获取队列头部,尾部元素

这里就体现了head和tail的好处。

头部

SD QueueFront(Qu* q)//获取队头元素
{
  assert(q);
  assert(!QueueEmpty(q));
  return q->head->data;
}

尾部

SD QueueBack(Qu* q)//获取队尾元素
{
  assert(q);
  assert(!QueueEmpty(q));
  return q->tail->data;
}

获取队列中有效元素个数

直接返回之前用于记录数量的siz就可以了。

int QueueSize(Qu* q)//获取队列中有效元素个数
{
  assert(q);
  return q->siz;
}


相关文章
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
251 9
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
74 5
|
3月前
|
C语言
数组栈的实现(C语言描述)
本文介绍了如何在C语言中使用数组来实现栈的数据结构,包括栈的创建、入栈、出栈、获取栈顶元素、检查栈是否为空、获取栈的大小以及销毁栈等操作,并提供了相应的函数实现。
47 1
|
4月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
506 8
|
4月前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
613 3
|
7月前
|
C语言
C语言的栈帧
C语言的栈帧
|
7月前
|
C语言 C++
【数据结构】C语言实现:栈(Stack)与队列(Queue)
【数据结构】C语言实现:栈(Stack)与队列(Queue)
|
7月前
数据结构——栈(C语言版)
数据结构——栈(C语言版)
31 0
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
70 10