空间换时间,查表法的经典例子

前言

我们怎么衡量一个函数/代码块/算法的优劣呢?这需要从多个角度看待。本篇笔记我们先不考虑代码可读性、规范性、可移植性那些角度。

在我们嵌入式中,我们需要根据实际资源的情况来设计我们的代码。

比如当我们能用的存储器空间极其有限的情况,我之前就有遇到这样子的情况,我能用的flash空间只有4KB,但是要实现的功能很多,稍微不注意就超了,这种情况下我们就得多考虑程序占用方面的问题。

如果我们的存储器空间很足,有时候可以牺牲一些存储器空间来换取我们程序的运行速度。查表法就是以空间换取时间的典型例子。下面看一个经典的例子:

基础例子

编写程序统计一个4bit数据(0x0~0x0F)中1的个数。这里提供两种方法:

1、方法一:常规法

常规法就是依次判断这个4bit的数据的每一位是否为1,并用一个计数变量把1的个数记录下来:

左右滑动查看全部代码>>>

#include <stdio.h>

/* 测试结果 */
struct test_res
{
 unsigned int data;  /* 数据         */
 unsigned int count; /* 数据中1的个数 */
};

struct test_res get_test_res(unsigned int data)
{
 /* 保存测试结果 */
 struct test_res res;
 
 /* 保证数据总会在0~0xf之间 */
 unsigned int temp = data & 0xf;  
 
 res.count = 0;
 res.data = temp;
 
 /* 循环判断每一位 */
 for (int i = 0; i < 4; i++)
 {
  if (temp & 0x01)
  {
   res.count++;
  }
  temp >>= 1;
 }
 
 return res;
}

int main(void)
{
 struct test_res res = {0};
 
 for (int i = 0; i < 32; i++)
 {
  res = get_test_res(i);
  printf("%2d中二进制位为1的个数有%d\n", res.data, res.count);
 }

return 0;
}

运行结果:

unsigned int temp = data & 0xf; 语句就是为了保证数据都是在0x0~0xf之间,即0~15为一个周期,如果输入的数据为16,则当做0来看待,输入的数据为17,则当做1来看待……

2、方法二:查表法

这个例子也可以用查表法来做,把0x0~0xF中的所有数据中每个数据的1的个数都记录下来,存放到一个表中。

这样一来,数据数据中1的个数就建立起了一一对应关系,我们就可以通过数组索引来获取我们想要的结果:

左右滑动查看全部代码>>>

int table[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};

struct test_res get_test_res(unsigned int data)
{
 /* 保存测试结果 */
 struct test_res res;
 
 /* 保证数据总会在0~0xf之间 */
 unsigned int temp = data & 0xf;  
 
 /* 获取结果 */
 res.data = temp;
 res.count = table[temp];
 
 return res;
}

常规法使用for循环的方式来实现,缺点是占用了不少处理器的时间;查表法的优点弥补了常规法的不足,但是额外占用了一些静态空间。

这里针对这个应用而言处理的数据还是比较简单的,数据范围只是0x0~0xF之间,所以这两种方式可能也都差不多。

那如果以上题目稍微改一下:编写程序统计一个8bit、16bit数据中1的个数。查表法换取的时间就比较明显了。

延伸例子

下面我们先来看一下编写程序统计一个8bit(0x0~0xFF)数据中1的个数的情况。

1、常规法

把以上代码稍微改一下就可以:

左右滑动查看全部代码>>>

struct test_res get_test_res(unsigned int data)
{
 /* 保存测试结果 */
 struct test_res res;
 
 /* 保证数据总会在0~0xf之间 */ 
 unsigned int temp = data & 0xff;  
 
 res.count = 0;
 res.data = temp;
 
 /* 循环判断每一位 */
 for (int i = 0; i < 16; i++)
 {
  if (temp & 0x01)
  {
   res.count++;
  }
  temp >>= 1;
 }
 
 return res;
}

运行结果:

2、查表法

上面的数据范围仅仅是0x0~0xF,数据量比较少,建立数据表也比较容易。

这里的数据量范围变成了0x0~0xFF,比原来多了两百多个数据,这也还可以接受,也还可以全都列出来。

但是针对这里的这个问题有更好的方法:

在这个问题中,8bit的数据可以看做两个4bit数据,这样就可以共用上面4bit数据的数据表。所以我们只要把2个4bit数据的1的个数相加,就是最后的结果。

获取8bit数据1的个数:

