建立词索引表
程序首先将存于
BookInfo
.
txt
文件中的每种书的书号及书名中的关键词提取出来。书 号存储于整型变量 BookNo
中,书名中的每个关键词先临时存储于全局变量
wdlist
中,
wdlist 的结构示例:

在提取书名的关键词时,要注意剔除
the
、
a
、
of
等非索引词。这些词在书名中一般是 小写,对于首字母是小写的单词不作处理即可。但这些非索引词若是书名的第 1
个单词, 则首字母也为大写。为了解决这个问题,将非索引词存入文件 NoIdx
.
txt
中,内容如下:
5
A
An
In
Of
The
NoIdx
.
txt
文件的内容可通过文字编辑软件自行输入。第
1
行为非索引词个数,单词按 字典顺序排列。程序将文件 NoIdx
.
txt
的内容读入全局变量
noidx
中。
noidx
的结构和 wdlist 相同
。对于书名中的每个单词,首先检索是否出现在
noidx 中,如果是,则不将该单词插入 wdlist 中作为关键词。
noidx 的结构:
程序依次根据临时存储于
wdlist
中的每个书名的关键词,产生和充实关键词索引表。
方法是:首先建一个空的关键词索引表变量
idxlist
,然后依次查询
wdlist
中的各个关键词 是否存在于 idxlist
中。如果已存在,则仅把该关键词的书号按升序插入相应的链表中。否 则先按字母顺序将 wdlist 中的关键词插入 idxlist
,再插入书号。
建立的书名关键词索引表 idxlist 的结构:

首先将存有书 名关键词索引表信息的文件 BookIdx
.
txt
的内容恢复到变量
idxlist
中。为方便 查询,将关键词一律存为小写。再将书目文件 BookInfo
.
txt
的内容存入到变量
booklist
中。程序运行时,从键盘输入一个书名关键词,并将此单词转为小写,在
idxlist
中查找。如果找到,则根据相应的链表中所存储的书号,依次查询
booklist
并输出相应的书名。
booklist 的结构:

