C语言中压缩字符串的简单算法小结_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语言
, 算法
, 字符串
压缩
c语言 字符串压缩算法、c语言 zip压缩算法、c语言压缩算法、c语言文件压缩算法、c语言字符串加密算法,以便于您获取更多的相关知识。

时间: 2024-09-13 00:45:51

C语言中压缩字符串的简单算法小结_C 语言的相关文章

C语言中的各种文件读写方法小结_C 语言

前言    找工作的时候,曾经用C语言练习过一段时间的算法题目,也在几个还算出名的OJ平台有过还算靠谱的排名.之前以为C语言只限于练习一下算法,但是工作中的一个问题解决让我意识到C语言的用处还是非常广泛的.下面介绍一下,如果用C语言来操作文件保存一个字符串,和读取一个字符串.算法中往往都是printf来打印出结果,但是真实工作中往往通过文件来进行一些持久化的存储工作. C-File I/O    文件的I/O操作是每一门语言的重点,因此这里我先来介绍一下如何用C语言去进行文件的I/O操作. 文件

C语言中数组的一些基本知识小结_C 语言

初始化数组 int ages[3] = {4, 6, 9}; int nums[10] = {1,2}; // 其余的自动初始化为0 int nums[] = {1,2,3,5,6}; // 根据大括号中的元素个数确定数组元素的个数 int nums[5] = {[4] = 3,[1] = 2}; // 指定元素个数,同时给指定元素进行初始化 int nums[3]; nums[0] = 1; nums[1] = 2; nums[2] = 3; // 先定义,后初始化 定义但是未初始化,数组中有

C语言中获取文件状态的相关函数小结_C 语言

C语言stat()函数:获取文件状态头文件: #include <sys/stat.h> #include <unistd.h> 定义函数: int stat(const char * file_name, struct stat *buf); 函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中. 下面是struct stat 内各参数的说明: struct stat { dev_t st_dev; //device 文件的设备编号

C++中sting类的简单实现方法_C 语言

String 在C++的学习生涯我中发现String类的功能十分强大,所以我们是很有必要模拟实现它的,况且在面试的时候模拟实现一个String类也是面试官经常会考的,但是因为外界因素的限制我们是不可能模拟的和库里的string一致的(C++库里的string功能更强大),所以今天我们只模拟实现string的基本功能-构造函数,拷贝构造函数,析构函数,赋值运算符重载,运算符+=的重载,运算符[]的重载,c_str(得到一个C风格的字符指针,可操作字符串),Size,Push_Back,Insert

C语言找出数组中的特定元素的算法解析_C 语言

     问题描述:一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它.能否只用一个额外数组和少量其它空间实现.       思路:如果能用两个辅助数组,那么相对来说简单一点,可定义数组Min和数组Max,其中Min[i]表示自a[i]之后的最小值(包括a[i]),Max[i]表示自a[i]之前元素的最大值.有了这两个辅助数组后,对于a[i],如果它大于Max[i-1]并且小于Min[i+1],那么就符合要求.       但是题目要求

解析C++中的字符串处理函数和指针_C 语言

C++字符串处理函数 字符串连接函数 strcat 其函数原型为 strcat(char[],const char[]); strcat是string catenate(字符串连接)的缩写.该函数有两个字符数组的参数,函数的作用是:将第二个字符数组中的字符串连接到前面字符数组的字符串的后面.第二个字符数组被指定为const,以保证该数组中的内容不会在函数调用期间修改.连接后的字符串放在第一个字符数组中,函数调用后得到的函数值,就是第一个字符数组的地址.例如: char str1[30]=″Peo

简单总结C语言中各种类型的指针的概念_C 语言

C语言中有很多关于指针的使用,指针也是C语言的灵魂所在,而且C语言中也有很多有关指针的概念,这里学习并总结了一些知道的概念.  常量指针:首先它是一个指针,常量只是用来修饰指针的定语.其定义如下: char const * cp; char a='a'; 如何识别呢?根据右结合优先,先是*优先,所以这个cp变量是一个指针,然后是const修饰*,所以这是一个常量指针.即指向常量的指针. cp=&a; //正常语法 *cp=a; //错误语法,因为其指向的值是一个常量  指针常量:首先它是一个常量

C语言中的函数指针基础学习教程_C 语言

顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun2(char * p1,char * p2); C) char * fun3(char * p1,char * p2); 看看上面三个表达式分别是什么意思? C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型. B) 也很简单,与C)表达式相比,唯一不同的就是函数的

c语言中 基于随机函数的使用详解_C 语言

在C语言中,rand()函数可以用来产生随机数,但是这不是真真意义上的随机数,是一个伪随机数,是根据一个数,我们可以称它为种子,为基准以某个递推公式推算出来的一系数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是定了的,除非你破坏了系统,为了改变这个种子的值,C提供了srand()函数,它的原形是void srand( int a). 可能大家都知道C语言中的随机函数random,可是random函数并不是ANSI C标准,