首页 > 技术文章 > 数据结构-串操作应用之词索引表

ABook 2016-07-22 20:21 原文

为书库创建查询索引表

建立词索引表基本步骤:

  1、从书目文件中读入一个书目单。

  2、从书目单中提取所有关键字插入词表。

  3、对词表中的每一个关键字在索引表中进行查找并作相应的插入操作。

详细操作:

  1、为识别从书名串中分离出来的单词是否是关键字,需要一张常用词表。顺序扫描书目单,首先分离单词,然后查找常用词表,若不和表中任一词相等,则为关键字,插入临时存放关键字的词表中。

  2、在索引表中查询关键字时可能出现两种情况:其中一种是索引表上已经有此关键词的索引项,只要在该项中插入书号索引即可;其二是需要在索引表中插入此关键词的索引项,插入应按字典有序原则插入。

  3、首先定义存储的数据结构:词表为线性表,只存放一本书的书名中若干个关键字,其数量有限,采用顺序存储结构即可,其中每个词是一个字符串。索引表为有序表,虽是动态生成,在生成过程中需频繁进行插入操作,但考虑索引表主要为查找用,为了提高查找效率,采用顺序存储结构;表中每隔索引项包含两个内容:其一是关键词,因索引表为常驻内存,则考虑节省存储,采用堆分配存储表示的串类型;其二是书号索引,由于书号索引是在索引表生成过程中逐个插入,且不同关键词的书号索引个数不等,甚至可能相差很多,则宜采用链表结构的线性表。

代码实现部分:

