歌词VSM实现!!!

Posted 天下岂有长生不灭者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了歌词VSM实现!!!相关的知识,希望对你有一定的参考价值。

主体VSM_SetUP.cpp;

 1 /*[ar:歌词作者]
 2 [ti:歌词(歌曲)的标题]
 3 */
 4 //编写程序实现lrc(歌词) 文件的检索,检索模型要求采用向量空间模型。请将源程序和文档压缩后,一并上传。
 5 #include<iostream>
 6 
 7 #include"Document_Index.h"
 8 
 9 using namespace std;
10 void main() {
11     cout << "*****本程序实现一个向量空间模型,对(D:\\暂时的)文件夹下的lrc文件进行遍历建立一个对应于歌曲名,作曲者,歌词主体的检索系统,请根据需要进行查询*****" << endl << endl;
12     cout << "*****检索出的文档编号对应的文档名字请在(检索结果.txt)内查找*****" << endl;
13     string query;
14     int select,result;
15     int isornot = 2;
16     Doc_Analysis doc_analysis;
17     doc_analysis.SETUP_Index();
18     ReQuery getResult(&doc_analysis);
19     
20     while (isornot>=1) {
21         cout << "输入查询词项:";
22         if (isornot != 2) {
23             getline(cin, query);
24         }
25         getline(cin, query);
26         
27         cout << "请选择查询模式(1为查歌曲,2为查歌手,3为查歌词主体):";
28         cin >> select;
29         cout << "请选择返回结果的数量:";
30         cin >> result;
31         getResult.Query(query, result, select);
32         cout << "is or not(1表示继续查询,0表示退出查询) ?    " ;
33         cin >> isornot;
34     }
35 }

 

