顺序表实现学生信息管理(C语言)

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

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

87b8d77149e34b5da788e718df632d6f.png


  下面是具体实现的代码。

SeqList.h

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

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// 顺序表中存储的数据类型,可以根据自己的需要修改
typedef struct student {
  char name[20];
  char sex[5];
  int sno;
  int age;
}SLDataType;  
typedef struct SeqList {
  SLDataType* a;  //指向动态开辟的数组
  int size;   //记录存储数据个数
  int capacity; //空间容量大小
}SL;
// 打印
void SLPrint(SL* ps);
// 初始化与销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
// 尾插尾删
void SLPushBack(SL* ps, SLDataType* x);
void SLPopBack(SL* ps);
// 头插头删
void SLPushFront(SL* ps, SLDataType* x);
void SLPopFront(SL* ps);
// 顺序表查找
int SLFind(SL* ps, int x); 
int Find(SL* ps, int sno);
// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType* x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);
// 扩容函数
void SLCheckCapacity(SL* ps);

main.c

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

#include "SeqList.h"
void TestSeqList()
{
  SL sl;
  SLInit(&sl);
  SLDataType stu1 = { "张三", "男", 110701, 22 };
  SLDataType stu2 = { "李四", "男", 110702, 21 };
  SLDataType stu3 = { "王五", "女", 110703, 23 };
  SLDataType stu4 = { "赵六", "女", 110704, 22 };
  SLDataType stu5 = { "周七", "男", 110705, 23 };
  SLPushBack(&sl, &stu1);
  SLPushBack(&sl, &stu2);
  SLPushBack(&sl, &stu3);
  SLPushBack(&sl, &stu4);
  SLPrint(&sl);
  SLInsert(&sl, 2, &stu5);
  SLPrint(&sl);
  // 查找可以有多种方式,按照不同的信息查找,这里只是以学号为例
  int n = SLFind(&sl, 110703);
  printf("%d\n", n);
  SLErase(&sl, 2);
  SLPrint(&sl);
  SLDestroy(&sl);
}
int main() 
{
  TestSeqList();
  return 0;
}

SeqList

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

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

 顺序表的初始化,相当于int a = 0;实际上这个功能并不是很必要,但是为了代码的规范,以及防止一些错误的出现,建议要进行初始化,一个合格的程序员应该具备初始化意识。

void SLInit(SL* ps) 
{
  assert(ps);
  ps->a = NULL;
  ps->size = 0;
  ps->capacity = 0;
}

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


void SLDestroy(SL* ps) 
{
  assert(ps);
  if (ps->a) {
    free(ps->a);
    ps->a = NULL;
    ps->size = ps->capacity = 0;
  }
}

检查是否需要扩容,只要在进行数据插入时都需要检查是否需要扩容,然后我们这里有头插尾插和在pos位置插入数据,所以单独把这一功能作为一个函数写出来。提高代码的复用,这样就不用每次都写这么一串代码出来。

 注意:在动态开辟空间之后一定要检查空间是否开辟成功了,如果不检查的话可能会出现一些不可预料的错误。malloc和realloc开辟空间都会是返回一个指针,只是在开辟失败后返回的是一个空指针,所以我们只需要检查返回值是否是NULL就行了。

void SLCheckCapacity(SL* ps) 
{
  assert(ps);
  if (ps->size == ps->capacity) 
  {
    // 判断是没有空间还是空间不够,如果是没有空间就给个初始空间,空间不够,就把空间扩大一倍
    int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    // 按照数据类型来进行空间扩容
    SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
    // 检查空间是否开辟成功
    if (NULL == tmp)
    {
      perror("realloc fail");
      exit(-1);//终止程序
    }
    ps->a = tmp;
    ps->capacity = newCapacity;
  }
}

顺序表的尾插和尾删,因为空间是动态开辟的,所以应该在插入数据之前使用SLCheckCapacity()来确保空间是能够允许插入一个数据,在数据插入之后元素个数要加一,不然加了和没加没有区别,因为虽然你空间上存在这个数据了,但是你的函数访问不到这个数据。

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

void SLPushBack(SL* ps, SLDataType* x) 
{
  assert(ps);
  SLCheckCapacity(ps);
  ps->a[ps->size] = *x;
  ps->size++;
}
void SLPopBack(SL* ps) 
{
  assert(ps);
  assert(ps->size > 0);
  ps->size--;
}

 顺序表的头插和头删,这里和尾插尾删的区别不是很多,不过有一个点需要注意的是,头插和头删需要移动数据。头插时需要将数据挨着向后移动一位,然后在头部插入数据。头删时,也是采用的覆盖,数据向前移动覆盖掉前一个数据就行了。

void SLPushFront(SL* ps, SLDataType* x) 
{
  assert(ps);
  // 在数据插入前检查是否需要扩容
  SLCheckCapacity(ps);
  int end = ps->size - 1;
  while (end >= 0) 
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[0] = *x;
  ps->size++;
}
void SLPopFront(SL* ps)
{
  assert(ps);
  assert(ps->size > 0);
  int begin = 0;
  while (begin < ps->size - 1) 
  {
    ps->a[begin] = ps->a[begin + 1];
    begin++;
  }
  ps->size--;
}

 在pos插入或者删除数据,这组函数的功能实际上是包括头插头删、尾插尾删的,可以用这组函数分别头插头删、尾插尾删。

void SLInsert(SL* ps, int pos, SLDataType* x) 
{
  assert(ps);
  assert(pos >= 0);
  assert(pos <= ps->size);
  // 在数据插入前检查是否需要扩容
  SLCheckCapacity(ps);
  int end = ps->size - 1;
  while (end >= pos) 
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[pos] = *x;
  ps->size++;
}
void SLErase(SL* ps, int pos) 
{
  assert(ps);
  assert(ps->size >= pos);
  int ret = pos;
  while (ret < ps->size - 1) 
  {
    ps->a[ret] = ps->a[ret + 1];
    ret++;
  }
  ps->size--;
}

查找有多种方式,如顺序查找、二分查找这些,也可以按学号、姓名、年龄这些的来查找,我这里只是写了一个按学号进行的顺序查找。

// 查找数据
int SLFind(SL* ps, int x) 
{
  return Find(ps, x);
}
int Find(SL* ps, int sno)
{
  int i = 0;
  while (i < ps->size) 
  {
    if (ps->a[i].sno == sno) 
      return i;
    i++;
  }
  return -1;
}
目录
相关文章
|
6月前
|
存储 算法 程序员
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
158 0
|
6月前
|
C语言
C语言顺序表
C语言顺序表
55 0
|
9天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
33 3
|
30天前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
19 2
|
30天前
|
C语言
链式顺序表实现(C语言描述)
本文介绍了如何在C语言中实现链式顺序表,包括数据结构的定义、节点的创建、数据的插入和删除以及链表的打印和销毁。
35 2
|
30天前
|
C语言
顺序表数组法构建(C语言描述)
如何使用C语言通过数组方法构建有序顺序表,包括顺序表的创建、插入、删除和打印等。
16 2
|
2月前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
181 5
|
2月前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
5月前
|
存储 C语言
数据结构——顺序表(C语言版)
数据结构——顺序表(C语言版)
61 5
|
6月前
|
存储 C语言
C语言实验-动态顺序表实现简易通讯录(二)
在这个C语言实验中,你将实现一个简单的通讯录,它使用动态顺序表来存储联系人信息。
50 2