建立词索引表(第四章 P86 算法4.9~4.14)

建立词索引表

 

程序首先将存于 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");
}

 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值