类的保存文件内:Document_Index.cpp和Document_Index.h

  1 #pragma once
  2 #include<iostream>
  3 #include<fstream>
  4 #include<vector>
  5 #include<math.h>
  6 #include<string>
  7 #include<iomanip>
  8 #include <stdio.h>
  9 #include<io.h>
 10 #include <windows.h>
 11 using namespace std;
 12 
 13 const static int Maxsize = 10000;
 14 const static int maxsize = 100;//a line and a smalllist
 15 
 16 //得分和相应的文档编号
 17 struct ScoreandDoc {
 18     float score;
 19     int text_number;
 20 };
 21 
 22 //包含词的所在的文档编号,词项在此文档出现的频率tf
 23 struct Word_Doc {
 24     int text_number;
 25     int text_fre;
 26 };
 27 
 28 //设计保存词项倒排记录头部的一个结构
 29 struct Index_List {//存储每个词的头项,包含单词和指向倒排记录的指针,存储df,df是包含词项的文档的数目,同时也是倒排记录的长度。next指向下一个词项
 30     float  df;
 31     string word;
 32     vector<Word_Doc> head_docID;// = nullptr;
 33     Index_List * next = nullptr;
 34 };
 35 
 36 //文档检索类,VSM的主体
 37 class Doc_Analysis {
 38 
 39     string BTEMP[Maxsize];
 40     string TEMP[maxsize];
 41     int arsize;//
 42     int tisize;
 43     Index_List * arofMusic_idList;  //歌曲作者索引的链表头
 44     Index_List * tiofMusic_idList;  //歌曲名字索引的链表头
 45     Index_List * idList;              //主体歌词倒排索引的链表头
 46     int size; //文档的词项的数目,即文档长度
 47     int allsize;//总的词数
 48      int N;                     //歌词主体文档集的大小,共有N篇文档
 49      int sizeofmusicname;          //歌词名字和歌词作者的大小
 50     string Inp_Temp_Lyrics[Maxsize];    //存放歌词主体
 51     string ti_Temp[maxsize/5];//歌曲名称和歌曲作者的暂时存放之地
 52     string ar_Temp[maxsize / 5];//歌曲名称和歌曲作者的暂时存放之地
 53 public:
 54     Doc_Analysis() {
 55         size = 0;
 56         allsize = 0;
 57         arsize = 0;
 58         tisize = 0;
 59         N = 0;
 60         idList = nullptr;
 61         arofMusic_idList = nullptr;
 62         tiofMusic_idList = nullptr;
 63     };
 64     ~Doc_Analysis() {
 65 
 66     };
 67 
 68 
 69     //把从文档中检索的词插入Inp_Temp_Words[Maxsize],如果不在就直接插入,如果已经存在则加一个
 70 
 71     //打开文件输入歌词,对词项进行分析,把歌曲的作者和歌曲名取出,存入对应的倒排索引,但是这个索引很小,所以可以直接构建倒排索引表。参数分别为:文件名,文档的编号。先对文档内歌词的作者和调用分离出的词项最终存储在Inp_Temp_Words[Maxsize],返回文档的词数
 72     int Doc_input(string filename, int number);
 73 
 74     //被int Doc_input(string filename, int number);调用,将分离出的词项存储在temp_Words[]中,size表示其大小,j表示其从哪一个数开始放入
 75     int Temp_Insert(string temp_words[],char T[],int &size);
 76 
 77     //对此文档的词项的表进行归并排序(按字典序)
 78     void Doc_mergesort(string *inputWord, string* Temp, int left, int right);
 79 
 80     //将此次输入的文档分词排序后得到的词项表存入最终的倒排索引中
 81     Index_List* insert_IndexList(string *inputWord, int n,int NofDoc, Index_List * idList);
 82 
 83     //歌曲名,作者,歌词主体倒排索引总体构建
 84     void SETUP_Index();// {};
 85 
 86     //返回最终查询的文档集大小
 87     int SizeOfDocSet() {
 88         return N;
 89     }
 90 
 91     //返回最终生成的歌词主体倒排索引表
 92     Index_List* tiIndex_head() {
 93         return tiofMusic_idList;
 94     };
 95 
 96     //返回最终生成的歌ming倒排索引表
 97     Index_List* DocIndex_head() {
 98         return idList;
 99     };
100 
101     //返回最终生成的作者倒排索引表
102     Index_List* arIndex_head() {
103         return arofMusic_idList;
104     };
105 
106     //此函数实现寻找指定文件夹下的指定后缀文件,并且保存其完整的路径
107     void GetAllFormatFiles(string path, vector<string>& files, string format);
108 //
109 };
110 
111 //对输入的查询词项进行分析,返回输入结果
112 class ReQuery {
113     Doc_Analysis* LMA;//歌词倒排索引的链表头
114     float *Scores;//每个查询词项的初始得分
115     float *arLength;//每个文档的长度
116     float *tiLength;
117     float *Length;
118     int N;//文档集大小
119 public:
120     ReQuery(Doc_Analysis* TEMP) {//得到Doc_Analysis返回的文档集长度和链表头
121         N = TEMP->SizeOfDocSet();
122         Scores = new float[N];
123         Length = new float[N];
124         
125         LMA = TEMP;
126         for (int i = 0; i < N; i++) {
127             Scores[i] = 0;
128             Length[i] = 0;
129         }
130     };
131     ~ReQuery() {
132         delete[] Scores;
133         delete[] Length;
134         delete[] arLength;
135         delete[] tiLength;
136     };
137 
138     //查询所有词项,对所有倒排索引表遍历一次,将每个向量的长度计算出来,初始化得分数组
139     void initialLength(Index_List * idList, float *tempLength);
140 
141     //输入查询歌词词项,输出查询结果,返回排名前k的文档编号,select 为选择的查询模式,1为查歌名,2为查歌手,3为查歌词主体
142     bool Query(string query, int k,int select=1);
143 
144     //查询某一个词是否在其中,有则返回其df,无则返回0
145     int isInner(string elem, Index_List idList[],Index_List &nowTemp);
146 
147     //某个词项对于suoyou文档的得分
148     float ScoreofaDoc(Index_List *idList, Index_List* word, int iQ);
149 
150     //进行堆排序,将所有的得分进行排序
151     bool HeapSort(float Scores[], int n,int k);
152 
153 };
154 
155 //堆排序,建立最大堆
156 class Max_Heap {
157     ScoreandDoc *Heap;
158     int size;
159     int n;
160     void siftdown(int elem);
161 public:
162     Max_Heap(int num, int max, ScoreandDoc *temp) {
163         n = num;
164         size = max;
165         Heap = temp;
166         buildHeap();
167     };
168     void buildHeap() {
169         for (int i = n / 2 - 1; i >= 0; i--)
170             siftdown(i);
171     };
172     int heapsize()const {
173         return n;
174     }
175     bool isLeaf(int pos)const {
176         return (pos >= n / 2) && (pos < n);
177     }
178     int leftchild(int pos)const {
179         return 2 * pos + 1;
180     }
181     int rightchild(int pos)const {
182         return 2 * pos + 2;
183     }
184     ScoreandDoc removemax(float it);
185 
186 };

