【C语言数据结构(基础篇)】第二站:顺序表(上)

简介: 【C语言数据结构(基础篇)】第二站:顺序表

一、线性表

首先我们必须要了解的一个概念是线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。

顺序表就是数组,他的内存是连续的

下面就是一个链表的结构,当然或许你现在并不知道链表是什么,但是没有关系, 我们在后面的文章中将会花费大量的笔墨去详细讲解链表,这里你只需要大概看一眼就可以了,下图什么都看不懂是没有任何关系的。

二、顺序表的实现(概念以及静态顺序表)

对于顺序表的实现,我们采用分文件的形式来展现,在前面我们也已经利用了两个小游戏来让大家熟悉了分文件的写法,这里就不在赘述。如果还有不懂的地方,可以去C语言专栏去找到对应的文章。同样数据结构部分,为了规范我们的写法,我们全部采用大驼峰的命名风格

1.创建三个工程文件

如下图所示,我们创建好三个文件,分别是SeqList.c SeqList.h Test.c

SeqList.c用于顺序表的实现

SeqList.h用于顺序表的声明

Test.c用于测试顺序表

2.顺序表的概念

我们得先了解顺序表的概念,才能继续完成下去

顺序表是一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

顺序表一般可分为

静态顺序表:使用定长数组进行存储

动态顺序表:使用动态开辟的数组进行存储

3.顺序表的定义

我们先看静态顺序表是如何定义的,如下图所示,我们知道顺序表他也是用来存储数据的,既然是用来存储数据的,那么他必然要有一个数组来存储,然后还要有一个size来确定目前存储了一个数据。将这两个合并到一起就是一个结构体

虽然说这可以当作一个静态顺序表来进行定义,但是要真是这样定义,还是会出现很多问题,比如说哪一天想要存储100个数据了,那么我们上面这个就是写死了,根本没法改。所以我们可以使用define来进行优化,如下图所示

这样的话,确实,解决了一些后续无法增加数据的问题,但是如果突然不想要整型类型了,他想要char类型的话,那这个顺序表又废了,所以我们还得再次进行优化,我们可以使用一个typedef来重定义类型,如下图所示

当然这样其实还不够好,我们如果想要使用这个结构体的话,这个结构体类型太长了,我们写着写着都快烦死了。所以我们也可以对结构体进行typedef

如下图所示,我们让这个结构体类型变成了SL,当然这个有两种写法,一种是使用注释中的写法,另外一种就是在定义结构体的时候就typedef

最终代码如下(SeqList.h这个文件)

#pragma once
#define N 10
typedef int SQDateType;
typedef struct SeqList
{
  SQDateType arr[N];
  int size;
}SL;
//等价于typedef struct SeqList SL;

4.初始化顺序表

我们在说顺序表的概念的时候就提到过,顺序表是要实现增删查改四大功能的,但是在这之前,我们得先初始化顺序表

于是我们在头文件先进行一次初始化函数的声明

在SeqList.c文件中,我们就要实现这个功能了,如下图所示,我们使用一个memset函数,在这里可能有些人还不熟悉或者不太了解这个函数,我们可以现场学习一下 ,如下图所示,他是将传入的一个指针,从他开始的前num个字节都设置为value

所以下面中的意思就是将这个数组的全部元素设置为0,并且将size也就是目前的元素个数也设置为0

而对应这个函数也有他自己的头文件,我们为了方便,可以直接全部放在SeqList.h中

既然如此,那么我们就开始来测试一下这个函数究竟对不对

我们打完断点以后,直接使用F5,跳转至断点处,并打开调试的监视窗口,如下图所示,我们已经将顺序表给初始化完成了

我们开始进入我们的函数,我们发现,这块并没有将这个顺序表给初始化啊。这是为什么呢?

其实这块已经很多人发现了这个问题,因为我们传的其实是形参,形参的改变不会影响实参。我们就不该使用这个传值调用了,我们应该使用传址调用,我们现在将我们的代码都改为指针

而此时就能够完成我们的目标了,实现初始化顺序表

顺序表初始化接口代码为

//顺序表初始化
void SeqListInit(SL* ps)
{
  memset(ps->arr, 0, sizeof(SQDateType) * N);
  ps->size = 0;
}

5.静态顺序表的尾插

在我们将顺序表给初始化以后,我们现在需要的就是试下顺序的表的增删查改,当然我们在讲述顺序表的概念的时候,提到了这两个关键点:

1.连续的物理存储地址------数组

2.数据必须是从头开始,依次存储------不能在数组的第一个元素插入一个,然后第二个又跑到了第三个元素上

那么我们就先来定义一下我们的接口函数,如下图所示,这里我们的命名与c++的标准库一致,让我们的程序更加规范

不过既然有尾插,那么与之对应的就有头插,尾删,以及头删,不妨我们也直接定义好他们的接口吧,如下图所示

那么我们先来实现尾插,如何实现尾插呢?我们可以试着画图理解一下,如下图所示,我们假设数组已经存储了5个元素了,此时他的size就是5,那么这个5刚好就是下一个数据的下标,所以我们就想到了,有了下标了,那不就是直接插入数据了吗。插入完之后再让size++就行了吗,确实是这样的。

我们来实现一下我们的想法,如下图所示

但是这样存在一个问题,如果顺序表满了呢?我们可以实验一下

我们进行调试,如下图所示,顺序表已经初始化完成

我们使用F10不进入函数内部进行调试,我们可以发现现在即将越界

此时已经越界了,我们发现arr[10]他与size进行同步变化,size直接变成了12,而不是变成了11,这个问题,在我们之前讲解调试的时候已经提到过了,这就是数组越界所带来的风险。size的数据已经被破坏了。所以这个顺序表已经废了

那么我们该怎么办呢?我们可以在顺序表满的时候提示一句顺序表满了,然后就直接返回,直接拦截这个错误的信息,不让他插入进去,所以实现如下

这个时候我们再次调试一下,此时我们发现,拦截成功了。

其实到这块我们也发现一个问题,那就是静态顺序表不太好,要么消耗的空间太大,要么空间不够。总之很麻烦。而我们一般下也不会去使用静态的顺序表,我们都是使用动态的顺序表,可以进行扩容的顺序表。

所以我们在这里就不在继续进行实现静态的顺序表的,我们转而实现动态的顺序表

相关文章
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
734 1
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
238 4
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
本文档介绍了线性表的基本运算任务,涵盖顺序表和链表的初始化、销毁、判定是否为空、求长度、输出、查找元素、插入和删除元素等内容。通过C++代码示例详细展示了每一步骤的具体实现方法,并提供了测试说明和通关代码。 主要内容包括: - **任务描述**:实现顺序表的基本运算。 - **相关知识**:介绍线性表的基本概念及操作,如初始化、销毁、判定是否为空表等。 - **具体操作**:详述顺序表和链表的初始化、求长度、输出、查找、插入和删除元素的方法,并附有代码示例。 - **测试说明**:提供测试输入和预期输出,确保代码正确性。 - **通关代码**:给出完整的C++代码实现,帮助完成任务。 文档
464 5
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
511 5
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
600 1
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
834 23
|
7月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1424 0