1. 背景说明
2. 示例代码
1) status.h
/* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H
#define STATUS_H#define CHECK_NULL(pointer) if (!(pointer)) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \return NULL; \
}#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) singleLinkList.h
/* 线性表的单链表存储结构头文件 */#ifndef SINGLELINKLIST_H
#define SINGLELINKLIST_H#include "status.h"typedef int ElemType;typedef struct LNode {ElemType data;struct LNode *next;
} *LinkList;/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e);/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L);/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L);/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L);/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L);/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L);/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e);/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Bollean(*compare)(ElemType, ElemType));/* 初始条件: 线性表 L 已存在操作结果: 若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱函数返回 OK;否则操作失败, pre_e 无定义, 返回 INFEASIBLE */
Status PriorElem(LinkList L, ElemType cur_e, ElemType *pre_e);/* 初始条件:线性表 L 已存在操作结果:若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继函数返回 OK;否则操作失败,next_e无定义,返回 INFEASIBLE */
Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e);/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e);/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e);/* 初始条件:线性表 L 已存在操作结果:依次对 L 的每个数据元素调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*vi)(ElemType));/* 初始条件:按非降序排列的线性表 L 已存在操作结果:在 L 中按非降序插入新的数据元素 e */
Status InsertAscend(LinkList L, ElemType e);/* 初始条件:按非升序排列的线性表 L 已存在操作结果:在 L 中按非升序插入新的数据元素 e */
Status InsertDescend(LinkList L, ElemType e);/* 初始条件:线性表 L 已存在操作结果:在 L 的头部插入新的数据元素 e, 作为链表的第一个元素 */
Status HeadInsert(LinkList L, ElemType e);/* 初始条件:线性表 L 已存在操作结果:在 L 的尾部插入新的数据元素 e, 作为链表的最后一个元素 */
Status EndInsert(LinkList L, ElemType e);/* 初始条件:线性表 L 已存在,且有不少于 1 个元素操作结果:删除 L 的第一个数据元素,并由 e 返回其值 */
Status DeleteFirst(LinkList L, ElemType *e);/* 初始条件:线性表 L 已存在,且有不少于 1 个元素操作结果:删除 L 的最后一个数据元素,并用 e 返回其值 */
Status DeleteTail(LinkList L, ElemType *e);/* 删除表中值为 e 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteElem(LinkList L, ElemType e);/* 用 e 取代表 L 中第 i 个元素的值 */
Status RePlaceElem(LinkList L, int i, ElemType e);/* 按非降序建立 n 个元素的线性表 */
Status CreateAscend(LinkList *L, int n);/* 按非升序建立 n 个元素的线性表 */
Status CreateDescend(LinkList *L, int n);/* 返回表头元素的值 */
Status GetFirstElem(LinkList L, ElemType *e);#endif
3) singleLinkList.c
/* 线性表的单链表存储结构源文件实现 */#include "singleLinkList.h"
#include <stdlib.h>
#include <stdio.h>/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e)
{LinkList newLNode = (LinkList)malloc(sizeof(struct LNode));CHECK_NULL(newLNode)newLNode->data = e;newLNode->next = NULL;return newLNode;
}/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L)
{*L = (LinkList)malloc(sizeof(struct LNode));CHECK_VALUE(!(*L), ERR_MEMORY_ALLOCATE)(*L)->next = NULL;return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L)
{LinkList q;while (*L) {q = (*L)->next;free(*L);*L = q;}return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L)
{LinkList p, q;p = L->next;while (p) {q = p->next;free(p);p = q;}L->next = NULL;return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L)
{return (L->next == NULL) ? TRUE : FALSE;
}/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L)
{int count = 0;LinkList p = L->next;while (p) {++count;p = p->next;}return count;
}/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 RET_OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e)
{int j = 1;LinkList p = L->next;while (p && j < i) {p = p->next;++j;}CHECK_VALUE((!p || j > i), ERR_PARA) /* j > i 适用于 i < 1 时,如 i = 0 */*e = p->data;return RET_OK;
}/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Bollean(*compare)(ElemType, ElemType))
{int i = 0;LinkList p = L->next;while (p) {++i;if (compare(p->data, e)) {return i;}p = p->next;}return 0;
}/* 初始条件: 线性表 L 已存在操作结果: 若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱函数返回 RET_OK;否则操作失败, pre_e 无定义, 返回 INFEASIBLE */
Status PriorElem(LinkList L, ElemType cur_e, ElemType *pre_e)
{LinkList q, p = L->next;while (p->next) {q = p->next;if (q->data == cur_e) {*pre_e = p->data;return RET_OK;}p = q;}return INFEASIABLE;
}/* 初始条件:线性表 L 已存在操作结果:若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继函数返回 RET_OK;否则操作失败,next_e无定义,返回 INFEASIBLE */
Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e)
{LinkList p = L->next;while (p->next) {if (p->data == cur_e) {*next_e = p->next->data;return RET_OK;}p = p->next;}return INFEASIABLE;
}/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e)
{int j = 0;LinkList p = L;while (p && j < i - 1) {++j;p = p->next;}CHECK_VALUE((!p || j > i - 1), ERR_PARA)LinkList newLNode = MakeNewLNode(e);CHECK_VALUE(!newLNode, ERR_MEMORY_ALLOCATE)newLNode->next = p->next;p->next = newLNode;return RET_OK;
}/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e)
{int j = 0;LinkList p = L;while (p->next && j < i - 1) {++j;p = p->next;}CHECK_VALUE((!p || j > i - 1), ERR_PARA)LinkList q = p->next;p->next = q->next;*e = q->data;free(q);return RET_OK;
}/* 初始条件:线性表 L 已存在操作结果:依次对 L 的每个数据元素调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*vi)(ElemType))
{LinkList p = L->next;while (p) {vi(p->data);p = p->next;}return RET_OK;
}/* 初始条件:按非降序排列的线性表 L 已存在操作结果:在 L 中按非降序插入新的数据元素 e */
Status InsertAscend(LinkList L, ElemType e)
{LinkList q = L, p = L->next;while ((p) && (e > p->data)) {q = p;p = p->next;}LinkList s = MakeNewLNode(e);q->next = s;s->next = p;return RET_OK;
}/* 初始条件:按非升序排列的线性表 L 已存在操作结果:在 L 中按非升序插入新的数据元素 e */
Status InsertDescend(LinkList L, ElemType e)
{LinkList q = L, p = L->next;while ((p) && (e < p->data)) {q = p;p = p->next;}LinkList s = MakeNewLNode(e);q->next = s;s->next = p;return RET_OK;
}/* 初始条件:线性表 L 已存在操作结果:在 L 的头部插入新的数据元素 e, 作为链表的第一个元素 */
Status HeadInsert(LinkList L, ElemType e)
{LinkList newLNode = MakeNewLNode(e);newLNode->next = L->next;L->next = newLNode;return RET_OK;
}/* 初始条件:线性表 L 已存在操作结果:在 L 的尾部插入新的数据元素 e, 作为链表的最后一个元素 */
Status EndInsert(LinkList L, ElemType e)
{LinkList p = L;while (p->next) {p = p->next;}LinkList newLNode = MakeNewLNode(e);p->next = newLNode;return RET_OK;
}/* 初始条件:线性表 L 已存在,且有不少于 1 个元素操作结果:删除 L 的第一个数据元素,并由 e 返回其值 */
Status DeleteFirst(LinkList L, ElemType *e)
{LinkList p = L->next;CHECK_VALUE(!p, ERR_NOT_FOUND)*e = p->data;L->next = p->next;free(p);return RET_OK;
}/* 初始条件:线性表 L 已存在,且有不少于 1 个元素操作结果:删除 L 的最后一个数据元素,并用 e 返回其值 */
Status DeleteTail(LinkList L, ElemType *e)
{LinkList p = L;CHECK_VALUE(!(p->next), ERR_NOT_FOUND)LinkList q = NULL;while (p->next) {q = p;p = p->next;}q->next = NULL;*e = p->data;free(p);return RET_OK;
}/* 删除表中值为 e 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteElem(LinkList L, ElemType e)
{LinkList p = L, q;while (p) {q = p->next;if ((q) && (q->data == e)) {p->next = q->next;free(q);return TRUE;}p = q;}return FALSE;
}/* 用 e 取代表 L 中第 i 个元素的值 */
Status RePlaceElem(LinkList L, int i, ElemType e)
{LinkList p = L;int j = 0;while ((p->next) && (j < i)) {++j;p = p->next;}CHECK_VALUE(j != i, ERR_NOT_FOUND)p->data = e;return RET_OK;
}/* 按非降序建立 n 个元素的线性表 */
Status CreateAscend(LinkList *L, int n)
{CHECK_VALUE(n < 1, ERR_PARA)CHECK_VALUE(!L, ERR_NULL_PTR)InitList(L);printf("Please input %d elements: ", n);ElemType e;scanf_s("%d", &e);LinkList newLNode = MakeNewLNode(e);(*L)->next = newLNode;for (int i = 0; i < n - 1; ++i) {scanf_s("%d", &e);LinkList newLNode = MakeNewLNode(e);LinkList q = *L;LinkList p = (*L)->next;while ((p) && (p->data < e)) {q = p;p = p->next;}newLNode->next = q->next;q->next = newLNode;}return RET_OK;
}/* 按非升序建立 n 个元素的线性表 */
Status CreateDescend(LinkList *L, int n)
{CHECK_VALUE(n < 1, ERR_PARA)CHECK_VALUE(!L, ERR_NULL_PTR)InitList(L);printf("Please input %d elements: ", n);ElemType e;scanf_s("%d", &e);LinkList newLNode = MakeNewLNode(e);(*L)->next = newLNode;for (int i = 0; i < n - 1; ++i) {scanf_s("%d", &e);LinkList newLNode = MakeNewLNode(e);LinkList q = *L;LinkList p = (*L)->next;while ((p) && (p->data > e)) {q = p;p = p->next;}newLNode->next = q->next;q->next = newLNode;}return RET_OK;
}/* 返回表头元素的值 */
Status GetFirstElem(LinkList L, ElemType *e)
{LinkList p = L->next;CHECK_VALUE(!p, ERR_NOT_FOUND)*e = p->data;return RET_OK;
}
4) algorithm.h
/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H#include "singleLinkList.h"/* 算法 2.11,逆位序(插在表头)输入 n 个元素的值,建立带表头结构的单链线性表 L */
void CreateList(LinkList *L, int n);/* 正位序(插在表尾)输入 n 个元素的值,建立带表头结构的单链线性表 */
void CreateList2(LinkList *L, int n);/* 算法 2.12,已知单链线性表 La 和 Lb 的元素按值非递减排列归并 La 和 Lb 得到新的单链线性表 Lc,Lc 的元素也按值非递减排列此处需要释放 Lb 头节点故需要传入 Lb 指针变量 */
void MergeList(LinkList La, LinkList *Lb, LinkList *Lc);/* 算法 2.1 其他实现,将所有在线性表 Lb 中但不在 La 中的数据元素插入到 La 中 */
void Union(LinkList La, LinkList Lb);/* 算法 2.2 其他实现,已知线性表 La 和 Lb 中的数据元素按值非递减排列归并 La 和 Lb 得到新的线性表 Lc,Lc 的数据元素也按值非递减排列 */
Status MergeList2(LinkList La, LinkList Lb, LinkList *Lc);#endif // !ALGORITHM_H
5) algorithm.c
/* 算法实现源文件 */
#include "algorithm.h"
#include "auxiliary.h"
#include <stdlib.h>
#include <stdio.h>/* 算法 2.11,逆位序(插在表头)输入 n 个元素的值,建立带表头结构的单链线性表 L */
void CreateList(LinkList *L, int n)
{(void)InitList(L);printf("Please input %d integers: ", n);int num;LinkList p;for (int i = 0; i < n; ++i) {scanf_s("%d", &num);p = MakeNewLNode(num);p->next = (*L)->next;(*L)->next = p;}
}/* 正位序(插在表尾)输入 n 个元素的值,建立带表头结构的单链线性表 */
void CreateList2(LinkList *L, int n)
{(void)InitList(L);LinkList q = *L, p;int num;printf("Please input %d integers: ", n);for (int i = 0; i < n; ++i) {scanf_s("%d", &num);p = MakeNewLNode(num);q->next = p;q = p;}
}/* 算法 2.12,已知单链线性表 La 和 Lb 的元素按值非递减排列归并 La 和 Lb 得到新的单链线性表 Lc,Lc 的元素也按值非递减排列 此处需要释放 Lb 头节点故需要传入 Lb 指针变量 */
void MergeList(LinkList La, LinkList *Lb, LinkList *Lc)
{LinkList pa = La->next, pb = (*Lb)->next, pc = NULL;*Lc = pc = La;while (pa && pb) {if (pa->data <= pb->data) {pc->next = pa;pc = pa;pa = pa->next;}else {pc->next = pb;pc = pb;pb = pb->next;}}pc->next = pa ? pa : pb;free(*Lb);
}/* 算法 2.1 其他实现,将所有在线性表 Lb 中但不在 La 中的数据元素插入到 La 中 */
void Union(LinkList La, LinkList Lb)
{int lengthLa = ListLength(La);int lengthLb = ListLength(Lb);ElemType e;for (int i = 0; i < lengthLb; ++i) {GetElem(Lb, i + 1, &e);if (!LocateElem(La, e, Equal)) {ListInsert(La, ++lengthLa, e);}}
}/* 算法 2.2 其他实现,已知线性表 La 和 Lb 中的数据元素按值非递减排列归并 La 和 Lb 得到新的线性表 Lc,Lc 的数据元素也按值非递减排列 */
Status MergeList2(LinkList La, LinkList Lb, LinkList *Lc)
{CHECK_VALUE(!Lc, ERR_NULL_PTR)InitList(Lc);int lengthLa = ListLength(La);int lengthLb = ListLength(Lb);ElemType ai, bj;int i = 1, j = 1, k = 0;while ((i <= lengthLa) && (j <= lengthLb)) {GetElem(La, i, &ai);GetElem(Lb, j, &bj);if (ai <= bj) {ListInsert(*Lc, ++k, ai);++i;} else {ListInsert(*Lc, ++k, bj);++j;}}while (i <= lengthLa) {GetElem(La, i++, &ai);ListInsert(*Lc, ++k, ai);}while (j <= lengthLb) {GetElem(Lb, j++, &bj);ListInsert(*Lc, ++k, bj);}return RET_OK;
}
6) auxiliary.h
/* 辅助函数定义头文件 */#ifndef AUXILIARY_H
#define AUXILIARY_H
#include "singleLinkList.h"void Visit(ElemType e);
Bollean Equal(ElemType e1, ElemType e2);
void ShowList(char str[], LinkList L);#endif // !AUXILIARY_H
7) auxiliary.c
/* 辅助函数实现源文件 */#include "auxiliary.h"
#include <stdio.h>void Visit(ElemType e)
{printf("%d ", e);
}Bollean Equal(ElemType e1, ElemType e2)
{return (e1 == e2) ? TRUE : FALSE;
}void ShowList(char str[], LinkList L)
{printf("%s", str);ListTraverse(L, Visit);putchar('\n');
}
8) main.c
/* 主函数入口源文件 */
#include "singleLinkList.h"
#include "algorithm.h"
#include "auxiliary.h"
#include <stdio.h>int main(void)
{int n = 5;LinkList La;CreateList(&La, n);ShowList("La is: ", La);LinkList Lb;CreateList2(&Lb, n);ShowList("Lb is: ", Lb);LinkList Lc;MergeList(La, &Lb, &Lc);ShowList("Lc is: ", Lc);int ret = DestroyList(&Lc);CHECK_RET(ret);/* free() 的作用:仅仅是释放堆内存,不将指针置空 */printf("After Destroy list Lc, the address of Lc is %p\n", Lc);/* 算法 2.1 其他实现测试 */LinkList LA, LB;CreateList2(&LA, 5);CreateList2(&LB, 5);ShowList("LA is: ", LA);ShowList("LB is: ", LB);Union(LA, LB);ShowList("LA is: ", LA);ShowList("LB is: ", LB);DestroyList(&LA);DestroyList(&LB);/* 算法 2.2 其他实现测试 */LinkList Lm, Ln;CreateList2(&Lm, 5);CreateList2(&Ln, 5);ShowList("Lm is: ", Lm);ShowList("Ln is: ", Ln);LinkList Lu;MergeList2(Lm, Ln, &Lu);ShowList("Lu is: ", Lu);DestroyList(&Lm);DestroyList(&Ln);DestroyList(&Lu);/* 测试其他 */LinkList L;printf("Please input the element num of L for create ascend: ");int num;scanf_s("%d", &num);CreateAscend(&L, num);ShowList("L is: ", L);InsertAscend(L, 10);printf("After insert 10 for ascend, ");ShowList("L is: ", L);HeadInsert(L, 12);EndInsert(L, 9);printf("After insert 12 in the head of L, insert 9 in the tail of L, ");ShowList("L is: ", L);ElemType e;printf("Please input the element to be delete: ");scanf_s("%d", &e);printf("delete %d %s\n", e, (DeleteElem(L, e) == TRUE) ? "success" : "failed");ShowList("L is: ", L);printf("Please input the order of the element to be replace and the new value: ");scanf_s("%d%d", &num, &e);RePlaceElem(L, num, e);ShowList("L is: ", L);DestroyList(&L);printf("Create L for descend, please input the num of L: ");scanf_s("%d", &num);CreateDescend(&L, num);ShowList("L is: ", L);InsertDescend(L, 10);printf("After insert 10 in L for descend, ");ShowList("L is: ", L);printf("Please input the element to be delete: ");scanf_s("%d", &e);printf("delete %d %s\n", e, (DeleteElem(L, e) == TRUE) ? "success" : "failed");ShowList("L is: ", L);ElemType e2;DeleteFirst(L, &e);DeleteTail(L, &e2);printf("After delete head element %d and tail element %d, ", e, e2);ShowList("L is: ", L);DestroyList(&L);return 0;
}
3. 运行示例