——————————————————————————————————————————————————————————————————————————————————

  1 #pragma once
  2 #include"Document_Index.h"
  3 #include<iostream>
  4 #include<fstream>
  5 #include<vector>
  6 #include<math.h>
  7 #include<string>
  8 #include<iomanip>
  9 #include <stdio.h>
 10 #include<io.h>
 11 #include <windows.h>
 12 using namespace std;
 13 
 14 ///////////类:Doc_Analysis///////////////////////
 15 
 16 //打开文件输入歌词,对词项进行分析,把歌曲的作者和歌曲名取出,存入对应的倒排索引,但是这个索引很小,所以可以直接构建倒排索引表。参数分别为:文件名,文档的编号。调用分离出的词项最终存储在Inp_Temp_Words[Maxsize],返回歌词文档的词数
 17 int Doc_Analysis::Doc_input(string filename, int number) {
 18     ifstream fin(filename);
 19     if (!fin.is_open()) {
 20         exit(0);
 21     }
 22     N++;
 23 //    cout << "此文件夹文档数目:" << N << endl;
 24     char c[maxsize] = { \0 };
 25     int ic = 0, i = 2;
 26     int numberofDoc = 0;
 27     string str;
 28     getline(fin, str);
 29 
 30     //分离出作者
 31     for (; str[i] != ]; i++) {
 32         if (str[i] == :&&str[i - 1] == r&&str[i - 2] == a) {
 33             for (; str[i] != ]; i++) {
 34                 if (((int)str[i] >= 65) && ((int)str[i] <= 91))
 35                     c[ic++] = (int)str[i] + 32;
 36                 else
 37                     c[ic++] = str[i];
 38             }
 39             i--;
 40         }
 41     }
 42     Temp_Insert(ar_Temp,c,arsize);
 43     
 44     Doc_mergesort(ar_Temp, TEMP, 0, arsize - 1);
 45     
 46     
 47     //分离出歌名
 48     getline(fin, str);
 49     i = 2;
 50     ic = 0;
 51     for (; str[i] != ]; i++) {
 52         if (str[i] == :&&str[i - 1] == i&&str[i - 2] == t) {
 53             for (; str[i] != ]; i++) {
 54                 if (((int)str[i] >= 65) && ((int)str[i] <= 91))
 55                     c[ic++] = (int)str[i] + 32;
 56                 else
 57                     c[ic++] = str[i];
 58             }
 59             i--;
 60         }
 61     }
 62 
 63     //cout << "歌名:" << c << endl;
 64     Temp_Insert(ti_Temp,c, tisize);
 65     
 66     //遍历整个geci文档主体,每次读取一行,然后进行分析
 67     getline(fin, str);
 68     
 69     do {
 70         //cout <<"收到: " <<str << endl;
 71         ic = 0;
 72         for (i = 0; str[i] != ]; i++);
 73         for (i++; str[i] != \r&&str[i] != \n&&str[i] != \0; i++) {
 74 
 75             //去掉引号后面的字符,但是如果是t的话就不去
 76             if ((int)str[i] == 39) {
 77                 while (str[i] !=  &&str[i] != \r&&str[i] != \n&&str[i] != \0) {
 78                     i++;
 79                     if (str[i] == t) {
 80                         i--;
 81                         break;
 82                     }
 83                 }
 84                 if (str[i] == \r || str[i] == \n || str[i] == \0)
 85                     break;
 86             }
 87 
 88             //除去大小写
 89             if (((int)str[i] >= 65) && ((int)str[i] <= 91))
 90                 c[ic++] = (int)str[i] + 32;
 91             else
 92                 c[ic++] = str[i];
 93         }
 94         c[ic] = \0;
 95         
 96         Temp_Insert(Inp_Temp_Lyrics, c, numberofDoc);
 97         getline(fin, str);
 98     } while (!fin.eof());
 99     fin.close();
