线性表
重新系统学习数据结构知识,使用博客记录之。
【系列博客】数据结构和算法 C语言实现
本文概览
- C语言实现顺序式线性表和链式线性表
- 可储存任意类型数据结构
- 支持插入、删除、读取、查找、遍历等接口。
1. 什么是线性表
线性表是由n个有限数据元素组成的有限序列。
特点:
- 同一线性表中的元素具有相同特性
- 相邻数据元素之间存在序偶关系。
- 除第一个元素都有一个前驱元素
- 除最后一个元素都有一个后继元素
结构:
线性表的存储结构可分为顺序式和链式两种,下面名称中出现的线性表均指顺序式的线性表,链式线性表直接称为链表。
链式结构中按不同的方式又可分为:单向链表、双向链表和循环链表三种。如果想的话,还可以使用数组实现静态链表。
2. 线性表接口定义
线性表数据包括信息节点和数据节点两部分。信息节点用于储存表的有关信息,比如线性表的长度,数据起始地址等。
下面分别是线性表和链表的信息节点声明。
/*连续式线性表数据结构,对外不可见*/
struct _list_t
{
void * base; /*数据基地址*/
uint16_t length; /*已使用数据长度*/
uint16_t cacapacity; /*列表容量*/
uint16_t size; /*元素大小*/
};
/*链表式线性表数据结构,对外不可见*/
struct _list_t
{
node_t * next; /*数据基地址*/
uint16_t length; /*已使用数据长度*/
uint16_t size; /*元素大小*/
};
在信息节点中储存着,线性表的长度、元素类型大小和数据存储基地址。
线性表的节点信息在源文件中定义,对上层代码不可见,使用时只能通过指针传参的方式调用相关接口。
线性表具有的接口函数在list.h
中声明,支持的接口如下:
// 创建线性表
int list_creat(list_t ** list ,uint16_t size,uint16_t length);
// 向线性表指定位置插入数据
int list_insert(list_t *list, uint16_t loca, uint16_t num, void *data);
// 向线性表指定位置读取数据并删除数据
int list_delete(list_t *list, uint16_t loca, uint16_t num, void *data);
// 读取线性表指定位置数据
int list_read(list_t *list, uint16_t loca, uint16_t num,void *data);
// 查找线性表指定数据第一次出现的位置
int list_find(list_t *list, void * data);
// 向线性表尾部追加数据
int list_append(list_t *list, uint16_t num, void *data);
// 遍历线性表所有数据
int list_traverse(list_t *list, int (*visit)(uint16_t index,void *data));
// 获取线性表长度
int list_length(list_t *list);
// 清空线性表
int list_clear(list_t *list);
// 删除线性表
int list_destroy(list_t *list);
3. 线性表的顺序实现
顺序式线性表式使用连续的空间进行数据储存,在线性表创建的时候分配指定大小的空间用于储存数据,结构类似数组。
int list_creat(list_t ** list ,uint16_t size ,uint16_t length)
{
/*创建信息节点*/
*list=malloc(sizeof(list_t));
/*分配数据节点空间*/
(*list)->base=malloc(size*length);
......
/*详细代码见附录*/
}
由于顺序式线性表的空间是连续的,类似数组可以使用“下标”进行数据读取。 其思想是由线性表的数据基地址和需要读取数据的偏移大小可计算出待读取数据的起始,其对应元素空间大小的数据就是待读取的数据。
int list_read(list_t *list, uint16_t loca, uint16_t num, void *data)
{
void * src_addr = list->base + (list->size*(loca+num-1) );
memcpy(data,src_addr, num * list->size);
return 1;
}
未完待续。。。