C 语言实现抽象数据类型(ADT)之链表
C 语言实现抽象数据类型(ADT)之链表
1 什么是链表?(懂跳)
C 语言本身自带了很多基本数据类型,每种基本数据类型的变量总是代表着某个数据,比如:我们通常用整型变量来计数,用浮点型变量来保存价格这样的数据……
int count;
double price;
而有时候我们需要表示的数据很复杂,比如我们想要保存一件商品的价格的同时,也能够保存这件商品的名称,这个时候结构体就派上用场了。
struct Book {
char bookName[100];
double bookPrice;
}
而像这样的多元数据,往往不止一个,我们通常的做法是使用结构体数组。
struct Book books[100];
但结构体数组的元素个数是有上限的,而且数组开辟的内存空间是连续的,这样内存利用率不高。在实际开发过程中,数据个数通常都是不确定的,都是动态变化的。
所以可以使用C 语言的动态内存分配在程序运行期间,动态的为每个这样的数据开辟空间。
(struct Book*)malloc(sizeof(struct Book));
但这样又有一个问题,就是每为一个数据开辟内存空间,就需要使用一个指针变量来保存它的地址,而如果使用数组来保存这些指针,虽说指针数组占用空间比较小,但显然又回到了最初的问题,就是数据的个数是有上限的。
而如果也使用动态内存分配的方式存储指针,那么存储这些指针的内存空间又需要新的指针“跟踪”。
于是就有了链表。
我们可以在每为一个数据开辟空间的时候,把这个数据的内存地址保存在上一个数据中,这样一来,只有第一个数据的指针需要另外保存,这个指针叫做头指针。
struct Book {
char bookName[100];
double bookPrice;
struct Book* next;
}
//每一个块数据中都存储着下一个数据的内存地址
//如果是最后一个,把其中“下一个”的指针赋为NULL即可
struct Book* head; //只需要一个头指针定位整条链表的头即可
这样一来,通过动态内存分配为每一个数据分配的内存空间,都被巧妙的链接了起来,于是把这种数据结构称为链表。把其中的每一块内存空间又形象的称为一个节点。

