第 2 章 线性表 (线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现)

1. 背景说明

静态单链表实现类似于单链表,只是指针域变成了数组下标。

第 2 章 线性表 (线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现)_第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. 输出示例

第 2 章 线性表 (线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现)_第2张图片

你可能感兴趣的:(#,数据结构(C语言版),链表,数据结构,算法,c语言)