前言

上一篇分享了:C语言精华知识:表驱动法编程实践

这一篇再分享一个查表法经典的例子。

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

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

比如当我们能用的存储器空间极其有限的情况,我之前就有遇到这样子的情况,我能用的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这样子大数据的情况,全部列出来的话会大幅度的增加我们的存储开销,这种以空间换时间的情况可能会得不偿失。

推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

嵌入式Linux

微信扫描二维码,关注我的公众号 

空间换时间,查表法的经典例子相关推荐

  1. JS哈希表算法——空间换时间

    题目来源力扣: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数组中同一个元素 ...

  2. 以空间换时间——动态规划算法及其应用:矩阵链相乘

    动态规划算法是5大算法基础中最重要的一个,它专门用来解决平面世界下的应用,即会多次使用二维数组. 当然动态规划算法是空间换时间的算法,也就是说:我们可以利用空间资源来使某算法问题的时间复杂度降到最低. ...

  3. E002-CRC查表法-表的由来与实现1

    一.背景 CRC计算中常用空间换时间的方案即查表法,从前面的文章关于CRC的介绍中不难知道,crc的表其实就是对于整个字节256个数据的不同结果记录的集合. 1. 本文主要针对CRC16查表法表的计算 ...

  4. 【基础知识】CRC(循环冗余校验)直接计算和查表法

    CRC概述 校验 校验是什么,个人理解就是经过一个算法,使用大量数据(几MB的数据)生成较小长度的一串信息(如16Bit),并切要做到 原数据不同时,生成的信息大概率不同(不是加密算法不考虑刻意造数据 ...

  5. 前端遍历导致查询数据时间过长_OLAP 服务器,空间换时间可行吗?

    [摘要] 全量预汇总真的是提高 OLAP 性能的可行方案吗?点击了解OLAP 服务器,空间换时间可行吗? 多维分析提供拖拽.旋转.切片.钻取等等人机交互操作,必须有秒级的响应速度.而这些操作对应的明细 ...

  6. 常用crc查表法_CRC校验码简介及CRC16的计算方法

    点击上方"嵌入式从0到1",选择"置顶/星标公众号" 干货福利,第一时间送达! 什么是CRC校验? CRC即循环冗余校验码(Cyclic Redundancy ...

  7. JAVA-初步认识-第五章-数组-常见操作-进制转换(查表法)

    一. 数组的常见应用 数组在开发中什么时候用? 举例说明: 需求:获取一个整数的十六进制表现形式(要明白十六进制的表现形式是什么样子,有数字有字母) 本来应该返回一个字符串,但是还没有学到返回字符串, ...

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

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

  9. 嵌入式C语言查表法的项目应用

    嵌入式C实战项目开发技巧:如何对一个有规律的数组表进行位移操作 就像下面的这个表 之前写过上面这个标题的一篇文章,讲的是以位移的方式去遍历表中的数据,效率非常高,但是,如果要实现一个乱序的流水灯或者跑 ...

最新文章

  1. Outlook2010 Bug 一则
  2. 技术开发频道一周精选2007-8-24
  3. 低头族的第三只眼,“赛博朋克”新装备让你走路不再撞树
  4. linux重装alsa,centos 6 安装alsa
  5. Ubuntu网络配置方法
  6. 欧文分校计算机新sat多少分录取,加州大学欧文分校SAT成绩要求
  7. P7599-[APIO2021]雨林跳跃【二分,倍增,ST表】
  8. P4201-[NOI2008]设计路线【结论,树形dp】
  9. maven安装教程安装教程_Maven教程之春
  10. 一汽大众将召回3.7万辆存自燃隐患车辆
  11. 特征向量的辨析(数学,机器学习)
  12. java20 创建服务器:ServerSocket
  13. CSDN 七夕包分配,最后一天啦!
  14. 那英、那狗、那年、那事
  15. Python 代码覆盖率统计工具 coverage.py
  16. 如何理解UCB-Upper Confidence Bound
  17. 豪华酒店介绍预订网站模板,里面总共7个页面,适合酒店预订相关网站模板下载。
  18. Android Netd ndc
  19. cad没有命令输入框_CAD命令,教您CAD命令栏不见了怎么调出来
  20. wp8.1 java_巨硬的内部比较——WP8.1版本与WP10系统对比(以lumia640为例)

热门文章

  1. laravel框架——composer导入laravel
  2. php 输入汉字自动带出拼音和英文
  3. IP SLA的路径控制
  4. Android应用开发—LayoutParams的用法
  5. Python 第三方库之docx
  6. Django模型关系
  7. Storm编程模型总结
  8. java框架概念_java概念(2)
  9. 5G毫米波通信中一些量化的概念
  10. 前端小demo——全选和全不选