1. 背景说明
静态单链表实现类似于单链表,只是指针域变成了数组下标。
A = { c, b, e, g, f, d }
B = { a, b, n, f }
2. 示例代码
1) status.h
/* DataStructure 预定义常量和类型头文件 */
#ifndef STATUS_H
#define STATUS_H
#define CHECK_RET(ret) if (ret != RET_OK) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \
return ret; \
}
#define CHECK_VALUE(value, ERR_CODE) if (value) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
return ERR_CODE; \
}
#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
return FALSE; \
}
/* 函数结果状态码 */
#define TRUE 1 /* 返回值为真 */
#define FALSE 0 /* 返回值为假 */
#define RET_OK 0 /* 返回值正确 */
#define INFEASIABLE 2 /* 返回值未知 */
#define ERR_MEMORY 3 /* 访问内存错 */
#define ERR_NULL_PTR 4 /* 空指针错误 */
#define ERR_MEMORY_ALLOCATE 5 /* 内存分配错 */
#define ERR_NULL_STACK 6 /* 栈元素为空 */
#define ERR_PARA 7 /* 函数参数错 */
#define ERR_OPEN_FILE 8 /* 打开文件错 */
#define ERR_NULL_QUEUE 9 /* 队列为空错 */
#define ERR_FULL_QUEUE 10 /* 队列为满错 */
#define ERR_NOT_FOUND 11 /* 表项不存在 */
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean; /* Boolean 是布尔类型,其值是 TRUE 或 FALSE */
#endif // !STATUS_H
2) staticLinkListMulti.h
/* 线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现头文件 */
#ifndef STATICLINKLISTMULTI_H
#define STATICLINKLISTMULTI_H
#include "status.h"
#define MAX_SIZE 100
typedef int ElemType;
typedef struct {
ElemType data;
int curr;
} SLinkList[MAX_SIZE];
/* 算法 2.15, 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点),否则返回 0 */
int Malloc(SLinkList space);
/* 算法 2.16, 将下标为 i 的空闲结点回收到备用链表(成为备用链表的第一个结点) */
void Free(SLinkList L, int i);
/* 静态数组无法被销毁 */
void DestroyList(void);
/* 算法 2.14, 将一维数组 L 中各分量链成一个备用链表,L[0].curr 为头指针。'0' 表示空指针 */
void InitSpace(SLinkList L);
/* 构造一个空链表,返回值为空表在数组中的位序 */
int InitList(SLinkList L);
/* 初始条件:L 中表头位序为 n 的静态链表已存在。
操作结果:将此表重置为空表 */
Status ClearList(SLinkList L, int n);
/* 判断 L 中表头位序为 n 的链表是否空,若是空表返回 TRUE; 否则返回 FALSE */
Bollean ListEmpty(SLinkList L, int n);
/* 返回 L 中表头位序为 n 的链表的数据元素个数 */
int ListLength(SLinkList L, int n);
/* 用 e 返回 L 中表头位序为 n 的链表的第 i 个元素的值 */
Status GetElem(SLinkList L, int n, int i, ElemType *e);
/* 算法 2.13, 在 L 中表头位序为 n 的静态单链表中查找第 1 个值为 e 的元素
若找到,则返回它在 L 中的位序,否则返回 0 */
int LocateElem(SLinkList L, int n, ElemType e);
/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
操作结果:若 curr_e 是此单链表的数据元素,且不是第一个
则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义 */
Status PriorElem(SLinkList L, int n, ElemType curr_e, ElemType *pre_e);
/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
操作结果:若 curr_e 是此单链表的数据元素,且不是最后一个
则用 next_e 返回它的后继,否则操作失败,next_e 无定义 */
Status NextElem(SLinkList L, int n, ElemType curr_e, ElemType *next_e);
/* 在 L 中表头位序为 n 的链表的第 i 个元素之前插入新的数据元素 e */
Status ListInsert(SLinkList L, int n, int i, ElemType e);
/* 删除在 L 中表头位序为 n 的链表的第 i 个数据元素 e,并返回其值 */
Status ListDelete(SLinkList L, int n, int i, ElemType *e);
/* 依次对 L 中表头位序为 n 的链表的每个数据元素,调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(SLinkList L, int n, void(*vi)(ElemType));
#endif // !STATICLINKLISTMULTI_H
3) staticLinkListMulti.c
/* 线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现源文件 */
#include "staticLinkListMulti.h"
#include
/* 算法 2.15, 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点),否则返回 0 */
int Malloc(SLinkList space)
{
int i = space[0].curr;
if (i) {
space[0].curr = space[i].curr;
}
return i;
}
/* 算法 2.16, 将下标为 i 的空闲结点回收到备用链表(成为备用链表的第一个结点) */
void Free(SLinkList space, int i)
{
space[i].curr = space[0].curr;
space[0].curr = i;
}
/* 静态数组无法被销毁 */
void DestroyList(void)
{
printf("Can not destroy the static link list\n");
}
/* 算法 2.14, 将一维数组 L 中各分量链成一个备用链表,L[0].curr 为头指针。'0' 表示空指针 */
void InitSpace(SLinkList L)
{
for (int i = 0; i < MAX_SIZE - 1; ++i) {
L[i].curr = i + 1;
}
L[MAX_SIZE - 1].curr = 0;
}
/* 构造一个空链表,返回值为空表在数组中的位序 */
int InitList(SLinkList L)
{
int i = Malloc(L);
L[i].curr = 0;
return i;
}
/* 初始条件:L 中表头位序为 n 的静态链表已存在。
操作结果:将此表重置为空表 */
Status ClearList(SLinkList L, int n)
{
int i = L[n].curr;
L[n].curr = 0;
int head = L[0].curr;
L[0].curr = i;
int j;
while (i) {
j = i;
i = L[i].curr;
}
L[j].curr = head;
return RET_OK;
}
/* 判断 L 中表头位序为 n 的链表是否空,若是空表返回 TRUE; 否则返回 FALSE */
Bollean ListEmpty(SLinkList L, int n)
{
return (L[n].curr == 0) ? TRUE : FALSE;
}
/* 返回 L 中表头位序为 n 的链表的数据元素个数 */
int ListLength(SLinkList L, int n)
{
int i = L[n].curr;
int length = 0;
while (i) {
++length;
i = L[i].curr;
}
return length;
}
/* 用 e 返回 L 中表头位序为 n 的链表的第 i 个元素的值 */
Status GetElem(SLinkList L, int n, int i, ElemType *e)
{
CHECK_VALUE((i < 1) || (i > ListLength(L, n)), ERR_PARA);
int head = n;
for (int j = 0; j < i; ++j) {
head = L[head].curr;
}
*e = L[head].data;
return RET_OK;
}
/* 算法 2.13, 在 L 中表头位序为 n 的静态单链表中查找第 1 个值为 e 的元素
若找到,则返回它在 L 中的位序,否则返回 0 */
int LocateElem(SLinkList L, int n, ElemType e)
{
int i = L[n].curr;
while ((i) && (L[i].data != e)) {
i = L[i].curr;
}
return i;
}
/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
操作结果:若 curr_e 是此单链表的数据元素,且不是第一个
则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义 */
Status PriorElem(SLinkList L, int n, ElemType curr_e, ElemType *pre_e)
{
int i = L[n].curr;
int pre;
do {
pre = i;
i = L[i].curr;
} while ((i) && (curr_e != L[i].data));
CHECK_VALUE(i, ERR_NOT_FOUND);
*pre_e = L[pre].data;
return RET_OK;
}
/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
操作结果:若 curr_e 是此单链表的数据元素,且不是最后一个
则用 next_e 返回它的后继,否则操作失败,next_e 无定义 */
Status NextElem(SLinkList L, int n, ElemType curr_e, ElemType *next_e)
{
int i = LocateElem(L, n, curr_e);
if (i) {
i = L[i].curr;
if (i) {
*next_e = L[i].data;
return RET_OK;
}
}
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NOT_FOUND);
return ERR_NOT_FOUND;
}
/* 在 L 中表头位序为 n 的链表的第 i 个元素之前插入新的数据元素 e */
Status ListInsert(SLinkList L, int n, int i, ElemType e)
{
CHECK_VALUE((i < 1) || (i > ListLength(L, n) + 1), ERR_PARA);
int newNode = Malloc(L);
CHECK_VALUE(!newNode, ERR_MEMORY_ALLOCATE);
L[newNode].data = e;
int head = n;
for (int j = 0; j < i - 1; ++j) {
head = L[head].curr;
}
L[newNode].curr = L[head].curr;
L[head].curr = newNode;
return RET_OK;
}
/* 删除在 L 中表头位序为 n 的链表的第 i 个数据元素 e,并返回其值 */
Status ListDelete(SLinkList L, int n, int i, ElemType *e)
{
CHECK_VALUE((i < 1) || (i > ListLength(L, n)), ERR_PARA);
int head = n;
for (int j = 0; j < i - 1; ++j) {
head = L[head].curr;
}
i = L[head].curr;
L[head].curr = L[i].curr;
*e = L[i].data;
Free(L, i);
return RET_OK;
}
/* 依次对 L 中表头位序为 n 的链表的每个数据元素,调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(SLinkList L, int n, void(*vi)(ElemType))
{
int i = L[n].curr;
while (i) {
vi(L[i].data);
i = L[i].curr;
}
return RET_OK;
}
4) algorithm.h
/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H
#include "staticLinkListMulti.h"
/* 算法 2.17, 依次输入集合 A 和 B 的元素,在一维数组 space 中建立表示集合 (A - B) ∪ (B - A)
的静态链表,S 为其头指针。假设备用空间足够大,space[0].cur 为备用空间的头指针 */
Status Difference(SLinkList space, int *S);
#endif // !ALGORITHM_H
5) algorithm.c
/* 算法实现源文件 */
#include "algorithm.h"
#include
/* 算法2.17, 依次输入集合 A 和 B 的元素,在一维数组 space 中建立表示集合 (A - B) ∪ (B - A)
的静态链表,S 为其头指针。假设备用空间足够大,space[0].cur 为备用空间的头指针 */
Status Difference(SLinkList space, int *S)
{
InitSpace(space);
*S = Malloc(space);
int tail = *S;
int numA, numB;
printf("Please input the element num of A and B: ");
scanf_s("%d%d", &numA, &numB);
getchar();
printf("Please input the element of A for totally %d elements: ", numA);
for (int i = 0; i < numA; ++i) {
int pos = Malloc(space);
CHECK_VALUE(!pos, ERR_MEMORY_ALLOCATE);
char ch;
scanf_s("%c", &ch, 1);
space[pos].data = ch;
space[tail].curr = pos;
tail = pos;
}
getchar();
space[tail].curr = 0;
printf("Please input the element of B for totally %d elements: ", numB);
for (int i = 0; i < numB; ++i) {
char e;
scanf_s("%c", &e, 1);
int p = *S;
int head = space[*S].curr;
while ((head != space[tail].curr) && (space[head].data != e)) {
p = head;
head = space[head].curr;
}
if (head == space[tail].curr) {
int pos = Malloc(space);
CHECK_VALUE(!pos, ERR_MEMORY_ALLOCATE)
space[pos].data = e;
space[pos].curr = space[tail].curr;
space[tail].curr = pos;
} else {
space[p].curr = space[head].curr;
Free(space, head);
if (tail == head) {
tail = p;
}
}
}
return RET_OK;
}
6) mian.c
/* 入口查询源文件 */
#include "staticLinkListMulti.h"
#include "algorithm.h"
#include
void Visit(ElemType e);
void Visit1(ElemType e);
int main(void)
{
SLinkList L;
InitSpace(L);
int La = InitList(L);
int Lb = InitList(L);
printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
ListLength(L, La));
for (int i = 0; i < 5; ++i) {
ListInsert(L, La, 1, i + 1);
}
printf("After insert 1 ~ 5 in the head of La, La is : ");
ListTraverse(L, La, Visit);
printf("\n");
for (int i = 0; i < 5; ++i) {
ListInsert(L, Lb, i + 1, i + 1);
}
printf("After insert 1 ~ 5 in the end of Lb, Lb is: ");
ListTraverse(L, Lb, Visit);
printf("\n");
printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
ListLength(L, La));
ClearList(L, La);
printf("After clear La, La is: ");
ListTraverse(L, La, Visit);
printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
ListLength(L, La));
for (int i = 2; i < 8; i += 5) {
ElemType e;
int ret = GetElem(L, Lb, i, &e);
if (ret == RET_OK) {
printf("The %dth element of Lb is %d\n", i, e);
} else {
printf("The %dth element of Lb is not exist\n", i);
}
}
for (int i = 0; i < 2; ++i) {
int ret = LocateElem(L, Lb, i);
if (ret) {
printf("The order of element of %d of Lb in static link list is %d\n", i, ret);
} else {
printf("The element of %d is not exist in Lb\n", i);
}
}
for (int i = 1; i <= 2; ++i) {
ElemType e;
GetElem(L, Lb, i, &e);
ElemType pre;
int ret = PriorElem(L, Lb, e, &pre);
if (ret != RET_OK) {
printf("There is no previous element of element %d\n", e);
} else {
printf("The previous element of element %d is %d\n", e, pre);
}
}
for (int i = ListLength(L, Lb) - 1; i <= ListLength(L, Lb); ++i) {
ElemType e;
GetElem(L, Lb, i, &e);
ElemType next;
int ret = NextElem(L, Lb, e, &next);
if (ret != RET_OK) {
printf("There is no next element of element %d in Lb\n", e);
} else {
printf("The next element of %d in Lb is %d\n", e, next);
}
}
int length = ListLength(L, Lb);
for (int i = length + 1; i >= length; --i) {
ElemType e;
int ret = ListDelete(L, Lb, i, &e);
if (ret == RET_OK) {
printf("The %dth element of Lb is %d, has been deleted\n", i, e);
} else {
printf("%dth elemetn of Lb is not exist\n", i);
}
}
printf("Now Lb is: ");
ListTraverse(L, Lb, Visit);
putchar('\n');
/* Algorithm 2.17 Test */
typedef char ElemType;
SLinkList S;
int pos;
Difference(S, &pos);
printf("S is: ");
ListTraverse(S, pos, Visit1);
putchar('\n');
return 0;
}
void Visit(ElemType e)
{
printf("%d ", e);
}
void Visit1(ElemType e)
{
printf("%c ", e);
}
3. 输出示例