2 数据的封装
为了提高代码的复用性,我们在创建链表之前,应该对元数据进行封装。
我们可以将元数据的定义放在一个头文件中。
/*MyType.h*/
#pragma once
struct MyType {
/*......*/
};
typedef struct MyType Item;
这样元数据就被封装成了Item类型。后面如果我们想要修改元数据类型,只需要需改此文件中的定义即可。
然后分别通过LinkedList.h和LinkedList.c两个文件来实现链表。
/*LinkedList.h*/
#pragma once
#include "MyType" //包含Item的定义
#include <stdbool.h> //使用bool
//封装节点
typedef struct listNode {
Item item;
struct listNode* next;
}Node;
//抽象:链表类型,用于存储链表头指针和其他信息
typedef struct linkedList {
Node* head; //头指针,必须,不仅定位头节点,也定位整个链表
Node* tail; //尾指针:为了方便在链表末尾追加节点,不是必须
bool isNull; //存储一个链表是否为空的布尔值
unsigned nodeCount; //存储链表中的节点数
}List;
如此一来,就完成了从元数据到链表的封装,封装不是必须的。
3 实现接口API
为什么要把链表封装成一种抽象数据类型(ADT)?在开发中,数据结构就像是,在造汽车中的轮胎一样,几乎是开发过程中必然会使用的工具,我们为了追求开发效率,必然不可能每次开发都去“造轮子”,所以把链表封装成一种抽象数据类型(ADT)可以大大简化后续的开发工作。
所以我们把对链表的所有操作都抽象得封装成函数,即把它当成一种数据类型,就如同C语言的内置类型一样。
每一种数据类型,都有属性和相关操作这两个特征,比如int类型的属性就是表示一个整数,相关操作有加减乘除等。
而链表的属性就是表示多个、内存空间不连续的相同类型的数据。和数组的概念类似(数组也是一种数据结构),只不过链表要比数据灵活,将其抽象封装的一个目的,就是能像使用数组那样简单而高效的使用链表这种数据结构。
链表的操作和数组有所不同,它更加复杂。它所有的操作都需要借助函数来完成。
- 初始化链表
void initList(List* const pList);//const 表示这个函数不会改变plist的值
- 判断一个链表是否为空
bool isListEmpty(const List* const pList);//const分别表示不会改变*pList和pList的值
- 获取一个链表中元数据的数量(节点数)
unsigned itemsCountOfList(const List* const pList);
- 在链表末尾添加一个元素
bool appendItemToList(List* const pList, const Item* const pItem);
- 清空一个链表
void clearList(List* const pList);
- 对链表中的每一项都执行某个函数(遍历链表)
void traverseList(const List* const pList, void(*pfun)(Item* pItem));
由于元数据的不同,所以不涉及任何对元数据的操作,这必须由实现元数据的人来写,或者说与元数据的定义写在一起。
等等……
关于链表的操作不止这些,这里只演示这些。
将这些接口函数的声明写在LinkedList.h中,然后在LinkedList.c中实现。这样做的好处是,隐藏具体实现,将接口对外公开;后续使用链表时,只需查看头文件即可一目了然。
/*LinkedList.c*/
#include "LinkedList.h"
#include <stdlib.h>
#include <stdbool.h>
void initList(List* const pList) {
if (pList != NULL) { //防止访问空指针
pList->head = NULL;
pList->tail = NULL;
pList->isNull = true;
pList->nodeCount = 0;
}
}
bool isListEmpty(const List* const pList) {
return pList->isNull;
}
unsigned itemsCountOfList(const List* const pList) {
return pList->nodeCount;
}
bool appendItemToList(List* const pList, const Item* const pNewItem) {
if (pList != NULL) {
Node* pNewNode = (Node*)malloc(sizeof(Node));
if (pNewNode != NULL) {
pNewNode->item = *pNewItem;
pNewNode->next = NULL;
if (pList->head == NULL) {
pList->head = pNewNode;
pList->isNull = false;
} else {
pList->tail->next = pNewNode;
}
pList->tail = pNewNode;
pList->nodeCount++;
return true;
}
}
return false;
}
void traverseList(const List* const pList, void(*pfun)(Item* item)) {
Node* pNode = pList->head;
while (pNode != NULL) {
pfun(&pNode->item);
pNode = pNode->next;
}
}
void clearList(List* const pList) {
if (pList != NULL) {
Node* pNode = pList->head;
while (pList->head != NULL) {
pList->head = pNode->next;
free(pNode);
pNode = pList->head;
}
}
}
C 语言实现抽象数据类型(ADT)之链表的更多相关文章
- 抽象数据类型(ADT)
概念 抽象数据类型(ADT),脱离具体实现定义数据结构,它的定义着重于做什么,而忽略怎么做 举例 列表.栈.队列 列表 列表,也叫线性表 抽象定义:数据项线性排列,可以插入某一项,删除某一项,读取某一 ...
- C语言抽象数据类型ADT
根据编程的问题匹配合适的数据类型.数据项连接构成了链表,定义了一个结构代表单独的项.设计了一些方法把一系列结构构成一个链表.本质上,我们使用C语言的功能设计了一种符合程序要求的新的数据类型.但是上述的 ...
- 抽象数据类型ADT
ADT(Abstract Data Type) 类型由什么组成? 一个类型(type)指定两类信息,一个属性集和一个操作集. 假设要定义一个新的数据类型.首先,要提供存储数据的方式,可能是通过设计一个 ...
- C语言泛型编程--抽象数据类型
一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...
- 【ADT】链表的基本C语言实现
什么是抽象数据类型?首先,这一概念是软件开发人员在力求编写的代码健壮.易维护且可以复用的过程中产生的.英文是AbstractData Type.有人将其比作"抽象"的墙壁,&quo ...
- 抽象数据类型(ADT)
抽象数据类型(Abstract Data Type,ADT)是指一个数学模型以及定义在这个模型上的一组操作.抽象数据类型的定义仅仅取决于它的一组逻辑特性,而与它在计算机中的表示和实现无关. 例如,in ...
- ADT(abstract data types)抽象数据类型
1.What is it? An abstract data type is a set of objects together with a set of operations. 抽象数据类型是带有 ...
- 数据结构 集合_集合(数学)抽象数据类型的C语言实现
链表是实现集合的一种理想的方式.将List以typedef的方式重命名为Set.这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性. 使用这种方法的最大好处就是可以使用list_next来遍历 ...
- 集合抽象数据类型的C语言实现
链表是实现集合的一种理想的方式.将List以typedef的方式重命名为Set.这样做能保留链表简洁的特性,还能使集合具有了一些多态的特性. 使用这种方法的最大好处就是可以使用list_next来遍历 ...
- 采用C/C++语言如何实现复数抽象数据类型Complex
记录一下! 采用C/C++语言如何实现复数抽象数据类型Complex #include <stdio.h> typedef struct Complex { double e1; // 实 ...
随机推荐
- Flink程序异常--CommunicationsException: The last packet successfully received from the server was
一.异常截图 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully receive ...
- Typora+PicGo+Gitee图床
Typora+PicGo+Gitee图床 介绍 Typora:一个用于写文章的Markdown 编辑器,Typora 没有采用源代码和预览双栏显示的方式,而是采用所见即所得的编辑方式,实现了即时预览的 ...
- 快速集成和使用 solon-flow 规则与流引擎(用 yaml 编写业务规则)
本文参考自:https://www.cnblogs.com/studyjobs/p/18125096 规则引擎技术的主要思想是将应用程序中的业务规则分离出来,业务规则不再以程序代码的形式驻留在系统中, ...
- Qt QString的格式化与QString的拼接
1. QString 与 QString 直接用 + 号也可以 QString date = "昨晚"; QString msg = "你真棒": QStrin ...
- 小米手机/红米手机解锁BL详细教程
由于MIUI解锁风控提升,全部小米默认为支持解锁BootLoader的 但需要登录小米账号后,到开发者选项将设备和账号绑定0-1000小时,一般默认为168小时,部分新机实际几百小时,具体绑定时间,我 ...
- AI 实践|零成本生成SEO友好的TDK落地方案
之前写过一篇文章「Google搜索成最大入口,简单谈下个人博客的SEO」,文章里介绍了网页的描述信息TDK(Title.Description和Keywords)对SEO的重要作用,尽管已经意识到了T ...
- C#如何使用HttpClient对大文件进行断点上传和下载
什么是Http的断点上传和下载 断点上传:在向服务商上传大文件的时候,将一个大的文件拆分成多个小的文件,每个文件通过单独的Http请求上传给服务器. 断点下载:在向服务器请求下载一个大的资源文件的时候 ...
- PanWeiDB2.0异构数据库访问测试
PanWeiDB2.0异构数据库访问测试 异构数据库访问兼容性测试一览表 No 访问路径 多维度结果 备注 1 PanWeiDB(集中式)-访问-PanWeiDB(集中式) √ 支持复杂SQL 2 P ...
- leaflet生成地图封装成jquery插件使用
公司业务里一直都有使用leaflet地图插件来做地图展示.绘图等操作.公司有个项目已经有好几年了,由于项目原因一直在使用,今年由于google 地图 api过期,导致已经使用的地图无法加载.我作为现在 ...
- Vulnhub-venom
对于该靶机,注意利用了信息收集来的21端口和80端口,网站源码发现账户,ftp匿名登录密码猜测,维吉尼亚解密,后台管理员登录,CVE文件上传RCE漏洞利用反弹shell,提权有两中,利用版本内核提权和 ...