查找結構一般有四種操做:查詢某個特定元素是否在表中,檢索知足條件的某個特定元素的各類屬性,在查找表中插入某一數據元素,從查找表中刪除某個元素html
鍵樹稱爲數字查找樹,是度大於等於2的書,書的每一個結點包含的是組成關鍵字的符號,若是關鍵字是數值,則結點包含一個數位,若是關鍵字是單詞,則結點包含一個字母字符,以下圖所示。node
每一個Node有三個域:ios
字典樹,又叫作Trie樹,單詞查找樹,或者前綴樹,是一種用於快速檢索的多叉樹結構,樹的每一個結點包含d個指針域,d是關鍵字符的基,好比英文字母的字典樹是26叉樹,數字字典樹是10叉樹。算法
Trie的缺點是:若是存在大量字符串,而這些字符串基本沒有公共前綴,那麼Trie樹將很是消耗內存。編程
Trie樹的實現:數組
#include<iostream> #include<cstdlib> using namespace std; const int branchNum = 26; struct Trie_node{ bool isStr; // 記錄此處是否構成一個串 Trie_node * next[branchNum]; //指向各個子樹的指針 // 初始化 Trie_node() :isStr(false){ memset(next, NULL, sizeof(next)); } }; class Trie{ private: Trie_node *root; public: Trie(){ root = new Trie_node(); } void insert(const char * str); bool search(char * str); void deleteTrie(Trie_node * root); Trie_node * getTrie(){ return root; } }; void Trie::insert(const char * str){ Trie_node * location = root; while (*str){ // 若是不存在則創建結點 if (location->next[*str - 'a'] == NULL){ Trie_node *temp = new Trie_node(); location->next[*str - 'a'] = temp; } location = location->next[*str - 'a']; // 每插入一步,至關於新串路過,指針移動 str++; } location->isStr = true;//標記一個串 // Trie *temp = (Trie *) malloc(sizeof(Trie)); // for(int i =0;i<26,i++) // temp->next[i] = NULL: } bool Trie::search(char * str){ Trie_node * location = root; while (*str && location){ // *str!='\0' location = location->next[*str - 'a']; str++; } return (location != NULL && location->isStr); } void Trie::deleteTrie(Trie_node *root){ for (int i = 0; i < branchNum; i++){ if (root->next[i] != NULL) deleteTrie(root->next[i]); } delete(root); } int main(){ char *str = "abcdefg"; Trie trie; trie.insert(str); if (trie.search(str)) cout << "true"; system("pause"); return 0; }
給定一個單詞a,若是經過交換字幕的順序能夠獲得另外的單詞b,那麼稱a和b是是兄弟單詞,如今要求給一個字典,用戶輸入一個單詞,能夠根據字典找到該單詞的兄弟單詞,要求時間和空間效率儘量高。
答:解法一:hash_map 和鏈表,定義一個ID,使得兄弟單詞有相同的id,不是兄弟單詞有不一樣的id,這個id能夠是將單詞從小到大排序後做爲其ID,也能夠是將單詞各個字母對應一個質數,將質數相乘當作hash id。建立一個hash_map,它的key爲單詞的id,value爲兄弟單詞鏈表的起始地址。全部的兄弟單詞存放在一個鏈表中。當須要找到該兄弟單詞時,只須要計算單詞id,而後到map中找到對應的鏈表便可。
解法二:利用Trie樹,單詞插入Trie樹前,先按照字母排序,將排序後的字母放入Trie樹,在樹的結點中增長一個vector,用於記錄全部的兄弟單詞安全
對大文件處理時,若文件過大,沒法一次性讀入內存,將hash映射將文件元素映射到不一樣小文件中,在依次處理各個小文件,最後合併處理結果。
例子:a、b文件,各存放50個url,請找出a、b共同的URL?
答:遍歷a,hash(url)%1024,將a分別存放在1024個文件中,對b進行一樣操做,處理後,**全部可能相同的url都在對應的小文件中,如a0對應b0,而後分別對小文件進行遍歷搜索處理等便可數據結構
【編程之美】讀書筆記:尋找最大的K個數
《編程之美》——尋找最大的K個數函數
// 快排 咱們基於數組的第K個數字來調整時,最小的k個數 void getleastNumber(int *input, int n, int *output, int k){ if (input == NULL || output == NULL || k>n || n <= 0 || k <= 0) return; int start = 0; int end = n - 1; int index = Partition(input, start, end); while (index != k - 1){ if (index > k - 1){ end = index - 1; // 一趟快排 index = Partition(input, start, end); } else{ start = index + 1; index = Partition(input, start, end); } } for (int i = 0; i < k; ++i) output[i] = input[i]; } int Partition(int *a, int low, int high){ int pivot = a[low]; while (low < high){ while (low < high && a[high] >= pivot) --high; a[low] = a[high]; while (low < high && a[low] <= pivot) ++low; a[high] = a[low]; } a[low] = pivot; return low; }
// 基於multiset的實現 void getLeastNumbers(const vector<int> &data, multiset<int, int> & leastNumbers, int k){ leastNumbers.clear(); if (k < 1 || data.size() < k) return; vector<int>::const iterator = data.begin(); for (; iter != data.end(); ++iter){ if (leastNumbers.size() < k) leastNumbers.insert(*iter); else{ mutiset<int, int>::iterator setiter = leastNumbers.begin(); if (*iter < *(leastNumbers.begin())){ leastNumbers.erase(setiter); leastNumbers.insert(iter); } } } }
時間複雜度爲O(n),以空間換時間,根據具體狀況須要n位的串url
例1: 40億個不重複的unsigned int的值,沒排過序,再給一個數,如何判斷這個數是否在40個億數中?
答:unsigned int 最多2^32個數,須要申請512M的內存,一個bit位表明一個unsigned int的值,讀入40億個數,設置對應bit位,讀入數,查詢相應的位
例2:4,7,2,5,3排序 答:申請一個8位byte位,讀入第一個值4,則將byte第5位置1,而後依次置位,最後遍歷bit區域,將該位是1的編號輸出