ConcordanceList.cpp

  1 #include "ChainedList.h"
  2 #include "HeapString.h"
  3 
  4 #include <conio.h>
  5 
  6 #define  MaxBookNum      1000    // 假设只对1000本书建索引表
  7 #define  MaxKeyNum       2500    // 索引表的最大容量
  8 #define  MaxLineLen       500    // 书目串的最大长度
  9 #define  MaxWordNum        10    // 词表的最大容量
 10 #define  MaxWordLength     30    // 单词的最大长度
 11 
 12 typedef int Boolean;
 13 typedef int Status;
 14 
 15 typedef struct {
 16     char    item[MaxWordNum][MaxWordLength];  // 字符串的数组
 17     int     last;        // 词表的长度
 18 } WordListType;          // 词表类型(顺序表)
 19 
 20 typedef struct {
 21     HString   key;       // 关键词
 22     LinkList bnolist;   // 存放书号索引的链表
 23 } IdxTermType;           // 索引项类型
 24 
 25 typedef struct {
 26     IdxTermType  item[MaxKeyNum+1];
 27     int          last;
 28 } IdxListType;           // 索引表类型(有序表)
 29 
 30 //------ 基本操作 ------
 31 void InitIdxList(IdxListType &idxlist);
 32    // 初始化操作,置索引表idxlist为空表,即idxlist.last=0,
 33    // 且在idxlist.item[0]设一空串
 34 void GetLine(FILE *f);
 35    // 从文件f读入一个书目信息到书目串缓冲区buf
 36 Status ExtractKeyWord(char *Buffer, WordListType &w, int &bno);
 37    // 从buf中提取书名关键词到词表wdlist,书号存入bno
 38 Status InsertIdxList(IdxListType &idxlist, ElemType bno);  
 39    // 将书号为bno的书名关键词按词典顺序插入索引表idxlist
 40 Status PutText(FILE *g, IdxListType idxlist);           
 41    // 将生成的索引表idxlist输出到文件g
 42 void PrintFile(FILE *FileName);
 43 
 44 Status InsertIdxList(IdxListType &idxlist, int bno);
 45    // 索引表插入算法
 46 void GetWord(int i, HString &wd);                
 47    // 用wd返回词表wdlist中第i个关键词。
 48 int Locate(IdxListType &idxlist, HString wd, Boolean &b);
 49    // 在索引表idxlist中查询是否存在与wd相等的关键词。
 50    // 若存在,则返回其在索引表中的位置,
 51    // 且b取值TRUE;否则返回插入位置,且b取值FALSE
 52 void InsertNewKey(IdxListType &idxlist, int i, HString wd);
 53    // 在索引表idxlist的第i项上插入新关键词wd,
 54    // 并初始化书号索引的链表为空表
 55 Status InsertBook(IdxListType &idxlist, int i, int bno);
 56    // 在索引表idxlist的第i项中插入书号为bno的索引
 57 
 58 //------ 主要变量 ------
 59 char          buf[MaxLineLen];   // 书目串缓冲区
 60 WordListType  wdlist;    // 词表
 61 IdxListType   idxlist;   // 索引表
 62 
 63 //------ 主函数 ------
 64 int main(int argc, char* argv[]) { 
 65   FILE *f,*g;
 66   int BookNo;
 67   if ((f = fopen("BookInfo.txt", "r"))==NULL) {
 68     printf("ERROR in open BookInfo.txt!\n");
 69     exit(1);
 70   }
 71   if ((g = fopen ("BookIdx.txt", "w"))==NULL) {
 72     printf("ERROR in open BookIdx.txt!\n");
 73     exit(1);
 74   }
 75   printf("书目文件:\n");
 76   PrintFile(f);
 77   InitIdxList(idxlist);         // 初始化索引表idxlist为空表
 78   while (!feof (f)) {
 79     GetLine (f);                // 从文件f读入一个书目信息到buf
 80     ExtractKeyWord(buf,wdlist,BookNo);  
 81         // 从buf提取关键词到词表,书号存入BookNo
 82     InsertIdxList(idxlist, BookNo);  // 书号为BookNo的关键词插入索引表
 83   }
 84   PutText(g, idxlist);          // 将生成的索引表idxlist输出到文件g
 85   fclose(f);
 86   fclose(g);
 87   printf("对书目文件进行处理后的索引文件:\n");
 88   if ((g = fopen ("Algo0409BookIdx.txt", "r"))==NULL) {
 89     printf("ERROR in open BookIdx.txt!\n");
 90     exit(1);
 91   }
 92   PrintFile(g);
 93   fclose(g);
 94   printf("按任意键,结束 ......\n");
 95   getch();
 96   return 0;
 97 } // main
 98 
 99 Status InsertIdxList(IdxListType &idxlist,  int bno) { 
100   int i,j;
101   HString wd;
102   Boolean b;
103   for (i=0;  i<wdlist.last;  i++) {
104     GetWord(i, wd);   
105     j = Locate(idxlist, wd, b);
106     if (!b)
107       InsertNewKey(idxlist, j, wd);  //  插入新的索引项
108     InsertBook(idxlist, j, bno);     //  插入书号索引
109   }
110   return OK;
111 } // InsertIdxList
112 
113 void GetWord(int i,  HString &wd) {
114   char *p;
115   p = *(wdlist.item +i);  // 取词表中第i个字符串
116   StrAssign(wd, p);       // 生成关键字字符串
117 } // GetWord
118 
119 int Locate(IdxListType &idxlist, HString wd, Boolean &b) {
120   int i,m;
121   for (i = idxlist.last-1; 
122        ((m = StrCompare(idxlist.item[i].key, wd)) > 0);  --i);
123   if (m==0) { // 找到
124     b = TRUE;
125     return i;  
126   } else {  // 没找到
127     b = FALSE;
128     return i+1;
129   }         
130 } // Locate
131 
132 void InsertNewKey(IdxListType &idxlist, int i, HString wd) {
133   int j;
134   for (j=idxlist.last-1;  j>=i;  --j)  // 后移索引项
135     idxlist.item[j+1] = idxlist.item[j];
136   // 插入新的索引项
137   StrCopy(idxlist.item[i].key, wd);    // 串赋值
138   InitList(idxlist.item[i].bnolist);   // 初始化书号索引表为空表
139   ++idxlist.last;
140 } // InsertNewKey
141 
142 Status InsertBook(IdxListType &idxlist, int i, int bno) {
143   Link p;
144   if (!MakeNode (p, bno)) 
145     return OVERFLOW;                   // 分配失败
146   Append(idxlist.item[i].bnolist, p);  // 插入新的书号索引
147   return OK;
148 } // InsertBook
149 
150 //------ 基本操作 -------
151 void InitIdxList(IdxListType &idxlist) {
152   int i;
153   idxlist.last= 0;
154   for(i=0; i<MaxKeyNum+1; i++)
155     InitList(idxlist.item[i].bnolist);
156 }
157 
158 Status ExtractKeyWord(char* Buffer,WordListType &w,int &Num) {
159   int i=0, j=0, k=0;
160   bool Ignore;
161   char TempChar[30];
162   char IgnoreChar[7][10] = { "to","of","the","and","not","or","if" };
163   w.last=0;
164   while(*(Buffer+i)!= ' ') { TempChar[i]=*(Buffer+i);  i++; }
165   i++;
166   TempChar[i]= '\0';
167   Num=atoi(TempChar);
168   while(*(Buffer+i)!='\n' && *(Buffer+i)!='\0') { 
169     // 每个字符串末尾都有作为结束符'\n'
170     if(*(Buffer+i)!=' ') { // 若非空字符,则把当前字符加入新的字符串中
171       if(*(Buffer+i)>='A' && *(Buffer+i)<='Z')  // 大写字母转换为小写
172         *(Buffer+i)-='A'-'a';
173       w.item[j][k]=*(Buffer+i);
174       k++;  i++;
175     } else {               // 如果是空字符,这是则开始另一个字符串
176       Ignore=false;
177       w.item[j][k++]='\0';
178       for (int m=0; m<7; m++)
179         if(strcmp(w.item[j],IgnoreChar[m])==0) 
180           { Ignore=true;  break; }
181       if (!Ignore) { j++;  k=0;  i++;  w.last++; }
182       else { k=0;  i++; }
183     }
184   }
185   w.item[j][k++]='\0';     // 把最后一个字符串收尾
186   Ignore=false;
187   for (int m=0; m<7; m++)
188     if (strcmp(w.item[j],IgnoreChar[m])==0) 
189       { Ignore=true;  break; }
190   if (!Ignore) w.last++;   // 并把最大数加1
191   return OK;
192 }
193 
194 void GetLine(FILE *f) {
195   fgets(buf, MaxLineLen, f);  // buf是全局数组变量
196 }
197 
198 Status PutText(FILE *IdxFile, IdxListType MyIdx) { 
199   int i,j,k;
200   Link p;
201   for(i=0; i<MyIdx.last; i++) {
202     for(j=0; j<MyIdx.item[i].key.length; j++)
203       putc(*(MyIdx.item[i].key.ch+j ),IdxFile);
204     putc('\t',IdxFile);
205     if (MyIdx.item[i].key.length < 8) putc('\t',IdxFile);
206     p = MyIdx.item[i].bnolist.head;
207     for (k=0; k<MyIdx.item[i].bnolist.len; k++) {
208       p = p->next;
209       fprintf(IdxFile,"%03d",p->data);
210       putc(' ', IdxFile);
211     }
212     putc('\n',IdxFile);
213   }
214   return OK;
215 }
216     
217 void PrintFile(FILE *FileName) {  // 辅助函数
218   char ch;
219   rewind(FileName);
220   ch=getc(FileName);
221   while (ch!=EOF) {
222     putchar(ch);
223     ch=getc(FileName);
224   }
225   printf("\n");
226   rewind(FileName);
227 }

