1. 背景说明
需要从书目文件中获取其关键字及对应的书号索引

bookInfo.txt
- 005 Computer Data Structures
- 010 Introduction to Data Structures
- 023 Fundamentals of Data Structures
- 034 The Design and Analysis of Computer Algorithms
- 050 Introduction to Numerical Analysis
- 067 Numerical Analysis
normalWord.txt
- 5
- A
- An
- In
- Of
- The
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) linkList.h
- /* 具有实用意义的线性链表(带头结点)实现头文件 */
-
- #ifndef LINKLIST_H
- #define LINKLIST_H
-
- #include "status.h"
-
- typedef int ElemType;
-
- typedef struct LNode {
- ElemType data;
- struct LNode *next;
- } LNode, *Link, *Position;
-
- typedef struct LinkList {
- Link head;
- Link tail;
- int length;
- } LinkList;
-
- /* 分配由指向的值为 e 的结点,并返回节点地址;若分配失败, 则返回 NULL */
- Link MakeNewLNode(ElemType e);
-
- /* 释放 p 所指结点 */
- Status FreeLNode(Link *p);
-
- /* 构造一个空的线性链表 */
- Status InitList(LinkList *list);
-
- /* 将线性链表 list 重置为空表,并释放原链表的结点空间 */
- Status ClearList(LinkList *list);
-
- /* 销毁线性链表 list,list 不再存在 */
- Status DestroyList(LinkList *list);
-
- /* head 指向 list 的一个结点,把 head 当做头结点,将 s 所指结点插入在第一个结点之前 */
- Status InsFirst(Link head, Link s, LinkList *list);
-
- /* head 指向 list 的一个结点,把 head 当做头结点,删除链表中的第一个结点并以 q 返回
- 若链表为空( head 指向尾结点),q = NULL */
- Status DelFirst(Link head, Link *q, LinkList *list);
-
- /* 将指针 s(s->data 为第一个数据元素)所指(彼此以指针相链,以 NULL 结尾)的一
- 串结点链接在线性链表 list 的最后一个结点之后,并改变链表 list 的尾指针指向新的尾结点 */
- Status Append(Link s, LinkList *list);
-
- /* 已知 p 指向线性链表 list 中的一个结点,用 *targetPos 返回 p 所指结点的直接前驱的位置若无前驱
- 则用 *targetPos 返回 NULL */
- Status PriorPos(const Link p, const LinkList *list, Position *targetPos);
-
- /* 删除线性链表 list 中的尾结点并以 q 返回,改变链表 list 的尾指针指向新的尾结点 */
- Status Remove(Link *q, LinkList *list);
-
- /* 已知 *p 指向线性链表 list 中的一个结点,将 s 所指结点插入在 *p 所指结点之前
- 并修改指针 *p 指向新插入的结点 */
- Status InsBefore(Link s, Link *p, LinkList *list);
-
- /* 已知 *p 指向线性链表 list 中的一个结点,将 s 所指结点插入在 *p 所指结点之后
- 并修改指针 p 指向新插入的结点 */
- Status InsAfter(Link s, Link *p, LinkList *list);
-
- /* 已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值 */
- Status SetCurrElem(ElemType e, Link p);
-
- /* 已知 p 指向线性链表中的一个结点,用 *e 返回 p 所指结点中数据元素的值 */
- Status GetCurrElem(Link p, ElemType *e);
-
- /* 若线性链表 list 为空表,则用 *isEmpty 返回 TRUE,否则用 *isEmpty 返回 FALSE */
- Status ListEmpty(const LinkList *list, Bollean *isEmpty);
-
- /* 用 *num 返回线性链表 list 中元素个数 */
- Status ListLength(const LinkList *list, int *num);
-
- /* 用 *targetPos 返回线性链表 list 中头结点的位置 */
- Status GetHead(const LinkList *L, Position *targetPos);
-
- /* 用 *targetPos 返回线性链表 list 中最后一个结点的位置 */
- Status GetLast(const LinkList *L, Position *targetPos);
-
- /* 已知 p 指向线性链表 list 中的一个结点,用 *targetPos 返回 p 所指结点的直接后继的位置
- 若无后继,则用 *targetPos 返回 NULL */
- Status NextPos(Link p, Position *targetPos);
-
- /* 返回 p 指示线性链表 list 中第 i 个结点的位置,并返回 OK,i 值不合法时
- 返回 ERROR, i = 0 为头结点 */
- Status LocatePos(int i, const LinkList *list, Link *p);
-
- /* 用 *targetPos 返回线性链表 list 中第 1 个与 e 满足函数 compare() 判定关系的元素的位
- 置若不存在这样的元素,则用 *targetPos 返回 NULL */
- Status LocateElem(ElemType e, Bollean(*compare)(ElemType, ElemType), const LinkList *list, Position *targetPos);
-
- /* 依次对 list 的每个数据元素调用函数 visit()。一旦 visit() 失败,则操作失败 */
- Status ListTraverse(void(*visit)(ElemType), const LinkList *list);
-
- /* 已知 list 为有序线性链表,将元素 e 按非降序插入在 list 中 */
- Status InsertAscend(ElemType e, int(*compare)(ElemType, ElemType), LinkList *list);
-
- /* 若升序链表 list 中存在与 e 满足判定函数 compare() 取值为 0 的元素,则 q 指示 list 中
- 第一个值为 e 的结点的位置,并用 *find 返回 TRUE;否则 q 指示第一个与 e 满足判定函数
- compare() 取值 > 0 的元素的前驱的位置, 并用 *find 返回 FALSE */
- Status LocateElemP(ElemType e, int(*compare)(ElemType, ElemType), const LinkList *list, Bollean *find, Position *q);
-
- #endif // !LINKLIST_H
3) linkList.c
- /* 具有实用意义的线性链表(带头结点)实现源文件 */
-
- #include "linkList.h"
- #include
- #include
-
- /* 分配由指向的值为 e 的结点,并返回节点地址;若分配失败, 则返回 NULL */
- Link MakeNewLNode(ElemType e)
- {
- Link newLNode = (Link)malloc(sizeof(LNode));
- CHECK_NULL(newLNode);
- newLNode->data = e;
- newLNode->next = NULL;
-
- return newLNode;
- }
-
- /* 释放 p 所指结点 */
- Status FreeLNode(Link *p)
- {
- CHECK_VALUE(!p || !(*p), ERR_NULL_PTR);
- free(*p);
- *p = NULL;
-
- return RET_OK;
- }
-
- /* 构造一个空的线性链表 */
- Status InitList(LinkList *list)
- {
- CHECK_VALUE(!list, ERR_NULL_PTR);
- Link newLNode = (Link)malloc(sizeof(LNode));
- CHECK_VALUE(!newLNode, ERR_MEMORY_ALLOCATE);
- newLNode->next = NULL;
- list->head = list->tail = newLNode;
- list->length = 0;
-
- return RET_OK;
- }
-
- /* 将线性链表 list 重置为空表,并释放原链表的结点空间 */
- Status ClearList(LinkList *list)
- {
- CHECK_VALUE(!list, ERR_NULL_PTR);
- if (list->head == list->tail) {
- return RET_OK;
- }
-
- Link p = list->head->next;
- list->head->next = NULL;
- Link q = NULL;
- while (p != list->tail) {
- q = p;
- p = p->next;
- free(q);
- }
-
- free(p);
- list->tail = list->head;
- list->length = 0;
-
- return RET_OK;
- }
-
- /* 销毁线性链表 list,list 不再存在 */
- Status DestroyList(LinkList *list)
- {
- CHECK_VALUE(!list, ERR_NULL_PTR);
- ClearList(list);
- FreeLNode(&(list->head));
- list->tail = NULL;
-
- return RET_OK;
- }
-
- /* head 指向 list 的一个结点,把 head 当做头结点,将 s 所指结点插入在第一个结点之前 */
- Status InsFirst(Link head, Link s, LinkList *list)
- {
- CHECK_VALUE(!head || !s || !list, ERR_NULL_PTR);
- s->next = head->next;
- head->next = s;
- if (head == list->tail) {
- list->tail = s;
- }
-
- ++(list->length);
-
- return RET_OK;
- }
-
- /* head 指向 list 的一个结点,把 head 当做头结点,删除链表中的第一个结点并以 q 返回
- 若链表为空( head 指向尾结点),q = NULL */
- Status DelFirst(Link head, Link *q, LinkList *list)
- {
- CHECK_VALUE(!head || !q || !(*q) || !list, ERR_NULL_PTR);
- *q = head->next;
- if (!(*q)) {
- return RET_OK;
- }
-
- head->next = (*q)->next;
- --(list->length);
- if (!(head->next)) {
- list->tail = head;
- }
-
- return RET_OK;
- }
-
- /* 将指针 s(s->data 为第一个数据元素)所指(彼此以指针相链,以 NULL 结尾)的一
- 串结点链接在线性链表 list 的最后一个结点之后,并改变链表 list 的尾指针指向新的尾结点 */
- Status Append(Link s, LinkList *list)
- {
- CHECK_VALUE(!s || !list, ERR_NULL_PTR);
- int length = 1;
- list->tail->next = s;
- while (s->next) {
- ++length;
- s = s->next;
- }
-
- list->tail = s;
- list->length += length;
-
- return RET_OK;
- }
-
- /* 已知 p 指向线性链表 list 中的一个结点,用 *targetPos 返回 p 所指结点的直接前驱的位置若无前驱
- 则用 *targetPos 返回 NULL */
- Status PriorPos(const Link p, const LinkList *list, Position *targetPos)
- {
- CHECK_VALUE(!p || !list || !targetPos, ERR_NULL_PTR);
- Link q = list->head->next;
- if (p == q) {
- *targetPos = NULL;
- return RET_OK;
- }
-
- while (q->next != p) {
- q = q->next;
- }
-
- *targetPos = q;
-
- return RET_OK;
- }
-
- /* 删除线性链表 list 中的尾结点并以 q 返回,改变链表 list 的尾指针指向新的尾结点 */
- Status Remove(Link *q, LinkList *list)
- {
- CHECK_VALUE(!q || !(*q) || !list, ERR_NULL_PTR);
- if (list->length == 0) {
- *q = NULL;
- return RET_OK;
- }
-
- *q = list->tail;
- Link p = list->head;
- while (p->next != list->tail) {
- p = p->next;
- }
-
- p->next = NULL;
- list->tail = p;
- --(list->length);
-
- return RET_OK;
- }
-
- /* 已知 *p 指向线性链表 list 中的一个结点,将 s 所指结点插入在 *p 所指结点之前
- 并修改指针 *p 指向新插入的结点 */
- Status InsBefore(Link s, Link *p, LinkList *list)
- {
- CHECK_VALUE(!s || !p || !(*p) || !list, ERR_NULL_PTR);
- Link q;
- PriorPos(*p, list, &q);
- if (!q) {
- q = list->head;
- }
-
- s->next = *p;
- q->next = s;
- *p = s;
- ++(list->length);
-
- return RET_OK;
- }
-
- /* 已知 *p 指向线性链表 list 中的一个结点,将 s 所指结点插入在 *p 所指结点之后
- 并修改指针 p 指向新插入的结点 */
- Status InsAfter(Link s, Link *p, LinkList *list)
- {
- CHECK_VALUE(!s || !p || !(*p) || !list, ERR_NULL_PTR);
- if (*p == list->tail) {
- (*list).tail = s;
- }
-
- s->next = (*p)->next;
- (*p)->next = s;
- *p = s;
- ++(list->length);
-
- return RET_OK;
- }
-
- /* 已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值 */
- Status SetCurrElem(ElemType e, Link p)
- {
- CHECK_VALUE(!p, ERR_NULL_PTR);
- p->data = e;
-
- return RET_OK;
- }
-
- /* 已知 p 指向线性链表中的一个结点,用 *e 返回 p 所指结点中数据元素的值 */
- Status GetCurrElem(Link p, ElemType *e)
- {
- CHECK_VALUE(!p, ERR_NULL_PTR);
- *e = p->data;
-
- return RET_OK;
- }
-
- /* 若线性链表 list 为空表,则用 *isEmpty 返回 TRUE,否则用 *isEmpty 返回 FALSE */
- Status ListEmpty(const LinkList *list, Bollean *isEmpty)
- {
- CHECK_VALUE(!list || !isEmpty, ERR_NULL_PTR);
- *isEmpty = (list->length == 0) ? TRUE : FALSE;
-
- return RET_OK;
- }
-
- /* 用 *num 返回线性链表 list 中元素个数 */
- Status ListLength(const LinkList *list, int *num)
- {
- CHECK_VALUE(!list || !num, ERR_NULL_PTR);
- *num = list->length;
-
- return RET_OK;
- }
-
- /* 用 *targetPos 返回线性链表 list 中头结点的位置 */
- Status GetHead(const LinkList *L, Position *targetPos)
- {
- CHECK_VALUE(!L || !targetPos, ERR_NULL_PTR);
- *targetPos = L->head;
-
- return RET_OK;
- }
-
- /* 用 *targetPos 返回线性链表 list 中最后一个结点的位置 */
- Status GetLast(const LinkList *L, Position *targetPos)
- {
- CHECK_VALUE(!L || !targetPos, ERR_NULL_PTR);
- *targetPos = L->tail;
-
- return RET_OK;
- }
-
- /* 已知 p 指向线性链表 list 中的一个结点,用 *targetPos 返回 p 所指结点的直接后继的位置
- 若无后继,则用 *targetPos 返回 NULL */
- Status NextPos(Link p, Position *targetPos)
- {
- CHECK_VALUE(!p || !targetPos, ERR_NULL_PTR);
- *targetPos = p->next;
-
- return RET_OK;
- }
-
- /* 返回 p 指示线性链表 list 中第 i 个结点的位置,并返回 OK,i 值不合法时
- 返回 ERROR, i = 0 为头结点 */
- Status LocatePos(int i, const LinkList *list, Link *p)
- {
- CHECK_VALUE(!list || !p, ERR_NULL_PTR);
- CHECK_VALUE((i < 0 || i > list->length), ERR_PARA);
- *p = list->head;
- for (int j = 0; j < i; ++j) {
- *p = (*p)->next;
- }
-
- return RET_OK;
- }
-
- /* 用 *targetPos 返回线性链表 list 中第 1 个与 e 满足函数 compare() 判定关系的元素的位
- 置若不存在这样的元素,则用 *targetPos 返回 NULL */
- Status LocateElem(ElemType e, Bollean(*compare)(ElemType, ElemType), const LinkList *list, Position *targetPos)
- {
- CHECK_VALUE(!compare || !list || !targetPos, ERR_NULL_PTR);
- Link p = list->head->next;
- while ((p) && !(compare(p->data, e))) {
- p = p->next;
- }
-
- *targetPos = p;
-
- return RET_OK;
- }
-
- /* 依次对 list 的每个数据元素调用函数 visit()。一旦 visit() 失败,则操作失败 */
- Status ListTraverse(void(*visit)(ElemType), const LinkList *list)
- {
- CHECK_VALUE(!visit || !list, ERR_NULL_PTR);
- Link p = list->head->next;
- for (int i = 0; i < list->length; ++i) {
- visit(p->data);
- p = p->next;
- }
-
- return RET_OK;
- }
-
- /* 已知 list 为有序线性链表,将元素 e 按非降序插入在 list 中 */
- Status InsertAscend(ElemType e, int(*compare)(ElemType, ElemType), LinkList *list)
- {
- CHECK_VALUE(!compare || !list, ERR_NULL_PTR);
- Link q = list->head;
- Link p = q->next;
- while ((p) && (compare(p->data, e) < 0)) {
- q = p;
- p = p->next;
- }
-
- Link newLNode = MakeNewLNode(e);
- CHECK_VALUE(!newLNode, ERR_NULL_PTR);
- q->next = newLNode;
- newLNode->next = p;
- ++(list->length);
- if (!p) {
- list->tail = newLNode;
- }
-
- return RET_OK;
- }
-
- /* 若升序链表 list 中存在与 e 满足判定函数 compare() 取值为 0 的元素,则 q 指示 list 中
- 第一个值为 e 的结点的位置,并用 *find 返回 TRUE;否则 q 指示第一个与 e 满足判定函数
- compare() 取值 > 0 的元素的前驱的位置, 并用 *find 返回 FALSE */
- Status LocateElemP(ElemType e, int(*compare)(ElemType, ElemType), const LinkList *list, Bollean *find, Position *q)
- {
- CHECK_VALUE(!compare || !list || !find || !q, ERR_NULL_PTR);
- Link pos = list->head;
- Link p = pos->next;
- while ((p) && (compare(p->data, e) < 0)) {
- pos = p;
- p = p->next;
- }
-
- if ((!p) || (compare(p->data, e) > 0)) {
- *q = pos;
- *find = FALSE;
- }
-
- *q = p;
- *find = TRUE;
-
- return RET_OK;
- }
4) hString.h
- /* 串的堆分配存储实现头文件 */
-
- #ifndef HSTRING_H
- #define HSTRING_H
-
- #include "status.h"
-
- typedef struct {
- char *ch;
- int length;
- } HString;
-
- /* 初始化(产生空串)字符串 t */
- Status InitString(HString *t);
-
- /* 生成一个其值等于串常量 chars 的串 t */
- Status StrAssign(const char *chars, HString *t);
-
- /* 初始条件: 串 s 存在
- 操作结果: 由串 s 复制得串 t */
- Status StrCopy(const HString *s, HString *t);
-
- /* 初始条件: 串 s 存在
- 操作结果: 若 s 为空串,则用 *isEmpty 返回 TRUE,否则用 *isEmpty 返回 FALSE */
- Status StrEmpty(const HString *s, Bollean *isEmpty);
-
- /* 若 s > t,则返回值 > 0;若 s = t,则返回值 = 0;若 s < t,则返回值 < 0 */
- Status StrCompare(const HString *s, const HString *t, int *ret);
-
- /* 返回 s 的元素个数,称为串的长度 */
- Status StrLength(const HString *s, int *length);
-
- /* 将 s 清为空串 */
- Status ClearString(HString *s);
-
- /* 用 t 返回由 s1 和 s2 联接而成的新串 */
- Status Concat(const HString *s1, const HString *s2, HString *t);
-
- /* 用 sub 返回串 s 的第 pos 个字符起长度为 len 的子串
- 其中,1 ≤ pos ≤ sLength 且 0 ≤ len ≤ sLength - pos + 1 */
- Status SubString(int pos, int len, const HString *s, HString *sub);
-
- /* 算法 4.1,t 为非空串。若主串 s 中第 pos 个字符之后存在与 t 相等的子串
- 则返回第一个这样的子串在 s 中的位置,否则返回 0 */
- Status Index(int pos, const HString *s, const HString *t, int *targetPos);
-
- /* 算法 4.4, 在串 s 的第 pos 个字符之前插入串 t, 1 ≤ pos ≤ sLength + 1 */
- Status StrInsert(int pos, const HString *t, HString *s);
-
- /* 从串 s 中删除第 pos 个字符起长度为 len 的子串 */
- Status StrDelete(int pos, int len, HString *s);
-
- /* 初始条件: 串 s, t 和 v 存在, t 是非空串(此函数与串的存储结构无关)
- 操作结果: 用 v 替换主串 s 中出现的所有与 t 相等的不重叠的子串 */
- Status Replace(const HString *t, const HString *v, HString *s);
-
- /* 堆分配类型的字符串无法销毁(结构体)*/
- void DestroyString(void);
-
- /* 输出 t 字符串 */
- Status StrPrint(const HString *t);
-
- #endif // !HSTRING_H
5) hString.c
- /* 串的堆分配存储实现源文件 */
-
- #include "hString.h"
- #include
- #include
- #include
-
- /* 初始化(产生空串)字符串 t */
- Status InitString(HString *t)
- {
- CHECK_VALUE(!t, ERR_NULL_PTR);
- t->length = 0;
- t->ch = NULL;
-
- return RET_OK;
- }
-
- /* 生成一个其值等于串常量 chars 的串 t */
- Status StrAssign(const char *chars, HString *t)
- {
- CHECK_VALUE(!chars || !t, ERR_NULL_PTR);
- if (t->ch) {
- free(t->ch);
- }
-
- int length = (int)strlen(chars);
- if (length == 0) {
- t->ch = NULL;
- t->length = 0;
- return RET_OK;
- }
-
- t->ch = (char *)malloc(sizeof(char) * length);
- CHECK_VALUE(!(t->ch), ERR_MEMORY_ALLOCATE);
- t->length = length;
- for (int i = 0; i < length; ++i) {
- t->ch[i] = chars[i];
- }
-
- return RET_OK;
- }
-
- /* 初始条件: 串 s 存在
- 操作结果: 由串 s 复制得串 t */
- Status StrCopy(const HString *s, HString *t)
- {
- CHECK_VALUE(!s || !t, ERR_NULL_PTR);
- if (t->ch) {
- free(t->ch);
- }
-
- t->ch = (char *)malloc(sizeof(char) * (s->length));
- CHECK_VALUE(!(t->ch), ERR_MEMORY_ALLOCATE);
- t->length = s->length;
- for (int i = 0; i < s->length; ++i) {
- t->ch[i] = s->ch[i];
- }
-
- return RET_OK;
- }
-
- /* 初始条件: 串 s 存在
- 操作结果: 若 s 为空串,则用 *isEmpty 返回 TRUE,否则用 *isEmpty 返回 FALSE */
- Status StrEmpty(const HString *s, Bollean *isEmpty)
- {
- CHECK_VALUE(!s || isEmpty, ERR_NULL_PTR);
- *isEmpty = ((s->length == 0) && (s->ch == NULL)) ? TRUE : FALSE;
-
- return RET_OK;
- }
-
- /* 若 s > t,则返回值 > 0;若 s = t,则返回值 = 0;若 s < t,则返回值 < 0 */
- Status StrCompare(const HString *s, const HString *t, int *ret)
- {
- CHECK_VALUE(!s || !t || !ret, ERR_NULL_PTR);
- for (int i = 0; (i < s->length) && (i < t->length); ++i) {
- if (s->ch[i] != t->ch[i]) {
- *ret = s->ch[i] - t->ch[i];
- return RET_OK;
- }
- }
-
- *ret = s->length - t->length;
-
- return RET_OK;
- }
-
- /* 返回 s 的元素个数,称为串的长度 */
- Status StrLength(const HString *s, int *length)
- {
- CHECK_VALUE(!s || !length, ERR_NULL_PTR);
- *length = s->length;
-
- return RET_OK;
- }
-
- /* 将 s 清为空串 */
- Status ClearString(HString *s)
- {
- CHECK_VALUE(!s, ERR_NULL_PTR);
- if (s->ch) {
- free(s->ch);
- s->ch = NULL;
- }
-
- s->length = 0;
-
- return RET_OK;
- }
-
- /* 用 t 返回由 s1 和 s2 联接而成的新串 */
- Status Concat(const HString *s1, const HString *s2, HString *t)
- {
- CHECK_VALUE(!s1 || !s2 || !t, ERR_NULL_PTR);
- if (t->ch) {
- free(t->ch);
- }
-
- int length = s1->length + s2->length;
- t->ch = (char *)malloc(sizeof(char) * length);
- CHECK_VALUE(!(t->ch), ERR_MEMORY_ALLOCATE);
- t->length = length;
- for (int i = 0; i < s1->length; ++i) {
- t->ch[i] = s1->ch[i];
- }
-
- for (int i = 0; i < s2->length; ++i) {
- t->ch[s1->length + i] = s2->ch[i];
- }
-
- return RET_OK;
- }
-
- /* 用 sub 返回串 s 的第 pos 个字符起长度为 len 的子串
- 其中,1 ≤ pos ≤ sLength 且 0 ≤ len ≤ sLength - pos + 1 */
- Status SubString(int pos, int len, const HString *s, HString *sub)
- {
- CHECK_VALUE(!s || !sub, ERR_NULL_PTR);
- CHECK_VALUE((pos < 1) || (pos > s->length) || (len < 1) || (len > s->length - pos + 1), ERR_PARA);
- if (sub->ch) {
- free(sub->ch);
- }
-
- if (len == 0) {
- sub->ch = NULL;
- sub->length = 0;
- } else {
- sub->ch = (char *)malloc(sizeof(char) * len);
- CHECK_VALUE(!(sub->ch), ERR_MEMORY_ALLOCATE);
- for (int i = 0; i < len; ++i) {
- sub->ch[i] = s->ch[pos - 1 + i];
- }
-
- sub->length = len;
- }
-
- return RET_OK;
- }
-
- /* 算法 4.1,t 为非空串。若主串 s 中第 pos 个字符之后存在与 t 相等的子串
- 则返回第一个这样的子串在 s 中的位置,否则返回 0 */
- Status Index(int pos, const HString *s, const HString *t, int *targetPos)
- {
- CHECK_VALUE(!s || !t || !targetPos, ERR_NULL_PTR);
- /* 模块内部调用,不检查返回值,外部调用需要检查 */
- int sLength, tLength;
- StrLength(s, &sLength);
- StrLength(t, &tLength);
- int maxRange = sLength - tLength + 1;
- CHECK_VALUE((pos < 1) || (pos > maxRange), ERR_PARA);
- HString sub;
- InitString(&sub);
- Status subRet;
- int ret;
- while (pos <= maxRange) {
- subRet = SubString(pos, tLength, s, &sub);
- CHECK_VALUE(subRet != RET_OK, subRet);
- StrCompare(s, t, &ret);
- if (ret != 0) {
- ++pos;
- } else {
- *targetPos = pos;
- return RET_OK;
- }
- }
-
- *targetPos = 0;
-
- return RET_OK;
- }
-
- /* 算法 4.4, 在串 s 的第 pos 个字符之前插入串 t, 1 ≤ pos ≤ sLength + 1 */
- Status StrInsert(int pos, const HString *t, HString *s)
- {
- CHECK_VALUE(!t || !s, ERR_NULL_PTR);
- CHECK_VALUE((pos < 1) || (pos > s->length + 1), ERR_PARA);
- if (s->length == 0) {
- return RET_OK;
- }
-
- s->ch = (char *)realloc(s->ch, sizeof(char) * (unsigned long long)(s->length + s->length));
- CHECK_VALUE(!(s->ch), ERR_MEMORY_ALLOCATE);
- for (int i = s->length - 1; i >= pos - 1; --i) {
- s->ch[i + t->length] = s->ch[i];
- }
-
- s->length += t->length;
- for (int i = 0; i < t->length; ++i) {
- s->ch[pos - 1 + i] = t->ch[i];
- }
-
- return RET_OK;
- }
-
- /* 从串 s 中删除第 pos 个字符起长度为 len 的子串 */
- Status StrDelete(int pos, int len, HString *s)
- {
- CHECK_VALUE(!s, ERR_NULL_PTR);
- CHECK_VALUE((pos < 1) || (pos > s->length) || (len < 1) || (len > s->length - pos + 1), ERR_PARA);
- for (int i = pos - 1; i < s->length - len; ++i) {
- s->ch[i] = s->ch[i + len];
- }
-
- s->ch = (char *)realloc(s->ch, sizeof(char) * s->length);
- CHECK_VALUE(!s->ch, ERR_MEMORY_ALLOCATE);
- s->length -= len;
-
- return RET_OK;
- }
-
- /* 初始条件: 串 s, t 和 v 存在, t 是非空串(此函数与串的存储结构无关)
- 操作结果: 用 v 替换主串 s 中出现的所有与 t 相等的不重叠的子串 */
- Status Replace(const HString *t, const HString *v, HString *s)
- {
- CHECK_VALUE(!t || !v || !s, ERR_NULL_PTR);
- int pos = 1, targetPos, tLength, vLength;
- StrLength(t, &tLength);
- StrLength(v, &vLength);
- Status ret;
- do {
- Index(pos, s, t, &targetPos);
- pos = targetPos;
- if (pos) {
- ret = StrDelete(pos, tLength, s);
- CHECK_VALUE(ret != RET_OK, ret);
- ret = StrInsert(pos, t, s);
- CHECK_VALUE(ret != RET_OK, ret);
- pos += vLength;
- }
- } while (pos);
-
- return RET_OK;
- }
-
- /* 堆分配类型的字符串无法销毁(结构体)*/
- void DestroyString(void)
- {
- printf("Do not need to destroy!\n");
- }
-
- /* 输出 t 字符串 */
- Status StrPrint(const HString *t)
- {
- CHECK_VALUE(!t, ERR_NULL_PTR);
- for (int i = 0; i < t->length; ++i) {
- putchar(t->ch[i]);
- }
-
- return RET_OK;
- }
6) bookNameSort.h
- /* 关键字索引表定义头文件 */
-
- #ifndef BOOKNAMESORT_H
- #define BOOKNAMESORT_H
-
- #include "hString.h"
- #include "linkList.h"
-
- #define MAX_KEY_NUM 25 /* 索引表的最大容量(关键词的最大数) */
- #define MAX_LINE_LEN 100 /* 书目串(书名 + 书号) buff 的最大长度 */
- #define MAX_KEY_WORD_LEN 15 /* 关键字最大长度 */
- #define MAX_WORD_NUM 10 /* 词表(一本书的关键词)的最大容量 */
- #define MAX_NORMAL_NUM 10 /* 常用词(仅指大写)的最大数 */
- #define MAX_BOOK_NUM 10 /* 最大书数量 */
-
- typedef struct {
- char *item[MAX_WORD_NUM];
- int last;
- } WordListType;
-
- typedef struct {
- char *item[MAX_NORMAL_NUM];
- int last;
- } NormalIdxType;
-
- typedef struct {
- HString key;
- LinkList bookNumList;
- } IdxTermType;
-
- typedef struct {
- IdxTermType item[MAX_KEY_NUM];
- int last;
- } IdxListType;
-
- typedef struct {
- char bookName[MAX_LINE_LEN];
- int bookNum;
- } BookTermType;
-
- typedef struct {
- BookTermType item[MAX_BOOK_NUM];
- int last;
- } BookListType;
-
- /* 初始化操作,置索引表 idxlist 为空表,且在 idxliat.item[0] 设一空串 */
- Status InitIdxList(IdxListType *idxList);
-
- Status ExtractKeyWord(const char *buff, const NormalIdxType *normalIdx, int *bookNum, WordListType *wordList);
-
- /* 用 keyWord 返回词表 wordList 中第 i 个关键词 */
- Status GetKeyWord(int i, const WordListType *wordList, HString *keyWord);
-
- /* 在索引表 idxList 中查询是否存在与 keyWord 相等的关键词。若存在,则用 *pos 返回其
- 在索引表中的位置, 且 *exist 取值 TRUE; 否则用 *pos 返回插入位置,且 *exist 取值 FALSE */
- Status LocateIdx(const IdxListType *idxList, const HString *keyWord, Bollean *exist, int *pos);
-
- /* 在索引表 idxList 的第 i 项前插入新关键词 keyWord,并初始化书号索引的链表为空表 */
- Status InsertNewKeyWord(int i, const HString *keyWord, IdxListType *idxList);
-
- /* 在索引表 idxList 的第 i 项前插入书号为 bookNum 的索引 */
- Status InsertBookNum(int i, int bookNum, IdxListType *idxList);
-
- /* 将书号为 bookNum 的关键词插入索引表 */
- Status InsIdxList(int bookNum, const WordListType *wordList, IdxListType *idxList);
-
- /* 将生成的索引表 idxList 输出到文件 file */
- Status SaveToFile(const char *fileName, const IdxListType *idxList);
-
- #endif // !BOOKNAMESORT_H
7) bookNameSort.c
- /* 关键字索引表实现源文件 */
-
- #include "bookNameSort.h"
- #include
- #include
- #include
- #include
-
- /* 初始化操作,置索引表 idxlist 为空表,且在 idxliat.item[0] 设一空串 */
- Status InitIdxList(IdxListType *idxList)
- {
- CHECK_VALUE(!idxList, ERR_NULL_PTR);
- idxList->last = 0;
-
- return RET_OK;
- }
-
- Status ExtractKeyWord(const char *buff, const NormalIdxType *normalIdx, int *bookNum, WordListType *wordList)
- {
- CHECK_VALUE(!buff || !normalIdx || !bookNum || !wordList, ERR_NULL_PTR);
- CHECK_VALUE(((int)strlen(buff) > MAX_LINE_LEN) || (buff[0] < '0') || (buff[0] > '9'), ERR_PARA);
- for (int i = 0; i < wordList->last; ++i) {
- free(wordList->item[i]);
- wordList->item[i] = NULL;
- }
-
- wordList->last = 0;
- *bookNum = (buff[0] - '0') * 100 + (buff[1] - '0') * 10 + (buff[2] - '0');
- const char *s1, *s2 = buff + 3;
- Bollean getEnd = FALSE;
- int length = 0;
- int i = 0;
- do {
- s1 = s2 + 1;
- s2 = strchr(s1, ' ');
- if (s2 == NULL) {
- s2 = strchr(s1, '\12');
- getEnd = TRUE;
- }
-
- length = (int)(s2 - s1);
- CHECK_VALUE(length > MAX_KEY_WORD_LEN, ERR_PARA);
- if (isupper(s1[0])) {
- wordList->item[wordList->last] = (char *)malloc(sizeof(char) * (unsigned long long)(length + 1));
- CHECK_VALUE(!(wordList->item[wordList->last]), ERR_MEMORY_ALLOCATE);
- for (i = 0; i < length; ++i) {
- wordList->item[wordList->last][i] = s1[i];
- }
-
- wordList->item[wordList->last][length] = '\0';
- for (i = 0; i < normalIdx->last; ++i) {
- if (strcmp(wordList->item[wordList->last], normalIdx->item[i]) == 0) {
- break;
- }
- }
-
- if (i != normalIdx->last) {
- free(wordList->item[wordList->last]);
- wordList->item[wordList->last] = NULL;
- continue;
- }
-
- ++(wordList->last);
- }
- } while (!getEnd);
-
- return RET_OK;
- }
-
- /* 用 keyWord 返回词表 wordList 中第 i 个关键词 */
- Status GetKeyWord(int i, const WordListType *wordList, HString *keyWord)
- {
- CHECK_VALUE(!wordList || !keyWord, ERR_NULL_PTR);
- CHECK_VALUE((i < 1) || (i > wordList->last + 1), ERR_PARA);
- Status ret = StrAssign(wordList->item[i - 1], keyWord);
- CHECK_VALUE(ret != RET_OK, ret);
-
- return RET_OK;
- }
-
- /* 在索引表 idxList 中查询是否存在与 keyWord 相等的关键词。若存在,则用 *pos 返回其
- 在索引表中的位置, 且 *exist 取值 TRUE; 否则用 *pos 返回插入位置,且 *exist 取值 FALSE */
- Status LocateIdx(const IdxListType *idxList, const HString *keyWord, Bollean *exist, int *pos)
- {
- CHECK_VALUE(!idxList || !keyWord || !exist || !pos, ERR_NULL_PTR);
- Status ret, retVal;
- for (int i = 0; i < idxList->last; ++i) {
- retVal = StrCompare(keyWord, &(idxList->item[i].key), &ret);
- CHECK_VALUE(retVal != RET_OK, retVal);
- if (ret == 0) {
- *exist = TRUE;
- *pos = i + 1;
- return RET_OK;
- }
-
- if (ret < 0) {
- *exist = FALSE;
- *pos = i + 1;
- return RET_OK;
- }
- }
-
- *exist = FALSE;
- *pos = idxList->last + 1;
-
- return RET_OK;
- }
-
- /* 在索引表 idxList 的第 i 项前插入新关键词 keyWord,并初始化书号索引的链表为空表 */
- Status InsertNewKeyWord(int i, const HString *keyWord, IdxListType *idxList)
- {
- CHECK_VALUE(!keyWord || !idxList, ERR_NULL_PTR);
- CHECK_VALUE((i < 1) || (i > idxList->last + 1) || (idxList->last == MAX_KEY_NUM), ERR_PARA);
- errno_t errRet;
- for (int j = idxList->last; j >= i; --j) {
- errRet = memcpy_s(&(idxList->item[j]), sizeof(IdxTermType), &(idxList->item[j - 1]), sizeof(IdxTermType));
- CHECK_VALUE(errRet != 0, errRet);
- }
-
- Status ret = InitString(&(idxList->item[i - 1].key));
- CHECK_VALUE(ret != RET_OK, ret);
- ret = StrCopy(keyWord, &(idxList->item[i - 1].key));
- CHECK_VALUE(ret != RET_OK, ret);
- ret = InitList(&(idxList->item[i - 1].bookNumList));
- CHECK_VALUE(ret != RET_OK, ret);
- ++(idxList->last);
-
- return RET_OK;
- }
-
- /* 在索引表 idxList 的第 i 项前插入书号为 bookNum 的索引 */
- Status InsertBookNum(int i, int bookNum, IdxListType *idxList)
- {
- CHECK_VALUE(!idxList, ERR_NULL_PTR);
- CHECK_VALUE((i < 1) || (i > idxList->last + 1), ERR_PARA);
- Link newLNode = MakeNewLNode(bookNum);
- CHECK_VALUE(!newLNode, ERR_MEMORY_ALLOCATE);
- Status ret = Append(newLNode, &(idxList->item[i - 1].bookNumList));
- CHECK_VALUE(ret != RET_OK, ret);
-
- return RET_OK;
- }
-
- /* 将书号为 bookNum 的关键词插入索引表 */
- Status InsIdxList(int bookNum, const WordListType *wordList, IdxListType *idxList)
- {
- HString keyWord = { 0 };
- int pos;
- Bollean exist;
- Status ret = 0;
- for (int i = 0; i < wordList->last; ++i) {
- ret = GetKeyWord(i + 1, wordList, &keyWord);
- CHECK_VALUE(ret != RET_OK, ret);
- ret = LocateIdx(idxList, &keyWord, &exist, &pos);
- CHECK_VALUE(ret != RET_OK, ret);
- if (!exist) {
- ret = InsertNewKeyWord(pos, &keyWord, idxList);
- CHECK_VALUE(ret != RET_OK, ret);
- }
-
- ret = InsertBookNum(pos, bookNum, idxList);
- CHECK_VALUE(ret != RET_OK, ret);
- }
-
- return RET_OK;
- }
-
- /* 将生成的索引表 idxList 输出到文件 file */
- Status SaveToFile(const char *fileName, const IdxListType *idxList)
- {
- CHECK_VALUE(!fileName || !idxList, ERR_NULL_PTR);
- FILE *fp;
- errno_t err_ret = fopen_s(&fp, fileName, "w");
- CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);
- fprintf_s(fp, "%d\n", idxList->last);
- for (int i = 0; i < idxList->last; ++i) {
- idxList->item[i].key.ch[0] = tolower(idxList->item[i].key.ch[0]);
- for (int j = 0; j < idxList->item[i].key.length; ++j) {
- fprintf_s(fp, "%c", idxList->item[i].key.ch[j]);
- }
-
- fprintf_s(fp, "\n%d\n", idxList->item[i].bookNumList.length);
- Link p = idxList->item[i].bookNumList.head;
- for (int j = 0; j < idxList->item[i].bookNumList.length; ++j) {
- p = p->next;
- fprintf_s(fp, "%d ", p->data);
- }
-
- fprintf_s(fp, "\n");
- }
-
- fclose(fp);
-
- return RET_OK;
- }
8) main.c
- #include "bookNameSort.h"
- #include
- #include
- #include
- #include
-
- int main(void)
- {
- /* Step 1 */
- FILE *fp;
- errno_t err_ret = fopen_s(&fp, "normalWord.txt", "r");
- CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);
- NormalIdxType normalIdx = { 0 };
- fscanf_s(fp, "%d", &normalIdx.last);
- char buff[MAX_KEY_WORD_LEN + 1];
- unsigned int length;
- for (int i = 0; i < normalIdx.last; ++i) {
- fscanf_s(fp, "%s", buff, MAX_KEY_WORD_LEN + 1);
- length = (int)strlen(buff) + 1;
- normalIdx.item[i] = (char *)malloc(sizeof(char) * length);
- strcpy_s(normalIdx.item[i], sizeof(char) * length, buff);
- }
-
- fclose(fp);
- err_ret = fopen_s(&fp, "bookInfo.txt", "r");
- CHECK_VALUE(err_ret != RET_OK, ERR_OPEN_FILE);
- WordListType wordList;
- int bookNum;
- Status ret;
- IdxListType idxList;
- InitIdxList(&idxList);
- char bookInfoBuff[MAX_LINE_LEN];
- BookListType bookList = { 0 };
- int bookCount = 0;
- while (fgets(bookInfoBuff, MAX_LINE_LEN, fp) != NULL) {
- ret = ExtractKeyWord(bookInfoBuff, &normalIdx, &bookNum, &wordList);
- CHECK_VALUE(ret != RET_OK, ret);
- ret = InsIdxList(bookNum, &wordList, &idxList);
- CHECK_VALUE(ret != RET_OK, ret);
- bookInfoBuff[(int)(strlen(bookInfoBuff)) - 1] = '\0';
- bookList.item[bookCount].bookNum = (bookInfoBuff[0] - '0') * 100 + (bookInfoBuff[1] - '0') * 10 +
- (bookInfoBuff[2] - '0');
- err_ret = strcpy_s(bookList.item[bookCount].bookName, sizeof(bookList.item[bookCount].bookName),
- bookInfoBuff);
- CHECK_VALUE(err_ret != RET_OK, err_ret);
- ++bookCount;
- }
-
- bookList.last = bookCount;
- fclose(fp);
- ret = SaveToFile("idxList.txt", &idxList);
- CHECK_VALUE(ret != RET_OK, ret);
-
- /* Step 2 */
- printf("Please input one key word: ");
- scanf_s("%s", buff, MAX_KEY_WORD_LEN + 1);
- int i = 0;
- while (buff[i]) {
- buff[i] = tolower(buff[i]);
- ++i;
- }
-
- HString hStr;
- ret = InitString(&hStr);
- CHECK_VALUE(ret != RET_OK, ret);
- ret = StrAssign(buff, &hStr);
- CHECK_VALUE(ret != RET_OK, ret);
- int retVal;
- i = 0;
- do {
- ret = StrCompare(&hStr, &(idxList.item[i].key), &retVal);
- CHECK_VALUE(ret != RET_OK, ret);
- ++i;
- } while ((retVal != 0) && (i < idxList.last));
-
- if (retVal) {
- printf("Not Found!\n");
- } else {
- Link p = idxList.item[i - 1].bookNumList.head->next;
- while (p) {
- int j;
- for (j = 0; (j < bookList.last) && (p->data != bookList.item[j].bookNum); ++j);
- if (j < bookList.last) {
- printf("%s\n", bookList.item[j].bookName);
- }
-
- p = p->next;
- }
- }
-
- /* Step 3 */
- for (int i = 0; i < normalIdx.last; ++i) {
- free(normalIdx.item[i]);
- }
-
- for (int i = 0; i < idxList.last; ++i) {
- ret = DestroyList(&(idxList.item[i].bookNumList));
- CHECK_VALUE(ret != RET_OK, ret);
- ret = ClearString(&(idxList.item[i].key));
- CHECK_VALUE(ret != RET_OK, ret);
- }
-
- return 0;
- }
3. 运行示例

生成文件 idxList.txt
- 9
- algorithms
- 1
- 34
- analysis
- 3
- 34 50 67
- computer
- 2
- 5 34
- data
- 3
- 5 10 23
- design
- 1
- 34
- fundamentals
- 1
- 23
- introduction
- 2
- 10 50
- numerical
- 2
- 50 67
- structures
- 3
- 5 10 23