[C语言数据结构]栈

简介: [C语言数据结构]栈

1.栈的定义:

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

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

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

1.2栈的特性:

先进后出

栈的最经典的特性就是先进后出,也可以被叫做后进先出;
这怎么理解呢,就相当于是枪的弹夹,在填装子弹的时候和取出子弹的时候,我们会发现最先放进去的子弹反而是被最后取出的,而最后放入的子弹是最先放进去的;

1.3栈的实现:

分析:对于栈的实现来说,我们有两种数据结构可待选择;

一种是链表,一种是数组;

对于栈的话我们要进行的最多的就是出栈和入栈的操作了。

首先我们来讲数组:数组对于实现入栈出战来说还是很方便的,特别是选用尾部为栈顶的话。只需要的就是数组的扩容问题,只需要调用realloc函数即可。

再其次是链表:对于链表的话我们如果选用单链表的话,若是选用尾部为栈顶的话,我们就很麻烦,每次都需要遍历找到链表的尾指针;

而且相对来说数组的尾插和尾删的效率都很高。

所以这里我们选择先使用数组来实现栈;

1.4代码:

1.4.1结构的声明:

首先我们来分析对于一个用数组来实现的栈来说,我们只需要有一个数组指针,标记栈顶位置的变量,和一个记录栈的容量的变量;

typedef int STDataType;
typedef struct Stack
{
  STDataType* a;
  int top;
  int capacity;
}ST;

1.4.2栈的初始化:

void StackInit(ST* ps);这个函数我们实现的是对于栈的初始化,这个函数的参数是一个结构体类型的指针,我们只需要将结构体内部包含的一个数组指针置空,和两个分别表示栈顶位置的变量和栈的容量的变量都置成零即可。

这里有一个要注意的点就是我们把top也置为0,就是表示top每次指向的是栈顶的后一个位置;(这一点很重要后面的出栈和入栈都会用到)

代码:

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

1.4.3入栈:

void StackPush(ST* ps, STDataType x);

这个函数来试下入栈的操作,对于入栈来说我们最需要注意的就是空间问题,因为数组的大小是给固定的所以我们要在每次入栈的时候要进行一次判断,判断是否需要扩容,并且这里要注意的是top指的是栈顶的后一个位置,所以我们执行的是先插入数据后,再将top++的;

代码:

//入栈
void StackPush(ST* ps, STDataType x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    int newCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
    STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
    if (tmp == NULL)
    {
      printf("realloc fail\n");
      exit(-1);
    }
    ps->a = tmp;
    ps->capacity = newCapacity;
  }
  ps->a[ps->top] = x;
  ps->top++;
}

1.4.4出栈

void StackPop(ST* ps);

对于数组实现的栈来说,出栈的操作非常简单,我们只需要将记录栈顶的位置的变量top--即可。

代码:

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

1.4.5拿到栈顶的数据
STDataType StackTop(ST* ps);

这个函数实现的就是返回栈顶的数据,只需要将数组中对应栈顶的数据返回即可,这里需要注意的就是,在返回栈顶数据的时候数组的下标用的是top-1;

代码:

//拿到栈顶的数据
STDataType StackTop(ST* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  return ps->a[ps->top - 1];
}

1.4.6栈的大小

int StackSize(ST* ps);

这个函数返回的是栈的大小,只需要将top返回即可;
代码:

//栈的大小
int StackSize(ST* ps)
{
  assert(ps);
  return ps->top;
}

1.4.7判断栈是否为空
bool StackEmpty(ST* ps);

如果栈的空间是空,我们就返回假,如果栈的空间是不为空,就返回真;

代码:

//栈是否为空
bool StackEmpty(ST* ps)
{
  assert(ps);
  return ps->top == 0;
}

1.4.8栈的销毁

void StackDestroy(ST* ps);

将数组指针置空,然后其他变量置为0即可;

代码:

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

以上就是栈用数组的实现了!

这里再推荐一个用到栈的力扣题大家可以去试一试练练手:

20. 有效的括号 - 力扣(LeetCode)

2.完整代码

源文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
//栈的初始化
void StackInit(ST* ps)
{
  assert(ps);
  ps->a = NULL;
  ps->top = 0;
  ps->capacity = 0;
}
//入栈
void StackPush(ST* ps, STDataType x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    int newCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
    STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
    if (tmp == NULL)
    {
      printf("realloc fail\n");
      exit(-1);
    }
    ps->a = tmp;
    ps->capacity = newCapacity;
  }
  ps->a[ps->top] = x;
  ps->top++;
}
//栈的销毁
void StackDestroy(ST* ps)
{
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}
//出栈
void StackPop(ST* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  ps->top--;
}
//拿到栈顶的数据
STDataType StackTop(ST* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  return ps->a[ps->top - 1];
}
//栈的大小
int StackSize(ST* ps)
{
  assert(ps);
  return ps->top;
}
//栈是否为空
bool StackEmpty(ST* ps)
{
  assert(ps);
  return ps->top == 0;
}

头文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
  STDataType* a;
  int top;
  int capacity;
}ST;
//栈的初始化
void StackInit(ST* ps);
//栈的销毁
void StackDestroy(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//拿到栈顶的数据
STDataType StackTop(ST* ps);
//栈的大小
int StackSize(ST* ps);
//栈是否为空
bool StackEmpty(ST* ps);

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void Teststack()
{
  ST st;
  StackInit(&st);
  StackPush(&st, 1);
  StackPush(&st, 2);
  StackPush(&st, 3);
  StackPush(&st, 4);
  while (!StackEmpty(&st))
  {
    printf("%d ", StackTop(&st));
    StackPop(&st);
  }
  StackDestroy(&st);
}
int main()
{
  Teststack();
  return 0;
}

以上就是本篇博客的所有内容了,如果帮到你请点赞关注收藏一下!

相关文章
|
3月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
94 1
|
3月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
81 4
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
142 77
|
4天前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
4天前
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
1月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
44 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
22天前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
1月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
46 9
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
38 7
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
99 5

热门文章

最新文章