数据结构01 —— 线性表(C)
一、线性表
线性表的分类:

线性表的抽象数据类型(ADT)定义如下:
ADT 线性表(List)
Data
数据对象为{a1, a2, ... , an}的集合,每个元素的类型相同。
Operation
InitList(*L)
操作结果:构造一个空的线性表 L。
DestroyList(*L)
初始条件:线性表 L 已经存在。
操作结果:销毁线性表 L。
ClearList(*L)
初始条件:线性表 L 已经存在。
操作结果:将 L 重置为空表。
ListEmpty(L)
初始条件:线性表 L 已经存在。
操作结果:若 L 为空,则返回 true,否则返回 false。
ListLength(L)
初始条件:线性表 L 已经存在。
操作结果:返回 L 中数据元素的个数。
GetElem(L, i, *e)
初始条件:线性表 L 已经存在,且 1 ≤ i ≤ ListLength(L)。
操作结果:返回 L 中第 i 个数据元素。
LocateElem(L, e)
初始条件:线性表 L 已经存在。
操作结果:返回 L 中第一个出现数据元素 e 的位置,若数据元素 e 不存在,则返回 0。
PriorElem(L, cur_e, *pre_e)
初始条件:线性表 L 已经存在。
操作结果:若 cur_e 不是 L 的第一个元素,则返回 true 和 cur_e 的前驱(赋值给 pre_e),否则返回 false,这时 pre_e 为空。
NextElem(L, cur_e, *next_e)
初始条件:线性表 L 已经存在。
操作结果:若 cur_e 不是 L 的最后一个元素,则返回 true 和 cur_e 的后继(赋值给 next_e),否则返回 false,这时 pre_e 为空。
ListInsert(*L, i, e)
初始条件:线性表 L 已经存在,且 1 ≤ i ≤ ListLength(L)+1。
操作结果:在 L 中第 i 个位置之前插入新的数据元素 e,L 的长度加 1。
ListDelete(*L, i, *e)
初始条件:线性表 L 已经存在,且 1 ≤ i ≤ ListLength(L)。
操作结果:删除 L 中第 i 个位置的数据元素,并用 e 返回其值,L 的长度减 1。
endADT
二、线性表的顺序存储结构
线性表的顺序存储结构在C语言中可以使用数组来实现,代码如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20 // 存储空间的初始分配量,根据实际情况而定
/* Data1:线性表的元素类型定义 */
typedef int ElemType; // 元素的类型,根据实际情况而定,这里假设为int
/* Data2:线性表定义 */
typedef struct
{
ElemType data[MAXSIZE]; // 使用数组存储数据元素,其长度为MAXSIZE
unsigned int length; // 存储线性表当前数据的的个数
}SqList;
/* Operation1:创建空表 */
// 在 C 语言中,因为使用了 typedef 定义线性表,所以可以直接使用 SqList 关键字创建线性表表
void InitList(SqList **list_p_p)
{
// 给线性表分配地址
*list_p_p = (SqList *)calloc(1, sizeof(SqList)); // calloc 会将每个字节初始化为 0,而 malloc 不会
}
/* Operation2:销毁线性表 */
// 不能销毁用 SqList 关键字创建的线性表
void DestroyList(SqList **list_p_p)
{
free(*list_p_p); // 由于 C 语言的特性,销毁了依然可以访问,很危险
}
/* Operation3:清空线性表 */
void ClearList(SqList *const list_p)
{
// 将数组 data 中已使用的空间循环赋值为 0,若没有必要,可以直接改变 length
for (int i = 0; (i < list_p->length)||(i < MAXSIZE); i++)
{
list_p->data[i] = 0;
}
// 数据个数 length 设为 0
list_p->length = 0;
}
/* Operation4:判断性表是否为空 */
int ListEmpty(const SqList *const list_p)
{
return (list_p->length == 0);
}
/* Operation5:返回线性表长度 */
int ListLength(const SqList *const list_p)
{
return list_p->length;
}
/* Operation6:返回线性表中第 i 个元素 */
int GetElem(const SqList *const list_p, const int i, ElemType *const elem)
{
// 检查 i 是否超出范围
if((i < 1)||(i > list_p->length)||(i > MAXSIZE))
{
return 0; // i超过了范围,查找失败
}
else
{
*elem = list_p->data[i-1];
return 1;
}
}
/* Operation7:返回线性表中第 start 后(不包括 start)第一个出现 elem 的位置,范围:start+1 ~ length */
int LocateElem(const SqList *const list_p, const int start, const ElemType elem)
{
// 循环查找
for (int i = start; (i < list_p->length)||(i < MAXSIZE); i++)
{
if (list_p->data[i] == elem)
{
return i+1;
}
}
return 0; // 不存在返回 0
}
/* Operation8:返回 cur_elem 的前驱 */
int PriorElem(const SqList *const list_p, const ElemType cur_elem, ElemType *const pre_elem)
{
// 先获取 cur_elem 的位置
int cur_elem_locate = LocateElem(list_p, 0, cur_elem);
// 判断位置信息
if ((cur_elem_locate <= 1)||(cur_elem_locate > list_p->length)||(cur_elem_locate > MAXSIZE))
{
return 0; // cur_elem 的位置信息错误,或者 cur_elem 为第一个元素
}
else
{
GetElem(list_p, cur_elem_locate - 1, pre_elem);
return 1;
}
}
/* Operation9:返回 cur_elem 的后继 */
int NextElem(const SqList *const list_p, const ElemType cur_elem, ElemType *const next_elem)
{
// 先获取 cur_elem 的位置
int cur_elem_locate = LocateElem(list_p, 0, cur_elem);
// 判断位置信息
if ((cur_elem_locate < 1)||(cur_elem_locate >= list_p->length)||(cur_elem_locate > MAXSIZE))
{
return 0; // cur_elem 的位置信息错误,或者 cur_elem 为最后一个元素
}
else
{
GetElem(list_p, cur_elem_locate + 1, next_elem);
return 1;
}
}
/* Operation10:在线性表的第 i 个位置之前插入元素 elem */
int ListInsert(SqList *const list_p, int i, const ElemType elem)
{
// 检查线性表是否已满
if (list_p->length >= MAXSIZE)
{
return 0; // 线性表已满,无法插入
}
// 检查 i 是否超出范围
if((i < 1)||(i > list_p->length+1)||(i > MAXSIZE))
{
return 0; // i 信息有误,无法插入
}
// 第 i 个位置的数据以及后面的数据向后移一位
for (int k = list_p->length; k >= i; k--)
{
list_p->data[k] = list_p->data[k-1];
}
// 插入数据
list_p->data[i-1] = elem; // 重新给第 i 个位置赋值
list_p->length++; // 长度加一
return 1;
}
/* Operation11:删除线性表中第 i 个元素,并返回给 elem */
int ListDelete(SqList *const list_p, int i, ElemType *const elem)
{
// 检查 i 是否超出范围
if((i < 1)||(i > list_p->length)||(i > MAXSIZE))
{
return 0; // i 信息有误,或者线性表为空表,无法删除
}
// 将第 i 个元素赋值给 elem
*elem = list_p->data[i-1];
// 将第 i 个位置后的元素向前移一位
for (int k = i-1; k < list_p->length; k++)
{
list_p->data[k] = list_p->data[k+1];
}
// 长度减一
list_p->length--;
return 1;
}
/* 主函数:测试及示例 */
int main(void)
{
SqList my_list; // 直接使用关键字生成空表,注意内部未初始化,数值不确定,需初始化为 0
SqList *my_list_p = &my_list; // 定义线性表指针,可以指向 my_list 空表
ElemType my_elem = 666;
// Test:创建空表
InitList(&my_list_p); // 通过 InitList() 函数分配内存,内部所有字节已初始化为 0
// Test:插入元素
printf("\n-------- Test:插入元素 --------\n");
printf("Insert debug code: %d\n", ListInsert(my_list_p, 0, my_elem)); // 查看 i 超范围
printf("Insert debug code: %d\n", ListInsert(my_list_p, MAXSIZE, my_elem)); // 查看 i 超范围
printf("Insert debug code: %d\n", ListInsert(my_list_p, 1, my_elem)); // 查看 i 正常
printf("-------- End --------\n");
// Test: 删除元素
printf("\n-------- Test:删除元素 --------\n");
printf("Delete debug code: %d\n", ListDelete(my_list_p, 0, &my_elem)); // 查看 i 超范围
printf("Delete debug code: %d\n", ListDelete(my_list_p, MAXSIZE, &my_elem)); // 查看 i 超范围
printf("Delete debug code: %d\n", ListDelete(my_list_p, 1, &my_elem)); // 查看 i 正常
printf("-------- End --------\n");
// Test:获取线性表长度
printf("\n-------- Test:获取线性表长度 --------\n");
for (int i = 1; i <= MAXSIZE+5; i++)
{
// 循环添加元素
ListInsert(my_list_p, i, (ElemType)(i+10));
printf("Length debug code: %d\n", ListLength(my_list_p));
}
printf("-------- End --------\n");
// Test:获取第 i 个元素
printf("\n-------- Test:获取第 i 个元素 --------\n");
my_elem = (ElemType) 666;
printf("Get debug code: %d\n", GetElem(my_list_p, 0, &my_elem)); // 查看 i 超范围
printf("my_elem = %d\n", my_elem);
printf("Get debug code: %d\n", GetElem(my_list_p, MAXSIZE+5, &my_elem)); // 查看 i 超范围
printf("my_elem = %d\n", my_elem);
printf("Get debug code: %d\n", GetElem(my_list_p, 5, &my_elem)); // 查看 i 正常
printf("my_elem = %d\n", my_elem);
printf("-------- End --------\n");
// Test:获取在第 start 位置之后,线性表中出现 my_elem 的位置
printf("\n-------- Test:获取在第 start 位置之后,线性表中出现 my_elem 的位置 --------\n");
int start = 4;
my_elem = (ElemType)15;
printf("Locate debug code: %d\n", LocateElem(my_list_p, start, my_elem)); // 存在 my_elem
my_elem = (ElemType)666;
printf("Locate debug code: %d\n", LocateElem(my_list_p, start, my_elem)); // 不存在 my_elem
printf("-------- End --------\n");
// Test:获取 cur_elem 的前驱 pre_elem 和后继 next_elem
printf("\n-------- Test:获取 cur_elem 的前驱 pre_elem 和后继 next_elem --------\n");
ElemType cur_elem = (ElemType)15;
ElemType pre_elem = (ElemType)0;
ElemType next_elem = (ElemType)0;
printf("Prior debug code: %d\n", PriorElem(my_list_p, cur_elem, &pre_elem));
printf("Pre_elem = %d\n", pre_elem);
printf("Next debug code: %d\n", NextElem(my_list_p, cur_elem, &next_elem));
printf("Pre_elem = %d\n", next_elem);
printf("-------- End --------\n");
// Test:测试判断是否为空、清空线性表
printf("\n-------- Test:判断是否为空、清空线性表 --------\n");
printf("Empty debug code: %d\n", ListEmpty(my_list_p));
ClearList(my_list_p);
printf("Empty debug code: %d\n", ListEmpty(my_list_p));
printf("-------- End --------\n");
return 0;
}
参考内容:
《大话数据结构》P42
《数据结构(C语言版)》P18

浙公网安备 33010602011771号