栈实现学生信息管理(C语言)

简介: 栈实现学生信息管理(C语言)

用栈实现学生信息管理。这里放一下有哪些文件。


1834bbdc388f420191232ec43978cb4a.png


Stack.h


#pragma once防止库函数的重复引用,因为库函数会在预编译的时候在程序中展开,会增大程序的体积。

 通过typedef对数据重命名,之后需要修改数据就十分方便。并且其他函数不需要太多的改动。

 这里结构体传的是指针,减少没必要的内存消耗。

 栈的特性是先进后出,所以不存在什么头插尾插和头删尾删之类的,数据的插入被称为入栈,只有一种方式。数据的删除被称为出栈,也只有一种方式。

 栈的top是表示栈顶,而不是用来表示元素个数的。虽然他们实质上的数值可能差别不大,但是意义并不相同。


#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
// 支持动态增长的栈
typedef struct student {
  char name[20];
  char sex[5];
  int sno;
  int age;
}STDataType;
typedef struct Stack
{
  STDataType* a;
  int top;    // 栈顶
  int capacity; // 容量
}Stack;
// 打印
void StackPrint(Stack* ps);
//初始化栈
void StackInit(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);
//入栈
void StackPush(Stack* ps, STDataType* x);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
STDataType* StackTop(Stack* ps);
//获取栈中有效元素个数
int StackSize(Stack* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);

main.c

  因为重点在于数据结构链表的使用,所以直接给定一些数据,就不进行重复繁琐的数据输入工作了。

#include "Stack.h"
int main()
{
  Stack st;
  StackInit(&st);
  STDataType stu1 = { "张三", "男", 110701, 22 };
  STDataType stu2 = { "李四", "男", 110702, 21 };
  STDataType stu3 = { "王五", "女", 110703, 23 };
  STDataType stu4 = { "赵六", "女", 110704, 22 };
  STDataType stu5 = { "周七", "男", 110705, 23 };
  StackPush(&st, &stu1);
  StackPush(&st, &stu2);
  StackPush(&st, &stu3);
  StackPush(&st, &stu4);
  StackPush(&st, &stu5);
  StackPrint(&st);
  printf("size:%d\n\n", StackSize(&st));
  STDataType* top = StackTop(&st);
  printf("%d %s %d %s\n\n", top->sno, top->name, top->age, top->sex);
  StackPop(&st);
  StackPop(&st);
  StackPop(&st);
  StackPrint(&st);
  printf("size:%d\n", StackSize(&st));
  StackDestroy(&st);
  return 0;
}

Stack.c

  打印函数的实现,如果栈中的数据类型发生了改变,其他功能函数基本上不需要有什么变化, 打印函数对应修改一下就行了,因为打印需要涉及到具体的数据问题

void StackPrint(Stack* ps)
{
  int n = StackSize(ps);
  for (int i = 0; i < n; ++i)
  {
    printf("%d %s %d %s\n", ps->a[i].sno, ps->a[i].name, ps->a[i].age, ps->a[i].sex);
  }
  printf("\n");
}

 栈的初始化,先动态开辟一块空间,然后将top置为0,把capacity置为4。

void StackInit(Stack* ps)
{
  assert(ps);
  //开空间
  ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
  if (ps->a == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  ps->top = 0;
  ps->capacity = 4;
}

数据入栈,因为这里只有这一个插入数据的函数,所以没有必要将检查空间的功能单独提取出来,就在插入数据时检查是否需要开辟空间就可以了。

 如果空间不够,每次空间的扩容是按之前2倍进行扩容的。这样扩容的原因是在避免重复扩容和空间浪费之间的一种平衡的选择。

void StackPush(Stack* ps, STDataType* x)
{
  assert(ps);
  if (ps->top == ps->capacity)
  {
    STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
    if (tmp == NULL)
    {
      perror("realloc fail");
      exit(-1);
    }
    ps->a = tmp;
    ps->capacity *= 2;
  }
  ps->a[ps->top] = *x;
  ps->top++;
}

这里的出栈操作和顺序表的删除数据操作相似,我们并不需要真正的删除掉这个数据,而且要删除掉一个数据实际上并不好删。我们要做的只是让我们的程序访问不到已经被删除的数据就行了,也就是只要top减一就可以了。当我们在插入新数据时,如果插入位置是有数据的,这个数据就会被覆盖掉,所以我们删没删这个数据,实际上是没有影响的。就相当于他有一个初始值而已,但是初始值并不是不能被改变的。

void StackPop(Stack* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  ps->top--;
}

检测栈是否为空,如果为空返回非零结果,如果不为空返回0。

int StackEmpty(Stack* ps)
{
  assert(ps);
  //如-1为空,如果等式成立,结果为真,返回真,非零为真
  return ps->top == -1;
}

获取栈顶元素,所以需要返回栈中存储的数据,但是我们的数据是一个结构体。直接返回一个结构体会占用很多内存,所以返回一个结构体指针。

 获取栈顶元素之前,我们需要检查这个栈中是否有元素,如果没有元素,那肯定是获取不到栈顶元素的。这里通过断言直接报错。

STDataType* StackTop(Stack* ps)
{
  assert(ps);
  assert(!StackEmpty(ps));
  return &(ps->a[ps->top - 1]);
}

获取栈中有效元素个数

int StackSize(Stack* ps)
{
  assert(ps);
  return ps->top;
}

销毁栈,因为采用的是动态开辟空间的方式,所以需要释放空间,如果不释放空间会造成内存泄露。这里我们需要先释放内存空间,然后再把指向这块内存空间的指针置为NULL,否则可能会出现非法访问的问题。之后的top和capacity也应该跟着置为0,一方面,空间已经销毁了,他具备的数据个数和容量本身就应该没有了。另一方面,防止让人误以为有数据或者有空间而去进行一些非法操作。

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