歌词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 }
时间: 2024-10-05 23:01:40

歌词VSM实现!!!的相关文章

原生js实现歌词本

/** * Created by Administrator on 2017/4/30. */// 1. 歌词在一个矩形区域内显示// 2. 当前歌词行高亮// 3. 在矩形显示区域中部固定位置显示当前歌词行// 4. 当前歌词行切换到下一行时,下一行歌词高亮,并逐步移动到当前歌词行位置// 5. 初始显示时歌词第一行顶住显示区域,当前歌词行未到达显示矩形区域的中部固定高亮位置时,不需要移动// 6. 歌词尾行到达显示区域后,不需要移动// 7. 用户可通过鼠标或者滚动条滚动歌词// 8. 用户

浅谈动感歌词-歌词显示篇

1引言 经过分析篇.生成篇和解析篇之后,相信大家对动感歌词都已经不再陌生了,现在最重要的就是,动感歌词怎样显示的问题,这里就不再介绍java swing上面怎样显示了,因为在生成篇,已经做了一些简单的介绍,这一篇着重说一下动感歌词在android上面怎样显示. 2显示 关于歌词的平滑滚动,之前一直都是用android Scroller来滚动,发现在歌词滑动快进方面,一直都实现不了,能力有限.幸好,发现了一个帖子,这个帖子真是帮了大忙,这里先贴一下,他的博客,我强烈推荐大家看一下他的博客,他说得比

浅谈动感歌词-歌词解析篇

1引言 要解析动感歌词文件,首先就要清楚动感歌词的文件内容,当然歌词的文件内容,我们已经在分析篇的文章里面介绍过了,这里将不再做详细的介绍,当我们可以把歌词成功解析出来后,再结合歌词生成篇,一个简单的歌词格式转换工具也就出来了. 2歌词解析 歌词解析,其实就是把文件里面的标签内容.歌词时间和歌词内容解析出来,当然,为了后期拓展其它的动感歌词格式,我们这里要好好设计一番. 2.1实体类 2.1.1歌词读取器 主要用来约束动感歌词读取器要实现的方法,可用于拓展实现其它的动感歌词格式. 2.1.2歌词

Java使用正则表达式解析LRC歌词文件

LRC歌词是一种应用广泛的歌词文件,对其进行解析时 标准格式: [分钟:秒.毫秒] 歌词 1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.FileInputStream; 4 import java.io.InputStreamReader; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.Li

Android开发本地及网络Mp3音乐播放器(十五)网络音乐及歌词下载功能实现

实现功能: 实现网络音乐歌词下载功能(下载音乐的同时,下载对应歌词) 下载好的歌词目前不在播放器内,可以通过文件浏览器查看. 后续将博文,将实现本地音乐歌词下载和已下载音乐扫描功能. 因为,没有自己的服务器,所以网络音乐所有相关功能(包含搜索音乐.下载音乐.下载歌词)均无法保证时效性,建议,尽快下载和练习:如果你下载时候,已经因为我采集的服务器更改规则,请给我留言,如果可以解决,我将在有空的时候献上新的源码. 截止到目前的源码下载: http://download.csdn.net/album/

Objective-C歌词解析

#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { FILE* fp1;//定义文件指针用于读文件 char* fp2;//用来判断是否歌词读完 char s[80];//暂存歌词 long int time2=0; long int time=0;//用来计算时间,精度为秒,不够完善,望高人指点 int a=1;//起判断作用 fp1=fopen("/Users/qingyun/De

我的项目7 js 实现歌词同步(额,小小的效果)

在项目中需要做一个播放器,还要实现歌词同步的效果,就跟现在搜狗音乐的歌词同步差不多,在网上查了一些关于这方面的,整理了一下,在这里,其实用这个方法可以吗? <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript" src="js/jqu

网页音乐播放器javascript实现,可以显示歌词

可以显示歌词,但是歌词和歌曲都要实现自己下载下来.只能播放一首歌,歌词还得是lrc格式的代码写的很罗嗦,急切希望帮改改CSS的代码?1.代码:<html >    <head>        <!--下面有很多style都是没用到的,但是我改不动了-->        <!--css觉得真是很麻烦-->        <style type="text/css">            audio            { 

手机影音第十七天,实现歌词同步

代码已托管到码云,有兴趣的小伙伴可以下载看看 https://git.oschina.net/joy_yuan/MobilePlayer 效果图: 有一个小的遗憾,就是该MP3文件和歌词文件要在同一路径下,才能读取到歌词,否则读取不到录音文件. 将录音文件发到这里,是.lrc格式的文件,其实TXT文件的也行:如果在手机上显示是乱码的话,就改一下文件的编码为Unicode,再尝试下. [ti:北京北京] [00:00.05]献给我最爱的老婆 --常长丽 [00:02.17]歌曲名:北京北京 [00