情境
需要频繁增加、删除、修改、查询、插入数据,且事先不知道数据的个数
分析
数组
在内存空间里是连续的一段空间
- 优:数组可以直接声明使用,能通过下标很方便地进行随机访问。
- 缺:删除其中一个数,后面的所有数都要依次往前挪;插入一个数,后面的所有数都要依次往后挪;声明一个数组必须事先指定数组长度。
链表
是通过将实际间断的内存空间通过地址串起来,形成逻辑上的连续空间。- 所以,像这种处理需要频繁插入和删除的情况时,
链表
会显得很优美。
链表
定义一种抽象数据类型(Abstract Data Type -
ADT
):简单链表。数据的存储结构是链表,属性是存储一系列项,数据的操作有增加、删除、修改、查询、插入、清空。
(定义抽象数据类型包括明确属性、确定数据的存储结构、确定有哪些操作,这是和实现无关的,可以用不同的语言实现。此篇用C语言实现)用C语言建立接口:
(接口?对,接口。Java里面接口就是用来规定一类东西具有哪些操作的,里面都是抽象方法,没有实体。C语言里面,延伸类比可以知道,接口是通过头文件建立的,只有声明,没有定义的实体)
链表由一个个节点
Node
连接而成,节点里面分为地址区
和数据区
,地址包括 上一个节点的地址 和 下一个节点的地址 ,数据区是要存储的数据。用C语言实现接口
在源代码中写出接口中每一个函数的实体,即实现接口。
建立接口
建立节点(Node)
这里就会有两种情况了:
一种是直接将数据放在节点 Node
里面:
typedef struct _node
{
struct _node *plast;
/*数据区*/
int value; //此处可以加入其他各种属性
struct _node *pnext;
} Node;
另一种是将数据单独封装成 Item
, Node
里面就只放一项 Item
,而不是放一项项具体的数据:
typedef struct _item
{
int value;
} Item;
typedef struct _node
{
struct _node *plast;
struct _item *item; //只有一项Item,数据都在里面
struct _node *pnext;
} Node;
第二种会好些,数据项变化就只需要改动 Item
就行了,不需要动 Node
(但这里用的还是第一种方法)
建立链表(List)
List存储着链表的头和尾以及链表长度
typedef struct _list
{
struct _node *phead;
struct _node *ptail;
int total;
} List;
声明链表具有的操作
(接口的函数名开头都用大写字母)
/*初始化链表*/
void InitializeList(List *list);
/*增加一个节点,值为value*/
void AddNode(List *list, int value);
/*在指定序号后面插入一段链表*/
void InsertNode(List *list, int index);
/*把节点值为value的节点全部删除*/
int RmNodeValued(List *list, int value);
/*把指定序号之间的所有数据删除*/
int RmNodeIndex(List *list, int lowerNumber, int upperNumber);
/*找出所有值为value的节点*/
int SearchNodeValued(const List *list, int value, Node** pnodes);
/*找出指定索引区间的所有节点,地址存在指针数组中*/
int SearchNodeIndex(const List *list, int lowerNumber, int upperNumber, Node **pnodes);
/*清空链表*/
void FreeAllNodes(const List *list);
完整接口代码(“linkedList.h”)
#ifndef _LINKED_LIST_H_
#define _LINKED_LIST_H_
typedef struct _node
{
struct _node *plast;
int value; //可以加入其他各种属性
struct _node *pnext;
} Node;
typedef struct _list
{
struct _node *phead;
struct _node *ptail;
int total;
} List;
//链表(Node-Link)
void InitializeList(List *list);
void AddNode(List *list, int value);
void InsertNode(List *list, int index);
int RmNodeValued(List *list, int value);
int RmNodeIndex(List *list, int lowerNumber, int upperNumber);
int SearchNodeValued(const List *list, int value, Node** pnodes);
int SearchNodeIndex(const List *list, int lowerNumber, int upperNumber, Node **pnodes);
void FreeAllNodes(const List *list);
#endif