題目要求:
請設計數據結構並寫出算法,統計一篇文章中每個單詞出現的次數,並按單詞在文章中出現的順序輸出單詞及它的個數。
個人思路:
采用了類似鍵樹的思想,用該樹來存儲單詞及某個單詞出現的次數;樹從根節點到葉子節點組成一個單詞,每個節點只存儲該單詞里的某個字符;
用孩子兄弟法表示樹,用左孩子記錄某個單詞出現的次數(參見樹結構圖),可讓每個單詞必有左孩子(創建新節點同時創建左孩子)。
這樣就能得到單詞及其個數,題目中要求按出現順序輸出可以用一個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