数据结构练习---基于不同策略的英文单词检索系统(顺序表,单链表,二叉排序树)
学校课程设计实训周,抽到了这个题,写完之后也有一些收获,放到网上和大家一起学习交流:)
本人数据结构只是学了一些皮毛,代码写的比较简单直接,通俗易懂。还望各路大神多多指教
拿到题目遇到的第一个问题,就是如何从指定路径下读取文件,去除空格及标点符号,并将读取到的英文文章拆分为一个个英文单词存储起来?
我的方法是用isalpha()这个函数来判断是否是英文字母,函数类型定义为bool,若不是英文字母,返回false,就再向后读取一个字符,直到找到第一个英文字母,证明找到了一个英文单词的开头,返回true。设置一个start变量,将这个单词的首字母所在位置记录下来,然后一直向后找,直到再次找到非英文字母,证明一个单词结束,再设置一个end变量记录下结束位置。这样就截取到了一个单词的起始位置。设置一个char型数组,运用循环将单词各字母逐个放入数组,最后加上'\0',一个个单词就截取成功啦!
int detect(const char *p,SqList &L,LinkList &LL)
{int i=0,m;char temp[20];int start,end;while(p[i]!=0) //当非空行 {while(judge_alphabet(p[i])==false){i++;}if(judge_alphabet(p[i])){start=i;i++;while(judge_alphabet(p[i])){i++;}}end=i;for(int j=start,k=0;j<=end;k++,j++){temp[k]=p[j];m=k;}temp[m]='\0';L.elem[count].key=temp; //count为单词个数,也可作为线性表存储单词的下标 count++;i++;LNode *s=new LNode;s->data=temp;s->next=LL->next;LL->next=s;}
}
遇到的第二个问题就是如何统计整篇文章的单词词频。我的方法是为存储单词的线性表再添加一个flag标志,初始化为true。循环遍历线性表,如果后面再次出现相同的单词,就把该单词所在位置的flag置为false,再次遍历时就直接跳过。
void Getnum(SqList &L) //获取文章中所有单词词频
{int j=1;for(int a=1;a<=L.length;a++) //外层循环,拿第a个单词和线性表所有单词进行比较 {int nums=0;if(L.elem[a].flag==true) //true证明还没有相同单词,执行比较操作 {for(int i=1;i<=L.length;i++) //内层循环,依次遍历整个线性表 {if(L.elem[a].key==L.elem[i].key){L.elem[i].flag=false;nums++;}else continue;}words_num[j]=nums; //将所有单词词频存放在word_num这个数组中 L.elem[j].key=L.elem[a].key;j++;}}
}
实现功能中还要求输出各查找方式的ASL,这里就直接输出:线性表查找为(n+1)/2,折半查找为log以2为底(n+1)-1,二叉排序树为㏒以2为底(n+1)
需要动脑子的应该只有这么多内容,其他都是一些比较基础的定义结构,初始化,读取调用等函数,平常数据结构课上应该都有练习,这里就不再赘述了,下面贴上完整代码
#include
#include //c++操作文件所需的头文件
#include
#include //判断字符是否是字母
#include //数学方法
using namespace std;
#define MAXSIZE 10000 //顺序表的最大长度int count=1; //既是单词个数又是线性表下标,一会儿输出单词个数记得count-1
int words=0; //统计欲查找单词频数
int words_num[MAXSIZE]; //存放所有单词词频
typedef struct{string key; //存放单词bool flag; //设置标志,若查找单词在后面出现过,就把该单词所在位置下的flag置为falseint words; //统计词频,若查询单词在后面再次出现,words++
}ElemType;
typedef struct{ //线性表结构ElemType elem[MAXSIZE];int length;
}SqList;typedef struct LNode{ //单链表结构 string data;struct LNode *next;
}LNode,*LinkList;typedef struct BSTNode{ //二叉链表结构 string data;struct BSTNode *Lchild,*Rchild;
}BSTNode,*BSTree;void Init_SqList(SqList &L) //初始化线性表
{L.length = 0;for(int i=0;inext = NULL;
}
bool judge_alphabet(char ch) //判断是否为英文字母
{if(isalpha(ch))return true;elsereturn false;
}
int detect(const char *p,SqList &L,LinkList &LL)
{int i=0,m;char temp[20];int start,end;while(p[i]!=0) //当非空行 {while(judge_alphabet(p[i])==false){i++;}if(judge_alphabet(p[i])){start=i;i++;while(judge_alphabet(p[i])){i++;}}end=i;for(int j=start,k=0;j<=end;k++,j++){temp[k]=p[j];m=k;}temp[m]='\0';L.elem[count].key=temp; //count为单词个数,也可作为线性表存储单词的下标 count++;i++;LNode *s=new LNode;s->data=temp;s->next=LL->next;LL->next=s;}
}//将文件C:\book.txt中的数据逐条读入顺序表L中
void ReadData(SqList &L,LinkList &LL,BSTree &T)
{int i=0;string temp;ifstream infile("d:\\Obama.txt"); //以输入的方式(读文件的方式)打开文件c:\book.txtwhile(!infile.eof()) //只要文件没读完,就读一行数据到顺序表L中的第i个分量中{getline(infile,temp);const char *p=temp.c_str();if(strlen(p)!=0){detect(p,L,LL);}}L.length = count-1;infile.close();
}void WriteData(SqList L)
{int q;ofstream outfile("d:\\words.txt"); //将单词总数及词频信息保存在新的txt中 outfile<<"单词总数为:"<next;/*while(p!=NULL) //以单链表形式输出所有单词 {cout<data;p=p->next;}cout<next;while(p!=NULL){if(p->data==key)words++;p=p->next;}return words;}void InsertSort(SqList &L) //使用直接插入法对线性表L进行排序
{int i,j;for(i=2;idata=e;s->Lchild=s->Rchild=NULL;T=s;}else if(edata)Insert_BST(T->Lchild,e);else if(e>T->data)Insert_BST(T->Rchild,e);
}
void Create_BST(BSTree &T,SqList L) //创建二叉排序树
{int i=1;string e;T=NULL;e=L.elem[1].key;while(i<=L.length){Insert_BST(T,e);i++;e=L.elem[i].key;}
}
void InorderBST(BSTree T) //中序遍历并输出二叉排序树
{if(T){InorderBST(T->Lchild);cout<data<<" ";InorderBST(T->Rchild);}
}BSTree SearchBST(BSTree T,string key) //二叉排序树的查找
{if(!T||key==T->data) return T;else if(keydata) return SearchBST(T->Lchild,key);else return SearchBST(T->Rchild,key);
}void Delete(BSTree &T,BSTNode *p,BSTNode *f) //二叉排序树中p所指结点的删除
{BSTNode *q,*s;q=p;if(p->Rchild && p->Lchild ) //p所指结点的左右子树均非空{s=p->Lchild;while(s->Rchild){q=s;s=s->Rchild;}p->data=s->data;if(q==p) q->Lchild=s->Lchild;else q->Rchild=s->Lchild;delete s;}else if(p->Rchild ==NULL) //p所指结点只有左子树{p=p->Lchild;}else if(p->Lchild ==NULL) //p所指结点只有右子树{p=p->Rchild;}if(f==NULL) T=NULL; //T只有一个根结点,且被删除的是根结点else if(q==f->Lchild ) f->Lchild =p; //被删结点是双亲f的左孩子else f->Rchild =p; //被删结点是双亲f的右孩子delete q; //释放被删结点
}bool DeleteBST(BSTree &T,string key) //二叉排序树的删除
{BSTNode *p=T,*f=NULL; while(p) //从二叉排序树的根开始,查找关键字为key的结点,并用p指向它,f指向p的双亲{if(p->data == key) //找到关键字为key的结点,且p指向它break;f=p; //f为p的双亲if(p->data > key) //在p的左子树中继续查找p=p->Lchild ;else //在p的右子树中继续查找p=p->Rchild ;}if(p==NULL) //T中不存在关键字等于key的结点,返回falsereturn false;Delete(T,p,f); //在二叉排序树T中删除p所指结点(关键字为key的结点),f指向p的双亲return true; //删除成功,返回true
}void show_main_menu()
{cout<<" -----------------------------------------"<>n;cout<>n;cout<>word; num = Sq_Search(LSq,word);if(num>0)cout<<"查找成功!"<<"\n该词词频为:"<>n;cout<>word;num = LL_Search(LL,word);if(num>0)cout<<"查找成功!"<<"\n该词词频为:"<>n;cout<>word;InsertSort(LSq);num=Search_Bin(LSq,word);if(num>0)cout<>n;cout<>word;num1=SearchBST(T,word);if(num1>0)cout<>word;if(DeleteBST(T,word)==false)cout<<"\n删除失败!! 二叉排序树中不存在单词 "<
说明:受限于存储结构,该代码应该最多只能读取5000词以下的文章,我用的奥巴马就职演讲(2400词)和姚老板名人堂演讲(1300词)都没有问题,但类似于傲慢与偏见,月亮与六便士这类篇幅较长的小说程序就该崩掉了
本来应该再来一个性能为O(1)的哈希查找,碍于各种原因没有加上,有兴趣的同学可以自己再完善一下:)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