100     allsize += numberofDoc;
101 
102     //cout << "本文档最终分离出词数:" << size << endl;
103     size = numberofDoc;
104     return numberofDoc;
105 };
106 
107 //被int Doc_input(string filename, int number);调用,将分离出的词项存储在temp_Words[]中,size表示其大小
108 int Doc_Analysis::Temp_Insert(string temp_words[], char T[],int &size) {
109     const char *d = "[] -;,:/?!.()\"";//以这些字符为分界符[] -;,:/?!.()\"
110     char *p = NULL;
111     char *next_p = NULL;
112     p = strtok_s(T, d, &next_p);
113     while (p)
114     {
115         //cout << p << endl;
116         temp_words[size++] = p;//put the char* into temp table
117         p = strtok_s(NULL, d, &next_p);
118     }
119     
120     return size;
121 };
122 
123 //对此文档的词项的表进行归并排序(按字典序)
124 void Doc_Analysis::Doc_mergesort(string *inputWord, string* Temp, int left, int right) {
125     int i, j, k, mid = (left + right) / 2;
126     if (left == right)
127         return;
128     Doc_mergesort(inputWord, Temp, left, mid);
129     Doc_mergesort(inputWord, Temp, mid + 1, right);
130     for (i = mid; i >= left; i--)
131         Temp[i] = inputWord[i];
132     for (j = 1; j <= right - mid; j++)
133         Temp[right - j + 1] = inputWord[j + mid];
134     for (i = left, j = right, k = left; k <= right; k++)
135         if (Temp[i]<= Temp[j])
136             inputWord[k] = Temp[i++];
137         else
138             inputWord[k] = Temp[j--];
139 };
140 
141 //将此次输入的文档分词排序后得到的词项表存入最终的倒排索引中,numberofDoc为此文档分离出的词的数目,(不是词项)NofDoc为文档的编号
142 Index_List* Doc_Analysis::insert_IndexList(string *inputWord, int numberofDoc,int NofDoc, Index_List * idListx) {
143     int i = 0, j = 0;
144     Index_List* pre_idList = idListx,*idList=idListx, *idListHead = idListx;    
145     //cout << "词数" << numberofDoc << endl;
146     if (i < numberofDoc) {
147         //cout << " 当前文档的词: " << inputWord[i] << endl;
148         while ((idList != nullptr)&&(i<numberofDoc)) {//将整个倒排索引在此遍历完全,在文档也未结束的情况下
149             //1.词项和目前监测的节点值一样,则直接在其后的此词项的后面加上本文档的相关信息即可
150             if (inputWord[i] == idList->word) {
151                 //cout << "此时词项" << inputWord[i] << "已存在索引表中" << endl;
152                 Word_Doc *temp = new Word_Doc;
153                 temp->text_number = NofDoc;//这个词项的文档编号,把所有相同的词项合并在一起
154                 temp->text_fre = 0;//肯定已经在这个文档出现了一次
155                 do {
156                     temp->text_fre++;
157                     i++;
158                     if (i == numberofDoc)
159                         break;
160                 } while (inputWord[i] == idList->word);//只有当文档检测的词项不一样时退出
161 
162                 idList->df++;//出现该词项的文档数增1,应该为df
163 
164                 idList->head_docID.push_back(*temp);
165                 
166                 /*cout << (idList->head_docID)[idList->head_docID.size() - 1].text_number << endl;*/
167                 
168                 pre_idList = idList;//前一个链表值
169 
170                 //print2(idList);//查看这个idList的具体值
171 
172                 idList = idList->next;//索引表下移
173             }
174             //2.当这个词项比当前索引的词项小时,说明词项肯定在倒排索引中排在当前词项的前面,则将其插入在其之前,注意区分第一个和中间的
175             else if (inputWord[i] < idList->word) {
176                 //cout << inputWord[i] << "比索引表的——" << idList->word << " 小" << endl;
177                 Index_List* newidList = new Index_List;
178                 vector<Word_Doc> forID ;//因为是单独建一个词项的索引,故建立存储倒排索引的容器
179                 Word_Doc *temp = new Word_Doc;
180                 temp->text_number = NofDoc;
181                 temp->text_fre = 0;//肯定已经出现过一次,把所有相同的词项合并在一起
182                 if (idList->word==pre_idList->word) {
183                     //cout << "这个词即将插入索引头。" << endl;
184                     idListHead = newidList;
185                 }
186                 else {
187                     pre_idList->next = newidList;
188                 }
189                 do {
190                     temp->text_fre++;
191                     i++;
192                     if (i == numberofDoc)
193                         break;
194                 } while (inputWord[i] == inputWord[i - 1]);//只有当文档检测的词项不一样时退出
195                 
196                 forID.push_back(*temp);
197 
198                 newidList->df = 1;
199                 newidList->next = idList;
200                 
201                 pre_idList = newidList;
202                 newidList->word = inputWord[i-1];
203                 newidList->head_docID = forID;
204 
205 
206             }
207             //3.当目前文档的词比索引的词项大时,倒排索引表向后走
208             else {
209                 //cout << inputWord[i] << "比索引表的——" << idList->word << " 大" << endl;
210 
211                 pre_idList = idList;
212                 //cout << idList->word << endl;
213                 idList = idList->next;
214             }
215         }
216         //idList==nullptr,,,if条件句成立意味着倒排索引表已经到达尾部,接下来的所有词项都大于索引表内任何词项,可以直接插入,注意区分第一个和中间的
217         while (i < numberofDoc) {
218             idList = new Index_List;
219             if (idListHead == nullptr) {//如果是
220                 pre_idList = idList;
221                 idListHead = idList;
222             }
223             else {
224                 pre_idList->next = idList;
225             }
226             
227             vector<Word_Doc> forID;//建立存储这个词项的倒排索引的容器
228             Word_Doc *temp = new Word_Doc;
229             temp->text_number = NofDoc;
230             temp->text_fre = 0;
231             do {
232                 temp->text_fre++;
233                 i++;
234                 if (i == numberofDoc)
235                     break;
236                 
237             } while (inputWord[i] == inputWord[i - 1]);//把所有相同的词项合并在一起,只有词项不一致时才退出
238             forID.push_back(*temp);
239 
240             idList->df = 1;
241             
242             pre_idList = idList;
243             idList->word = inputWord[i-1];
244             idList->head_docID = forID;
245 
246             //print2(idList); 
247             idList = idList->next;
248         }
249     }
250     //print1(idListHead);
251     return idListHead;
252 };
253 
254 //歌曲名,作者,歌词主体倒排索引总体构建
255 void Doc_Analysis::SETUP_Index(){
256     int i;
257     string tx_filePath = "\0", filePath = "D:\\暂时的", distAll = "检索结果.txt", format = ".lrc";
258     vector<string> files;
259 
260     GetAllFormatFiles(filePath, files, format);
261     distAll = filePath + "\\" + distAll;
262     ofstream ofn(distAll);
263     int tsize = files.size();
264     cout << "文件夹下的.lrc数目:" << tsize << endl;//查询出文件夹下文档的数目
265     for (i = 0; i < tsize; i++)//一次遍历,每检索一个文档将其存入相应的缓冲区,然后建立倒排索引
266     {
267         ofn <<"文档"<<i<<""<< files[i] << endl; // 写入文件  
268         Doc_input(files[i], i);
269         Doc_mergesort(ar_Temp, TEMP, 0, arsize-1);
270         Doc_mergesort(ti_Temp, TEMP, 0, tisize-1);
271         Doc_mergesort(Inp_Temp_Lyrics,BTEMP, 0, size-1);
272     
273         //插入倒排索引
274 
275         arofMusic_idList = insert_IndexList(ar_Temp, arsize, i, arofMusic_idList);
276         tiofMusic_idList = insert_IndexList(ti_Temp, tisize, i, tiofMusic_idList);
277         idList=insert_IndexList(Inp_Temp_Lyrics, size, i, idList);
278     
279 
280         arsize = 0;
281         tisize = 0;
282         size = 0;
283         
284         //cout << "索引链表内容如下:" << endl;
285         //cout << "作者:" << endl;
286         //print1(arofMusic_idList);
287         //cout << "歌名:" << endl;
288         //print1(tiofMusic_idList);
289         //cout << "主体:" << endl;
290         //print1(idList)
291         //insert_IndexList(ti_Temp, arsize, i, tiofMusic_idList);
292         //insert_IndexList(Inp_Temp_Lyrics, arsize, i, idList);
293     }
294     //至此,索引构建完毕
295     /*cout << "主体:" << endl;
296     print1(idList);*/
297     ofn <<endl<< "文件夹下的.lrc数目:" << tsize << endl;
298     cout << endl;
299     ofn << "检索出词数(非词项数):" << allsize << endl;
300     ofn.close();
301     cout << "一共检索出词数(非词项数):" << allsize << endl;
302     cout << "歌曲名索引构建完毕!!!" << endl;
303     cout << "作曲者索引构建完毕!!!" << endl;
304     cout << "歌词主体索引构建完毕!!!" << endl;
305     cout << endl;
306 };
307 
308 //此函数实现寻找指定文件夹下的指定后缀文件,并且保存其完整的路径
309 void Doc_Analysis::GetAllFormatFiles(string path, vector<string>& files, string format)
310 {
311     //文件句柄    
312     long   hFile = 0;
313     //文件信息    
314     struct _finddata_t fileinfo;
315     string p;
316     if ((hFile = _findfirst(p.assign(path).append("\\*" + format).c_str(), &fileinfo)) != -1)
317     {
318         do
319         {
320             if ((fileinfo.attrib &  _A_SUBDIR))
321             {
322                 if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
323                 {
324                     files.push_back(p.assign(path).append("\\").append(fileinfo.name));
325                     GetAllFormatFiles(p.assign(path).append("\\").append(fileinfo.name), files, format);
326                 }
327             }
328             else
329             {
330                 files.push_back(p.assign(path).append("\\").append(fileinfo.name));; //将文件路径保存,也可以只保存文件名:    p.assign(fileinfo.name)
331             }
332         } while (_findnext(hFile, &fileinfo) == 0);
333 
334         _findclose(hFile);
335     }
336 };
337 
338 
339 ////////////////////类:ReQuery////////////////////
340 
341 //查询所有词项,对倒排索引表遍历一次,初始化得分数组
342 
343 void ReQuery::initialLength(Index_List * idList, float *tempLength) {
344     float idf;//记录log N/df
345     int size;
346     int i;
347     
348     while (idList != nullptr) {
349         idf = log(N/idList->df) / log(10);
350         size = idList->head_docID.size();
351         i = 0;
352         for (; i < size; i++) {
353             tempLength[idList->head_docID[i].text_number] += (idf*(1 + log(idList->head_docID[i].text_fre) / log(10)))*(idf*(1 + log(idList->head_docID[i].text_fre) / log(10)));
354         }
355         idList = idList->next;
356     }
357     for (i = 0; i < N; i++)
358         tempLength[i] = sqrt(tempLength[i]);
359     /*for (int i = 0; i < LMA->SizeOfDocSet();i++)
360         cout << "文档" << i <<" 长度为 "<< tempLength[i] << endl;*/
361 }
362 
363 //输入查询词项,输出查询结果,返回排名前k的文档编号,select 为选择的查询模式,1为查歌名,2为查歌手,3为查歌词主体
364 bool ReQuery::Query(string query, int k, int select) {
365     Index_List QUERY[10];
366     char aa[50] = { \0 };
367     int ia = 0, i = 0, iQ = 0, j = 0;
368     
369     for (; i<query.length(); i++) {
370         while (query[i] !=  && i < query.length()) {
371             if (((int)query[i] >= 65) && ((int)query[i] <= 91))
372                 aa[ia++] = query[i++] + 32;
373             else
374                 aa[ia++] = query[i++];
375         }
376             
377         aa[ia] = \0;
378         for (; j < iQ; j++) {
379             if (QUERY[j].word == aa) {
380                 QUERY[j].df++;
381                 j = -1;
382                 break;
383             }
384         }
385         if (j != -1) {
386             QUERY[iQ++].word = aa;
387             QUERY[iQ-1].df = 1;
388         }
389         j = 0;
390         ia = 0;
391         //cout << f[ic1 - 1] << endl;
392     }
393 
394     //查歌名
395     if (select == 1) {
396         initialLength(LMA->tiIndex_head(), Length);
397         //计算查询de得分
398         ScoreofaDoc(LMA->tiIndex_head(), QUERY, iQ);
399     }
400     //查作者
401     if (select == 2) {
402         initialLength(LMA->arIndex_head(), Length);
403         //计算查询de得分
404         ScoreofaDoc(LMA->arIndex_head(), QUERY, iQ);
405     }
406     //查歌词主体
407     if (select == 3) {
408         initialLength(LMA->DocIndex_head(), Length);
409         //计算查询de得分
410         ScoreofaDoc(LMA->DocIndex_head(), QUERY, iQ);
411     }
412     /*for (int i = 0; i < N; i++) {
413         cout << Scores[i] << endl;
414     }*/
415     //对得分数组建堆,并且返回前K个
416     HeapSort(Scores, N, k);
417     return true;
418 };
419 
420 //词项对于suoyou文档的得分
421 float ReQuery::ScoreofaDoc(Index_List *idList, Index_List Tword[],int iQ) {
422     int size = 0;
423     int df;
424     float idf;
425     Word_Doc TEMPS;
426     Index_List nowTemp;
427     for (int i = 0; i < iQ;i++) {
428         
429         if ((df = isInner(Tword[i].word,idList,nowTemp)) != 0) {
430             idf = log(N/df) / log(10);
431             size =nowTemp.head_docID.size();
432             for (int j = 0; j < size; j++) {
433                 TEMPS = (nowTemp.head_docID)[j];
434                 Scores[TEMPS.text_number] += ((idf)*Tword[i].df)*(idf*(1 + log(nowTemp.head_docID[j].text_fre) / log(10)));
435             }
436         }
437     }
438     cout <<endl <<"各文档依次得分:" << endl;
439     for (int i = 0; i < N; i++) {
440         if(Scores[i]!=0)
441             Scores[i] = Scores[i]/ Length[i];
442         cout << Scores[i] <<" ";
443     }
444     return 0;
445 }
446 
447 //查询某一个词是否在其中,有则返回其df,无则返回0
448 int ReQuery::isInner(string elem, Index_List idList[], Index_List &nowTemp) {
449     int i = 0;
450     //cout << "查找单词" << elem << endl;
451     while (idList != nullptr) {
452         if (idList[i].word == elem) {
453             //cout << "单词" << elem << "在其中,文档编号"<<idList[i].head_docID[0].text_number<<endl;
454             nowTemp = idList[i];
455             return idList->df;
456         }
457         if (idList->word > elem)
458             return 0;
459         idList = idList->next;
460     };
461     return 0;
462 }
463 
464 //进行堆排序,将所有的得分进行排序,找出前k个,n为数组大小
465 bool ReQuery::HeapSort(float Scores[],int n,int k) {
466     float doc = -1;
467     int i = 0;
468     ScoreandDoc *TScores = new ScoreandDoc[n];
469     for (; i < n; i++) {
470         TScores[i].score = Scores[i];
471         TScores[i].text_number = i;
472     }
473 
474     Max_Heap H(n, n, TScores);
475     i = 0;
476     cout << endl << endl << "---------------------向您推荐如下文档--------------------------------" << endl;
477     for (; i < k; i++) {
478         ScoreandDoc temp= H.removemax(doc);
479         cout << "文档编号:" << temp.text_number << " 得分:" << temp.score << endl;
480     }
481 
482     cout << endl;
483     delete[]TScores;
484     return true;
485 
486 };
487 
488 //////////////////////////////lei Max_Heap///////////////////////////
489 //堆建立
490 
491 //建立整堆
492 void Max_Heap::siftdown(int pos) {
493     while (!isLeaf(pos)) {
494         int j = leftchild(pos);
495         int rc = rightchild(pos);
496         if ((rc < n) && (Heap[j].score < Heap[rc].score)) {
497             j = rc;
498         }
499         if (!(Heap[pos].score < Heap[j].score))
500             return;
501         ScoreandDoc xxx = Heap[pos];
502         Heap[pos] = Heap[j];
503         Heap[j] = xxx;
504         pos = j;
505     }
506 };
507 
508 
509 //每次找出移除最大的
510 ScoreandDoc Max_Heap::removemax(float it) {
511     //if (n == 0)
512     //    return ;
513     ScoreandDoc xxx = Heap[--n];
514     Heap[n] = Heap[0];
515     Heap[0] = xxx;
516     if (n != 0)
517         siftdown(0);
518     //it = Heap[n].score;
519     return Heap[n];
520 }

 

以上是关于歌词VSM实现!!!的主要内容,如果未能解决你的问题,请参考以下文章

Proteus VSM Studio建立代码工程与调试全过程

Proteus仿真基于VSM 串口printf调试输出示例

Go练习题—动态打印歌词

延迟渲染中的点光源双抛物面 VSM

酷狗音乐展示滚动歌词效果的控件实现

Android中通过Java代码实现ScrollView滚动视图-以歌词滚动为例