左右滑动查看全部代码>>>

struct test_res get_test_res(unsigned int data)
{
 /* 保存测试结果 */
 struct test_res res;
 
 /* 保证数据总会在0~0xf之间 */
 unsigned int temp = data & 0xff;  
 
 /* 获取低4位中1的个数 */
 unsigned int low_data = temp & 0xf;
 unsigned int low_cnt = table[low_data];
 
 /* 获取高4位中1的个数 */
 unsigned int high_data = (temp >> 4) & 0xf;
 unsigned int high_cnt = table[high_data];
 
 /* 结果 */
 res.count = low_cnt + high_cnt;
 res.data = temp;
 
 return res;
}

同样的,获取16bit数据也是类似的,把16bit数据当做4个4bit数据。

针对以上这个查表法的例子我们可以总结出:

1、数据表的确定要合适。像上面8bit的情况再重新创建一个数据表把表元素列出来也还可以接受。但是如果是16bit这样子大数据的情况,建立这么大的数据表也不太现实。所以需要考虑如何建立一个合适的数据表。

2、需要权衡空间换取时间是否值得。像16bit这样子大数据的情况,全部列出来的话会大幅度的增加我们的存储开销,这种以空间换时间的情况可能会得不偿失。

(0)

相关推荐

  • c语言结构体中的冒号的用法

    结构体中常见的冒号的用法是表示位域. 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可.为了节省存储空间,并使处理 ...

  • 嵌入式开发中的AES加密/解密算法,你知道吗?看完这篇你就明白了

    今天给大家推荐一篇文章,来自我的好朋友老程. 深耕嵌入式,技术扎实,他用数学的方式讲解嵌入式系统的开发,简单明了,很容易理解,同时给我们开发带来很好的理论指导思路. 他的内容实用性很强,强烈推荐大家关 ...

  • 资本经营:做乘法/上电梯/以空间换时间 | 周永信说产融05

    文 / 9C产融  周永信 资本经营经常被比喻为做乘法.上电梯(产业经营是做加法.爬楼梯).它的本质是以空间换时间,别人几十年的努力,它可能只通过一夜便拿到.并且,它的关注点和收益来源不是利润,而是资 ...

  • 生育子孙查表法

    长生四子中旬半 ,沐浴一双保吉祥;    冠带临官三子位,旺中五子自成行;    衰中二子病中一, 死中至老无儿郎;    墓中必养他人子,入库之时命夭亡;   受气为绝一个子, 腹中头胎是姑娘;   ...

  • 步进电机S(SigMoid)曲线加减速【查表法】

    首先感谢以下博客的博主提供的参考公式:https://blog.csdn.net/pengzhihui2012/article/details/52228822?locationNum=6 首先在本设 ...

  • OLAP 服务器,空间换时间可行吗?

    多维分析提供拖拽.旋转.切片.钻取等等人机交互操作,必须有秒级的响应速度.而这些操作对应的明细数据量非常巨大,如果在明细数据的基础上直接计算,速度会很慢,等待时间过长,是用户无法接受的. 图1:基于明 ...

  • 技术资料丨《突发水污染事件以空间换时间的应急处置技术方法指导手册》

    伯益说 96篇原创内容 公众号 -----正文----- 突发水污染时间以空间换时间的应急处置技术方法指导手册.pdf 转自:环保有个号

  • 道教骨相算命法【好玩的查表命学】

    人的面相会随着时间改变,但骨相是一出生就注定好的.今天就要教大家,如何从农历出生月份,查知自己是哪种骨相,有着哪种好命? 查表命学,原理未知,仅供娱乐 农历出生月 骨相速查表 麒骨 天生富贵,有权势, ...

  • 周易六爻时间起卦速查表

    周易六爻时间起卦速查表

  • 潘书朋:经典语录——要给孩子们足够思考的空间和时间

    421.只有给孩子们足够思考的空间和时间,才是引导孩子们利用已有知识获取新知识,这才是学习的最佳方式,这也是高超教学技巧的精髓. 422.真正知识的获取是需要经过产生疑问.思考分析.解疑答惑等过程的, ...

  • 道教骨相算命法,查表算命

    人的面相会随着时间改变,但骨相是一出生就注定好的.今天就要教大家,如何从农历出生月份,查知自己是哪种骨相,有着哪种好命? 查表命学,原理未知,仅供娱乐 农历出生月 骨相速查表 麒骨 天生富贵,有权势, ...