查找结构一般有四种操做:查询某个特定元素是否在表中,检索知足条件的某个特定元素的各类属性,在查找表中插入某一数据元素,从查找表中删除某个元素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的编号输出