一道笔试题:统计文章中出现的单词个数

题目要求:

请设计数据结构并写出算法,统计一篇文章中每个单词出现的次数,并按单词在文章中出现的顺序输出单词及它的个数。

个人思路:

采用了类似键树的思想,用该树来存储单词及某个单词出现的次数;树从根节点到叶子节点组成一个单词,每个节点只存储该单词里的某个字符;

用孩子兄弟法表示树,用左孩子记录某个单词出现的次数(参见树结构图),可让每个单词必有左孩子(创建新节点同时创建左孩子)。

这样就能得到单词及其个数,题目中要求按出现顺序输出可以用一个list或vector存放单词记录,该记录里存放单词及指向代表该单词访问记录数的树节点指针,这样文章读完后,将list或vector里的记录输出即可。

 

其它思路:

(1)可以用stl里的map实现

(2)可以将单词hash,存放在一个数组里,若hash冲突,采用链地址法,在数组元素后添加链表存放单词及次数,同时将首次出现的记录指针存放到Vector或list中

 

实现:

定义树结构及单词记录如下:

//孩子兄弟法表示树
typedef struct KeyNode
{
    char data;
    unsigned int count;
    struct KeyNode *son,*next;
}*KeyTree;

//单词记录
//存放单词及指向单词出现数的节点的指针
struct TWord
{
string word;
struct KeyNode* pNode;
};

 树结构示意图:

 

上图展示的是查询过单词"ah","she"后形成的树;

 以"ah"单词访问为例,描述如何构造树:

(1)初始化一个树,生成一个根节点和一存放空字符的左孩子

(2)单词"ah",先从树中找字符'o',没找到,则在树根插入节点,赋值为'a',同时创建存放空字符的左孩子,次数设为0(这个次数,表示单词"a"出现的次数)

(3)之后按同样方法将字符'h'按(2)中方法生成新节点插入到(2)中生成节点'a'下

(4)单词读完,将'h'的左子树出现次数+1,表示单词"ah"出现次数为1;同时将该左子树指针与单词名放入vector

(5)同样方法生成"she"单词及其次数

 若出现同样的单词,只需将单词对应的尾字符的左孩子节点次数+1即可。

 查找及插入单词用到的函数:

//从给定键树中查看是否存在字符串pStr,
//若存在返回true,若是第一次查询该字符串,则记字符串为首次查询且用p返回
//指向该字符串结束叶子节点的指针;
//若不存在返回false
bool FindString(const KeyTree pTree,char* pStart,const char* pEnd,bool& isFirstFind,KeyTree& p)
{
    assert(pTree!=NULL && pTree->son!=NULL);
    assert(pStart!=NULL);
    assert(pEnd!=NULL);
    char* pCur = pStart;
    KeyTree pCurTree = pTree->son;
    while(pCurTree)
    {
        KeyTree pNext = pCurTree->next;
        //从兄弟中找相应字符直到找到若兄弟为空
        while(pNext && pNext->data!=*pCur)
        {
            pNext = pNext->next;
        }
        //没找到
        if(pNext==NULL) return false;
        //找到进入下一层判断
        pCurTree = pNext->son;
        pCur++;

        //字符串匹配结束,成功找到
        if(pCur>pEnd) break;
    }

    KeyTree pSon = pCurTree;
    //第一次访问,孩子节点不存在,创建
    if(pSon == NULL)
    {
        pSon = CreateKeyNode(END_WORD);
        pSon->count = 1;
        isFirstFind = true;
        p = pSon;
    }
    else
    {
        //出现次数+1
        pSon->count++;
        if(pSon->count==1)
        {
            isFirstFind = true;
            p = pSon;
        }
    }
    return true;
}

 

//将字符串插入到键树中
//从第一个不匹配的字符开始创建新树节点存储字符串里的字符
//p返回指向该字符串结束叶子节点的指针
bool Insert(const KeyTree pTree,char* pStr,const char* pEnd,KeyTree& p)
{
    assert(pTree!=NULL && pTree->son!=NULL);
    assert(pStr!=NULL);
    assert(pEnd!=NULL);

    char* pCur = pStr;
    KeyTree pCurTree = pTree->son;
    while(pCur<=pEnd)
    {
        KeyTree pNext = pCurTree->next;
        
        //从兄弟中找对应字符,直至找到或找完所有兄弟
        while(pNext && pNext->data!=*pCur) 
        {
            pCurTree = pNext;
            pNext = pNext->next;
        }
        //未找到,则创建
        if(pNext==NULL)
        {
            pNext = CreateKeyNode(*pCur);
            pNext->son = CreateKeyNode(END_WORD);
            pCurTree->next = pNext;
        }

        //当前字符匹配完成,匹配下一个字符
        pCurTree = pNext->son;
        pCur++;
    }

    //出现次数+1
    pCurTree->count++;
    p = pCurTree;
    return true;
}

对字符串的输出:

 

附上源码文件:类键树统计字符串个数.zip

posted @ 2012-09-19 23:53  t427  阅读(3349)  评论(0编辑  收藏  举报