C语言中压缩字符串的简单算法小结
应用中,经常需要将字符串压缩成一个整数,即字符串散列。比如下面这些问题:
(1)搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。请找出最热门的10个检索串。
(2)有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
(3)有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
(4)给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url。
(5)一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词。
这些问题都需要将字符串压缩成一个整数,或者说是散列到某个整数 M 。然后再进行取余操作,比如 M%16,就可以将该字符串放到编号为M%16的文件中,相同的字符串肯定是在同一个文件中。通过这种处理,就可以将一个大文件等价划分成若干小文件,而对于小文件,就可以用常规的方法处理,内排序、hash_map等等。最后将这些小文件的处理结果综合起来,就可以求得原问题的解。
下面介绍一些字符串压缩的算法。
方法1:最简单就是将所有字符加起来,代码如下:
unsigned long HashString(const char *pString, unsigned long tableSize) { unsigned long hashValue = 0; while(*pString) hashValue += *pString++; return hashValue % tableSize; }
分析:如果字符串的长度有限,而散列表比较大的话,浪费比较大。例如,如果字符串最长为16字节,那么用到的仅仅是散列表的前16*127=2032。假如散列表含2729项,那么2032以后的项都用不到。
方法2:将上次计算出来的hash值左移5位(乘以32),再和当前关键字相加,能得到较好的均匀分布的效果。
unsigned long HashString(const char *pString,unsigned long tableSize) { unsigned long hashValue = 0; while (*pString) hashValue = (hashValue << 5) + *pString++; return hashValue % tableSize; }
分析:这种方法需要遍历整个字符串,如果字符串比较大,效率比较低。
方法3:利用哈夫曼算法,假设只有0-9这十个字符组成的字符串,我们借助哈夫曼算法,直接来看实例:
#define Size 10 int freq[Size]; string code[Size]; string word; struct Node { int id; int freq; Node *left; Node *right; Node(int freq_in):id(-1), freq(freq_in) { left = right = NULL; } }; struct NodeLess { bool operator()(const Node *a, const Node *b) const { return a->freq < b->freq; } }; void init() { for(int i = 0; i < Size; ++i) freq[i] = 0; for(int i = 0; i < word.size(); ++i) ++freq[word[i]]; } void dfs(Node *root, string res) { if(root->id >= 0) code[root->id] = res; else { if(NULL != root->left) dfs(root->left, res+"0"); if(NULL != root->right) dfs(root->right, res+"1"); } } void deleteNodes(Node *root) { if(NULL == root) return ; if(NULL == root->left && NULL == root->right) delete root; else { deleteNodes(root->left); deleteNodes(root->right); delete root; } } void BuildTree() { priority_queue<Node*, vector<Node*>, NodeLess> nodes; for(int i = 0; i < Size; ++i) { //0 == freq[i] 的情况未处理 Node *newNode = new Node(freq[i]); newNode->id = i; nodes.push(newNode); } while(nodes.size() > 1) { Node *left = nodes.top(); nodes.pop(); Node *right = nodes.top(); nodes.pop(); Node *newNode = new Node(left->freq + right->freq); newNode->left = left; newNode->right = right; nodes.push(newNode); } Node *root = nodes.top(); dfs(root, string("")); deleteNodes(root); }
上一篇:C++ auto类型说明符
栏 目:C语言
本文标题:C语言中压缩字符串的简单算法小结
本文地址:https://www.xiuzhanwang.com/a1/Cyuyan/2435.html
您可能感兴趣的文章
- 04-02c语言函数调用后清空内存 c语言调用函数删除字符
- 04-02c语言的正则匹配函数 c语言正则表达式函数库
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言中对数函数的表达式 c语言中对数怎么表达
- 04-02c语言用函数写分段 用c语言表示分段函数
- 04-02c语言编写函数冒泡排序 c语言冒泡排序法函数
- 04-02c语言没有round函数 round c语言
- 04-02c语言分段函数怎么求 用c语言求分段函数
- 04-02C语言中怎么打出三角函数 c语言中怎么打出三角函数的值
- 04-02c语言调用函数求fibo C语言调用函数求阶乘
阅读排行
本栏相关
- 04-02c语言函数调用后清空内存 c语言调用
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言的正则匹配函数 c语言正则表达
- 04-02c语言用函数写分段 用c语言表示分段
- 04-02c语言中对数函数的表达式 c语言中对
- 04-02c语言编写函数冒泡排序 c语言冒泡排
- 04-02c语言没有round函数 round c语言
- 04-02c语言分段函数怎么求 用c语言求分段
- 04-02C语言中怎么打出三角函数 c语言中怎
- 04-02c语言调用函数求fibo C语言调用函数求
随机阅读
- 04-02jquery与jsp,用jquery
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-11ajax实现页面的局部加载
- 01-10C#中split用法实例总结
- 01-10SublimeText编译C开发环境设置
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10delphi制作wav文件的方法