文档章节

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

o
 osc_yo7hxxom
发布于 07/01 15:42
字数 1397
阅读 22
收藏 0

精选30+云产品,助力企业轻松上云!>>>

前言

上一篇分享了: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; 语句就是为了保证数据都是在0x00xf之间,即015为一个周期,如果输入的数据为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这样子大数据的情况,全部列出来的话会大幅度的增加我们的存储开销,这种以空间换时间的情况可能会得不偿失。

以上就是本次的分享。

o
粉丝 0
博文 55
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

DateTime2与SQL Server中的DateTime - DateTime2 vs DateTime in SQL Server

问题: Which one: 哪一个: datetime datetime2 is the recommended way to store date and time in SQL Server 2008+? 是在SQL Server 2008+中存储日期和时间的推荐方法吗? I'm aware of......

富含淀粉
59分钟前
13
0
Linux 文件打开过多 (Too many open files)

如图是程序运行了一段时间后抛出来的一个bug, 刚开始看这个bug的时候各种网上找答案, 无外乎教你怎么改ulimit(就是linux最大打开文件数), 当然不是说改这个没有用, 作为程序开发者来说, 如果...

onedotdot
今天
25
0
ZStack实践汇|ZStack与行云管家对接实践ZStack与行云管家对接实践

一、ZStack与行云管家概述 大道至简·极速部署,ZStack致力于产品化私有云和混合云。 ZStack是一家坚持自主创新、专注产品化的云计算公司,以“降低企业上云门槛、让每一家企业都拥有自己的云...

ZStack社区版
今天
7
0
switch linux mint 20 apt repository to tsinghua' mirrors

edit file /etc/apt/sources.list.d/cat official-package-repositories.list lwk@qwfys:/etc/apt/sources.list.d$ lltotal 12drwxr-xr-x 2 root root 4096 Jul 5 20:01 ./drwxr-xr-x 7 ......

qwfys
今天
12
0
面试系列之C++的对象布局【建议收藏】

我们都知道C++多态是通过虚函数表来实现的,那具体是什么样的大家清楚吗?开篇依旧提出来几个问题: 普通类对象是什么布局? 带虚函数的类对象是什么布局? 单继承下不含有覆盖函数的类对象是...

伊牙牙嘿哈哈
今天
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部