c语言实现栈(顺序栈,链栈)(上)

简介: c语言实现栈(顺序栈,链栈)


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


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


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



"栈"的常见接口实现


  • InitST:初始化栈


  • STPush:入栈


  • STPop:出栈


  • STEmpty:判空(判断是否为空栈)


  • PrintSTTop:打印栈顶元素


  • STTop:返回栈顶元素(返回值类型:stacktype)


一、顺序栈


"顺序栈"的类型定义


如果友友们学过顺序表,这种类型可以随便拿捏.😄😄


代码:


typedef struct stack
{
  stacktype* data;//一个指向连续内存空间的指针
  int top;//记录栈顶元素的下标
  int capacaity;
}ST;



1.1 初始化栈


top指针:


由于数组的下标是从0开始,所以我们初始化"栈"时,可以将top指针(栈顶指针)初始化为-1,这样即可代表"栈"中无数据.


capacaity :


同顺序表一样,我们可以设置初始最大容量,后续不够可以扩容.


void InitST(ST* ps)
{
  assert(ps);
  ps->top = -1;//此时栈中无数据
  ps->capacaity = 4;//设置初始最大容量
  ps->data = (stacktype*)malloc(ps->capacaity * sizeof(stacktype));
}


此处初始化后:



1.2 入栈(压栈,向"栈"中插入数据)


学到这里(顺序表和链表),对于"栈"的压栈操作很简单.


  1. 由于是顺序表实现栈,所以在进行插入操作之前要先进行"判满"操作,如果栈满了,要进行扩容.


  1. top是指向栈顶下标,需要将其往后移动一位,使其指向待插入位置.


  1. 将新元素插入.此时刚好top为新的栈顶的下标.


图解:



代码:


void STPush(ST* ps, stacktype x)//压栈
{
  assert(ps);
  if (ps->top+1 == ps->capacaity)//检查"栈"满
  {
    ps->capacaity *= 2;//扩容
    stacktype* tmp = (stacktype*)realloc(ps->data, ps->capacaity * sizeof(stacktype));
    if(tmp == NULL)
    {
      printf("增容失败\n");
    }
    ps->data = tmp;
  }
  //将"栈顶指针"指向待插入位置
  ps->top++;
  //将元素压栈
  ps->data[ps->top] = x;
}


1.3 “出栈”,删除"栈"中的数据


步骤:


  1. 删除数据时,需要判断"栈"是否为空.


  1. 将top向前(下)移动一位,即表示有效数据位减1.


代码:


void STPop(ST* ps)
{
  assert(ps);
  assert(!STEmpty(ps));
  ps->top--;
}


1.4 判空(判断"栈"是否为空)


当栈为空时,top为初始状态-1.


bool STEmpty(ST* ps)//判断是否为空栈,是空返回真
{
  assert(ps);
  if (ps->top == -1)
  {
    return true;
  }
  return false;
}


1.5 打印"栈顶"元素


void PrintSTTop(ST* ps)
{
  assert(ps);
  printf("%d", ps->data[ps->top]);
}


1.6 返回"栈顶"元素


stacktype STTop(ST* ps)//返回栈顶元素
{
  assert(ps);
  return ps->data[ps->top];
}


1.7 "栈"的销毁


栈的销毁操作,因为malloc开辟出来的是连续的空间,所以只需要释放一次即可.


void STDestory(ST* ps)
{
  assert(ps);
  free(ps->data);
  ps->data = NULL;
  ps->top = -1;
  ps->capacaity = 0;
}


二、链栈


"链栈"的类型定义


typedef int stacktype;
// 链栈的类型
typedef struct SLStackNode
{
    stacktype data;
    struct SLStackNode* next;
}SLStackNode;


其实我们不难发现,"链栈"的类型与单链表很相似,通过对"栈"的基本知识了解,"栈"只在一端进行"插入"和"删除"操作,为了用单链表实现这一要求.


同时为了提高效率:


链表 分析
尾插,尾删 效率低,因为需要找尾巴
头插,头插 效率高,只需要改变头指针的指向


综上:我们利用不带头单链表的"头插(入栈)和头删(出栈)"来完成栈的各项基本操作.并且"栈"不需要进行随机访问其中的元素,只能从栈顶访问,链表是可以完成的.


2.1 初始化"链栈"


对于链表实现的栈,如果不带头结点:


我们不需要特意去写一个初始化函数.只需要创建一个栈顶指针,将其初始化指向NULL即可.(下面的代码是采用这种形式)


//创建一个栈顶指针,并完成初始化
SLStackNode* SLStack = NULL;


如果是带头结点的单链表:


我们可以定义一个初始化函数,申请一个头结点(头结点的数据域不存数据),将头结点返回.


//stack.c
SLStackNode* InitStack()
{
  SLStackNode* newnode = (SLStackNode*)malloc(sizeof(SLStackNode));
  if (newnode == NULL)
  {
    perror("newnode malloc fail");
  }
  return newnode;
}
//test.c
SLStackNode* SLStack = InitStack();


2.2 入栈(压栈,向"栈"中插入数据)


步骤:(与单链表的头插类似)


  1. 创建一个新节点.


  1. 将新节点的next指针指向原"栈"的顶点


  1. 更新栈顶指针(将栈顶指针指向新节点)


图解:



代码:


//入栈
void STPush(SLStackNode** pps, stacktype x)//压栈.相当于链表的头插
{
  assert(pps);
  //获取新的结点
  SLStackNode* newnode = BuyNode(x);
  newnode->next = *pps;//将新节点的next指针指向原"栈"的顶点
  *pps = newnode;//更新栈顶
}


2.3 “出栈”,删除"栈"中的数据


步骤:(与链表的头删操作类似)


  1. 判空,防止空链栈的删除操作


  1. 记录原栈顶元素的地址.


  1. 更新栈顶.(将栈顶指针指向原栈顶的下一个结点↓).


  1. 释放原栈顶空间


图解:



void STPop(SLStackNode** pps)//出栈
{
  assert(pps);//二级指针不可能为空,如果为空就一定是传错了
  assert(*pps);//防止空链栈的删除操作
  SLStackNode* head = *pps;//记录栈顶元素的地址
  *pps = (*pps)->next;//更新栈顶,即原来栈顶的下一个结点
  free(head);//释放原栈顶空间
}


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