/* 生成书名关键词索引文件bookidx.txt,算法4.9~4.14 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
/* --------------------------- 带头结点的线性链表类型 ------------------------------*/
typedef int ElemType;
typedef struct LNode /* 结点类型 */
{
ElemType data;
struct LNode *next;
}LNode, *Link, *Position;
typedef struct LinkList /* 链表类型 */
{
Link head, tail; /* 分别指向线性链表中的头结点和最后一个结点 */
int len; /* 指示线性链表中数据元素的个数 */
}LinkList;
/* ------------------------------------------------------------------------------------------*/
/* --------------------------- 串的堆分配存储表示 ------------------------------*/
typedef struct
{
char *ch; /* 若是非空串,则按串长分配存储区,否则ch为NULL */
int length; /* 串长度 */
}HString;
/* ------------------------------------------------------------------------------------------*/
#define MaxKeyNum 25 /* 索引表的最大容量(关键词的最大数) */
#define MaxLineLen 51 /* 书目串(书名+书号)buf的最大长度 */
#define MaxWordNum 10 /* 词表(一本书的关键词)的最大容量 */
#define MaxNoIdx 10 /* 常用词(仅指大写)的最大数 */
#define MaxBookNum 10 /* 假设只对10本书建索引表 */
typedef struct
{
char *item[MaxWordNum]; /* 词表(字符串)指针数组 */
int last; /* 词的数量 */
}WordListType; /* 词表类型(顺序表) */
typedef struct
{
HString key; /* 关键词(堆分配类型) */
LinkList bnolist; /* 存放书号索引的链表() */
}IdxTermType; /* 索引项类型 */
typedef struct
{
IdxTermType item[MaxKeyNum + 1];
int last; /* 关键词的个数 */
}IdxListType; /* 索引表类型(有序表) */
typedef struct
{
char *item[MaxNoIdx]; /* 常用词表指针数组 */
int last; /* 常用词的数量 */
}NoIdxType; /* 常用词表类型(有序表) */
/* 全局变量 */
char buf[MaxLineLen + 1]; /* 当前书目串(包括'\0') */
WordListType wdlist; /* 暂存一本书的词表 */
NoIdxType noidx; /* 常用词表 */
/* --------------------------- 需要用到的具有实用意义的线性链表的基本操作 --------------------------*/
Status MakeNode(Link *p, ElemType e)
{ /* 分配由p指向的值为e的结点,并返回OK;若分配失败。则返回ERROR */
*p = (Link)malloc(sizeof(LNode));
if (!*p)
return ERROR;
(*p)->data = e;
return OK;
}
Status InitList(LinkList *L)
{ /* 构造一个空的线性链表 */
Link p;
p = (Link)malloc(sizeof(LNode)); /* 生成头结点 */
if (p)
{
p->next = NULL;
(*L).head = (*L).tail = p;
(*L).len = 0;
return OK;
}
else
return ERROR;
}
Status Append(LinkList *L, Link s)
{ /* 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的 */
/* 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新 */
/* 的尾结点 */
int i = 1;
(*L).tail->next = s;
while (s->next)
{
s = s->next;
i++;
}
(*L).tail = s;
(*L).len += i;
return OK;
}
/* --------------------------- 需要用到的串采用堆分配存储的基本操作 --------------------------*/
Status StrAssign(HString *T, char *chars)
{ /* 生成一个其值等于串常量chars的串T */
int i, j;
if ((*T).ch)
free((*T).ch); /* 释放T原有空间 */
i = strlen(chars); /* 求chars的长度i */
if (!i)
{ /* chars的长度为0 */
(*T).ch = NULL;
(*T).length = 0;
}
else
{ /* chars的长度不为0 */
(*T).ch = (char*)malloc(i * sizeof(char)); /* 分配串空间 */
if (!(*T).ch) /* 分配串空间失败 */
exit(OVERFLOW);
for (j = 0; j < i; j++) /* 拷贝串 */
(*T).ch[j] = chars[j];
(*T).length = i;
}
return OK;
}
Status StrCopy(HString *T, HString S)
{ /* 初始条件:串S存在。操作结果: 由串S复制得串T */
int i;
if ((*T).ch)
free((*T).ch); /* 释放T原有空间 */
(*T).ch = (char*)malloc(S.length * sizeof(char)); /* 分配串空间 */
if (!(*T).ch) /* 分配串空间失败 */
exit(OVERFLOW);
for (i = 0; i < S.length; i++) /* 拷贝串 */
(*T).ch[i] = S.ch[i];
(*T).length = S.length;
return OK;
}
int StrCompare(HString S, HString T)
{ /* 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */
int i;
for (i = 0; i < S.length&&i < T.length; ++i)
if (S.ch[i] != T.ch[i])
return S.ch[i] - T.ch[i];
return S.length - T.length;
}
void InitString(HString *T)
{ /* 初始化(产生空串)字符串T。另加 */
(*T).length = 0;
(*T).ch = NULL;
}
/* ------------------------------------------------------------------------------------------*/
void InitIdxList(IdxListType *idxlist)
{ /* 初始化操作,置索引表idxlist为空表,且在idxliat.item[0]设一空串 */
(*idxlist).last = 0;
InitString(&(*idxlist).item[0].key);
InitList(&(*idxlist).item[0].bnolist);
}
void ExtractKeyWord(int *BookNo)
{ /* 从buf中提取书名关键词到词表wdlist,书号存入BookNo */
int i, l, f = 1; /* f是字符串结束标志 0: 结束 1: 未结束 */
char *s1, *s2;
if (buf[0]<'0' || buf[0]>'9') /* buf的首字母不是数字 */
exit(OVERFLOW);
for (i = 1; i <= wdlist.last; i++) /* 释放上一个书目在词表wdlist的存储空间 */
{
free(wdlist.item[i]);
wdlist.item[i] = NULL;
}
wdlist.last = 0;
*BookNo = (buf[0] - '0') * 100 + (buf[1] - '0') * 10 + (buf[2] - '0'); /* 前三位为书号 */
s2 = &buf[2]; /* s1指向书号的尾字符 */
do
{ /* 提取书名关键词到词表wdlist */
s1 = s2 + 1; /* s1向后移动一个单词 */
s2 = strchr(s1, ' '); /* s2指向s1的第一个空格,如没有,返回NULL */
if (!s2) /* 到串尾 */
{
s2 = strchr(s1, '\12'); /* s2指向buf的最后一个字符(回车符) */
f = 0;
}
l = s2 - s1; /* 单词长度 */
if (s1[0] >= 'A'&&s1[0] <= 'Z') /* 单词首字母为大写 */
{ /* 写入词表 */
wdlist.item[wdlist.last] = (char *)malloc((l + 1) * sizeof(char));
/* 生成串空间(包括'\0') */
for (i = 0; i < l; i++)
wdlist.item[wdlist.last][i] = s1[i]; /* 写入词表 */
wdlist.item[wdlist.last][l] = 0;
for (i = 0; i < noidx.last; i++) /* 查找是否为常用词 */
if (!strcmp(wdlist.item[wdlist.last], noidx.item[i]))
break;
if (i != noidx.last) /* 是常用词 */
{
free(wdlist.item[wdlist.last]); /* 从词表中删除该词 */
wdlist.item[wdlist.last] = NULL;
}
else
wdlist.last++; /* 词表长度+1 */
}
} while (f);
}
void GetWord(int i, HString *wd)
{ /* 用wd返回词表wdlist中第i个关键词 */
StrAssign(wd, wdlist.item[i]); /* 生成关键字字符串 */
}
int Locate(IdxListType *idxlist, HString wd, Status *b)
{ /* 在索引表idxlist中查询是否存在与wd相等的关键词。若存在,则返回其 */
/* 在索引表中的位置,且b取值TRUE;否则返回插入位置,且b取值FALSE */
int i, m;
for (i = (*idxlist).last; (m = StrCompare((*idxlist).item[i].key, wd)) > 0; --i);
if (m == 0) /* 找到 */
{
*b = TRUE;
return i;
}
else
{
*b = FALSE;
return i + 1;
}
}
void InsertNewKey(IdxListType *idxlist, int i, HString wd)
{ /* 在索引表idxlist的第i项上插入新关键词wd,并初始化书号索引的链表为空表 */
int j;
InitList(&(*idxlist).item[(*idxlist).last + 1].bnolist);
for (j = (*idxlist).last; j >= i; --j) /* 后移索引项 */
(*idxlist).item[j + 1] = (*idxlist).item[j];
InitString(&(*idxlist).item[i].key);
StrCopy(&(*idxlist).item[i].key, wd); /* 串拷贝插入新的索引项 */
InitList(&(*idxlist).item[i].bnolist); /* 初始化书号索引表为空表 */
(*idxlist).last++;
}
void InsertBook(IdxListType *idxlist, int i, int bno)
{ /* 在索引表idxlist的第i项中插入书号为bno的索引 */
Link p;
if (!MakeNode(&p, bno)) /* 分配失败 */
exit(OVERFLOW);
p->next = NULL;
Append(&(*idxlist).item[i].bnolist, p); /* 插入新的书号索引 */
}
void InsIdxList(IdxListType *idxlist, int bno)
{ /* 将书号为bno的关键词插入索引表 */
int i, j;
Status b;
HString wd;
InitString(&wd);
for (i = 0; i < wdlist.last; i++)
{
GetWord(i, &wd);
j = Locate(idxlist, wd, &b);
if (!b)
InsertNewKey(idxlist, j, wd); /* 插入新的索引项 */
InsertBook(idxlist, j, bno); /* 插入书号索引 */
}
}
void PutText(FILE *f, IdxListType idxlist)
{ /* 将生成的索引表idxlist输出到文件f */
int i, j;
Link p;
fprintf(f, "%d\n", idxlist.last);
for (i = 1; i <= idxlist.last; i++)
{
for (j = 0; j < idxlist.item[i].key.length; j++)
fprintf(f, "%c", idxlist.item[i].key.ch[j]);
fprintf(f, "\n%d\n", idxlist.item[i].bnolist.len);
p = idxlist.item[i].bnolist.head;
for (j = 1; j <= idxlist.item[i].bnolist.len; j++)
{
p = p->next;
fprintf(f, "%d ", p->data);
}
fprintf(f, "\n");
}
}
typedef struct
{
char bookname[MaxLineLen]; /* 书目串 */
int bookno; /* 书号 */
}BookTermType; /* 书目项类型 */
typedef struct BookListType /* 书目表类型(有序表) */
{
BookTermType item[MaxBookNum];
int last; /* 书目的数量 */
}BookListType; /* 书目表类型(有序表) */
void main()
{
FILE *f; /* 任何时间最多打开一个文件 */
IdxListType idxlist; /* 索引表 */
int BookNo; /* 书号变量 */
int k, l;
f = fopen("NoIdx.txt", "r"); /* 打开常用词文件 */
if (!f)
exit(OVERFLOW);
fscanf(f, "%d", &noidx.last); /* 常用词个数 */
for (k = 0; k < noidx.last; k++) /* 把常用词文件的内容拷到noidx中 */
{
fscanf(f, "%s", buf);
l = strlen(buf);
noidx.item[k] = (char*)malloc(l * sizeof(char));
strcpy(noidx.item[k], buf);
}
fclose(f);
f = fopen("BookInfo.txt", "r"); /* 打开书目文件 */
if (!f)
exit(FALSE);
InitIdxList(&idxlist); /* 初始化索引表idxlist为空 */
wdlist.last = 0; /* 词表长度初值为0 */
while (!feof(f))
{
fgets(buf, MaxLineLen, f);
l = strlen(buf);
if (l <= 1)
break;
ExtractKeyWord(&BookNo); /* 从buf中提取关键词到词表,书号存入BookNo */
InsIdxList(&idxlist, BookNo);
}
fclose(f);
f = fopen("BookIdx.txt", "w");
if (!f)
exit(INFEASIBLE);
PutText(f, idxlist); /* 将生成的索引表idxlist输出到文件f */
fclose(f);
BookListType booklist; /* 书目表 */
char buf[MaxLineLen + 1]; /* 当前书目串(包括'\0') */
HString ch; /* 索引字符串 */
int i;
Link p;
InitString(&ch); /* 初始化HString类型的变量 */
f = fopen("BookIdx.txt", "r"); /* 打开书名关键词索引表文件 */
if (!f)
exit(OVERFLOW);
fscanf(f, "%d", &idxlist.last); /* 书名关键词个数 */
for (k = 0; k < idxlist.last; k++) /* 把关键词文件的内容拷到idxlist中 */
{
fscanf(f, "%s", buf);
i = 0;
while (buf[i])
buf[i++] = tolower(buf[i]); /* 字母转为小写 */
InitString(&idxlist.item[k].key);
StrAssign(&idxlist.item[k].key, buf);
InitList(&idxlist.item[k].bnolist); /* 初始化书号链表 */
fscanf(f, "%d", &i);
for (l = 0; l < i; l++)
{
fscanf(f, "%d", &BookNo);
if (!MakeNode(&p, BookNo)) /* 分配失败 bo2-6.c */
exit(OVERFLOW);
p->next = NULL;
Append(&idxlist.item[k].bnolist, p); /* 插入新的书号索引 */
}
}
fclose(f);
f = fopen("BookInfo.txt", "r"); /* 打开书目文件 */
if (!f)
exit(FALSE);
i = 0;
while (!feof(f)) /* 把书目文件的内容拷到booklist中 */
{
fgets(buf, MaxLineLen, f);
booklist.item[i].bookno = (buf[0] - '0') * 100 + (buf[1] - '0') * 10 + (buf[2] - '0'); /* 前三位为书号 */
strcpy(booklist.item[i].bookname, buf);
i++;
}
booklist.last = i;
printf("请输入书目的关键词(一个)");
scanf("%s", buf);
i = 0;
while (buf[i])
buf[i++] = tolower(buf[i]); /* 字母转为小写 */
StrAssign(&ch, buf);
i = 0;
do
{
k = StrCompare(ch, idxlist.item[i].key);
i++;
} while (k&&i <= idxlist.last);
if (!k) /* 索引表中有此关键词 */
{
p = idxlist.item[i - 1].bnolist.head->next;
while (p)
{
l = 0;
while (l < booklist.last&&p->data != booklist.item[l].bookno)
l++;
if (l < booklist.last)
printf("%s", booklist.item[l].bookname);
p = p->next;
}
}
else
printf("没找到\n");
}