HeapString.h

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 
 5 typedef int Status;
 6 #define OK 1
 7 #define ERROR 0
 8 #define OVERFLOW -2
 9 
10 typedef struct{
11     char *ch;    //若是非空串,则按串长度分配存储区域,否则ch为NULL
12     int length;    //串的长度
13 }HString;
14 
15 /*生成一个其值等于等于串常量chars的串T*/
16 Status StrAssign(HString &T, char *chars){
17     if(T.ch)
18         free(T.ch);    //若串存储空间不为NULl 释放原有空间
19     int i = strlen(chars);    //获取chars长度
20     if(!i){
21         T.ch = NULL;    //串常量chars长度为0时串为空串长度0存储区间指向NULL
22         T.length = 0;
23     }
24     else{
25         T.ch = (char *)malloc(i * sizeof(char));    //申请空间
26         if(!T.ch)
27             exit(OVERFLOW);
28         for(int j = 0; j < i; j++)
29             T.ch[j] = chars[j];        //写入chars串
30         T.length = i;
31     }
32     return OK;
33 }
34 
35 /*由串S复制得到T*/
36 Status StrCopy(HString &T, HString S){
37     if(T.ch)
38         free(T.ch);
39     T.ch = (char*)malloc(S.length * sizeof(char));
40     if(!T.ch)
41         exit(OVERFLOW);
42     for(int j = 0; j < S.length; j++)
43         T.ch[j] = S.ch[j];    
44     T.length = S.length;
45     return OK;
46 }
47 /*若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0*/
48 int StrCompare(HString T, HString S){
49     for(int i = 0; i < S.length && i < T.length; i++)
50         if(S.ch[i] != T.ch[i])
51             return S.ch[i] - T.ch[i];
52     return S.length - T.length;
53 }

ChainedList.h

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define OK 1
 5 #define ERROR 0
 6 #define OVERFLOW -2
 7 #define TRUE 1
 8 #define FALSE 0
 9 
10 typedef int Status;
11 typedef int ElemType;
12 
13 typedef struct LNode{
14     ElemType data;
15     struct LNode *next;
16 }*Link, *Position;
17 typedef struct{
18     Link head, tail;
19     int len;
20 }LinkList;
21 
22 Status InitList(LinkList &L){
23     L.head = (Link)malloc(sizeof(LNode));
24     if(!L.head)
25         exit(OVERFLOW);
26     L.tail = L.head;
27     L.len = 0;
28     L.head->next = NULL;
29     return 0;
30 }
31 
32 Status MakeNode(Link &p,ElemType e){
33     p = (Link)malloc(sizeof(LNode));
34     if(!p)
35         exit(OVERFLOW);
36     p->data = e;
37     p->next = NULL;
38     return OK;
39 }
40 
41 Status Append(LinkList &L, Link S){
42     Link p;
43     L.tail->next = S;
44     p = S;
45     ++L.len;
46     while(p->next){
47         p = p->next;
48         ++L.len;
49     }
50     L.tail = p;
51     return OK;
52 }

 

推荐阅读