使用c和位移位来解决特定需求
我有一个16个字母的字母表。给定一个句子,我想计算每个字母的频率,然后使用巧妙的位移位将所有频率封装在一个数字中。假设这些句子都是100个字母,假设没有字母出现超过31次,我想这样:使用c和位移位来解决特定需求,c,algorithm,bit-shift,C,Algorithm,Bit Shift,我有一个16个字母的字母表。给定一个句子,我想计算每个字母的频率,然后使用巧妙的位移位将所有频率封装在一个数字中。假设这些句子都是100个字母,假设没有字母出现超过31次,我想这样: A: occurs 2 times -> 0010 B: occurs 10 times -> 1010 C: occurs 7 times -> 0111 等等 现在,我想把这些连接起来: 001010100111 我只是集中了上面的频率。为了方便地存储数字,我想将上面的二进制文件转换为64位
A: occurs 2 times -> 0010
B: occurs 10 times -> 1010
C: occurs 7 times -> 0111
等等
现在,我想把这些连接起来:
001010100111
我只是集中了上面的频率。为了方便地存储数字,我想将上面的二进制文件转换为64位无符号整数
我的另一个要求是有那么长的时间,并重新提取每个字母的频率。因此,我需要能够生成十进制数,然后将其解析为各个频率位
在c语言中我该怎么做?我可以对这些频率进行位移位和加法,但这意味着我是重叠频率。另一个问题是在提取频率时,我如何知道要移动多少位,因为尾随的0不重要,也不保存在十进制中,但它们在我的算法中非常重要
有什么好主意吗?多谢各位 你有两个问题:一个数学问题和一个编码问题 让我们暂时忽略这道数学题。您可以构建一个包含16个整数的数组,并在扫描文本时统计每个字母的出现次数。如果您假设没有字母出现超过15次,那么您就不必担心溢出,您可以很容易地将计数放入64位整数中。你会写:
int counts[16]; // has the counts
unsigned long long freqs; // this holds the encoded value
// after you compute the counts
freqs = 0;
for (int i = 0; i < 16; ++i)
{
freqs <<= 4;
freqs |= (counts[i] & 0xF);
}
int计数[16];//有计数吗
无符号长-长频率;//它保存编码的值
//在你计算计数之后
频率=0;
对于(int i=0;i<16;++i)
{
freqs试试这个,优点是不需要中间数组来计算字母:
int ch_to_index(char ch) { return ch-'A'; }
unsigned long long get_freq(unsigned long long freq, int index)
{
return (freq>>(4*index))&0x0f;
}
unsigned long long set_freq(unsigned long long freq, int index, unsigned long val)
{
return ( ((val&0x0fULL)<<(4*index)) | (freq & (0xffffffffffffffffULL ^ (0xfULL<<(4*index)))) );
}
unsigned long long inc_freq(unsigned long long freq, int index)
{
return set_freq(freq, index, get_freq(freq, index) +1) ;
}
int main()
{
int i;
unsigned long long freq=0;
freq = inc_freq(freq, ch_to_index('A'));
freq = inc_freq(freq, ch_to_index('A'));
freq = inc_freq(freq, ch_to_index('B'));
for(i=0;i<16;i++)
{
printf("%i = %i\n", i, (int)get_freq(freq, i));
}
}
int chu to_index(char ch){return ch-'A';}
无符号long-long-get\u-freq(无符号long-long-freq,int-index)
{
返回(频率>>(4*索引))&0x0f;
}
无符号长集\频率(无符号长频率、整数索引、无符号长值)
{
return(((val&0x0fULL)这样的内容就足够了:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
const static int SIZE = 16;
const static char ALPHABET[] = "0123456789ABCDEF";
char* getFrequency(char* str);
uint64_t getFrequencyNumber(char* freq);
int main() {
char* str = "1337CODE";
uint64_t freqNum = getFrequencyNumber(getFrequency(str));
printf("%llu\n",freqNum);
return 0;
}
char* getFrequency(char* str) {
int i,j;
char* freq = (char*) calloc(SIZE, sizeof(char));
for(i=0; str[i]; ++i)
for(j=0; j<SIZE; ++j)
if(str[i] == ALPHABET[j])
if(freq[i] < 15) //ignore overflow
(freq[j])++;
return freq;
}
uint64_t getFrequencyNumber(char* freq) {
uint64_t i,num;
for(i=num=0; i<SIZE; ++i)
num |= freq[i] << (4*i); //use bit shifting to concatenate 4 bit values
return num;
}
#包括
#包括
#包括
常量静态int SIZE=16;
常量静态字符字母[]=“0123456789ABCDEF”;
char*getFrequency(char*str);
uint64_t getFrequencyNumber(字符*频率);
int main(){
char*str=“1337代码”;
uint64_t frequenum=getFrequencyNumber(getFrequency(str));
printf(“%llu\n”,freqNum);
返回0;
}
char*getFrequency(char*str){
int i,j;
char*freq=(char*)calloc(SIZE,sizeof(char));
对于(i=0;str[i];++i)
对于(j=0;j而言,现有答案是好的;不过,也许下面的答案更好
只需使用一个64位数字,就可以轻松地增加其中的单个4位部分
例如,下面增加了第3、第5和第13个字母的计数器(从0开始计算):
要打印:
char c;
for (c = 'a'; c <= 'p'; ++c)
{
int index = c - 'a';
int counter = (int)((my_counters >> (4 * index)) & 0xf);
printf("Letter %c, count %d\n", c, counter);
}
charc;
对于(c='a';c>(4*索引))&0xf);
printf(“字母%c,计数%d\n”,c,计数器);
}
注意:我的代码以与您想要的相反的顺序连接位;这种方式似乎更清楚。如果您将4*索引
替换为60-4*索引,则可以颠倒顺序,最多31表示存储一个字母的计数需要5位,乘以16个字母表示80位-您在嗯。可以限制每个字母15个吗?或者只有12个字母?您的规范最多只允许字母表中的一个字母出现15次。对不起,是的,我的意思是最多15次。一个解决方案可以满足您最初的16个字母、31个最大用法、100个长句子的要求,方法是使用汉明码来匹配64位整数。这不是你建议的串联,但可行。有趣的是,我从未想过这种方法!太好了!我只是认为有必要去掉一个大数组。有时,你可以通过将所有数据放入一个或多个适合一个CPU寄存器的变量来优化代码的速度。这些变量不需要访问缓存或R或者,当为只有1k或更少RAM的MCU编码时,位优化可能会很有帮助。有趣的方法,如果你能保证值会留在寄存器中,可能会非常快。如果你确定计数不会超过15,这个解决方案可以很好地工作,但你需要更改行:'return((val&0x0f)
uint64_t my_counters = 0;
size_t i;
for (i = 0; str[i] != '\0'; ++i)
{
int index = str[i] - 'a';
my_counters += (uint64_t)1 << (4 * index);
}
char c;
for (c = 'a'; c <= 'p'; ++c)
{
int index = c - 'a';
int counter = (int)((my_counters >> (4 * index)) & 0xf);
printf("Letter %c, count %d\n", c, counter);
}