免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: heavyrain44
打印 上一主题 下一主题

[算法] 请教一个算法 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2007-05-24 10:45 |只看该作者
总共就那么几位,就算从最低位开始一位一位的扫描,用的时间也是很少的,如果这个是在别的系统中的话,我觉得提高效率应该考虑系统的其他部分。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
12 [报告]
发表于 2007-05-24 11:41 |只看该作者
原帖由 heavyrain44 于 2007-5-24 09:03 发表
我想请教一个算法,有一无符号32位整数,求其右边第一位数起到第一个位为‘1’的0的个数。
如0x21c534a8,则返回3;0x1b94a4c0,则返回6。
用循环好做,但时间复杂度不是常数。有时间复杂度为常数的算法吗,谢谢 ...

先考虑简单的实现,测试一下速度,如果不符合你的要求再考虑优化吧。要不也可以直接在网上搜索较快的算法。

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
13 [报告]
发表于 2007-05-24 12:28 |只看该作者
可以折半查找,但总共就32位,意义不大。
象这样:

  1.     unsigned int mask = 0x0000ffff;
  2.     for(i=16; i > 0; i >>= 1, mask >>= i)
  3.     {
  4.         if( (n&mask) == 0)
  5.         {
  6.             m += i;
  7.             n >>= i;
  8.         }
  9.     }
  10.     if(n == 0) m++;
  11.     return m;
复制代码

只在理论上成立,实际的效果我很怀疑还不如循环32次

论坛徽章:
0
14 [报告]
发表于 2007-05-24 12:29 |只看该作者

  1. unsigned int num = 0x12345678;
  2. unsigned int table[32] = {0x00000001, 0x00000002, .....};
  3. do{
  4. if(num & table[0]){
  5.    printf("0\n");
  6.    break;
  7. }
  8. if(num & table[1]){
  9.    printf("1\n");
  10.    break;
  11. }
  12. .......
  13. }while(0);
复制代码

[ 本帖最后由 FreeGnu 于 2007-5-24 12:41 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2007-05-24 15:40 |只看该作者
unsigned int num = 0x12345678;
unsigned int count = 0;
while(1)
{
if(num & 0x00000001)
{
   printf("%d\n", count );
   break;
}
num = num>>1;
count++;
}

这样简洁些嘛

[ 本帖最后由 zenglj 于 2007-5-24 15:47 编辑 ]

论坛徽章:
0
16 [报告]
发表于 2007-05-24 15:48 |只看该作者
二分:

  1. int ntz(unsigned x) {
  2.    int n;

  3.    if (x == 0) return(32);
  4.    n = 1;
  5.    if ((x & 0x0000FFFF) == 0) {n = n +16; x = x >>16;}
  6.    if ((x & 0x000000FF) == 0) {n = n + 8; x = x >> 8;}
  7.    if ((x & 0x0000000F) == 0) {n = n + 4; x = x >> 4;}
  8.    if ((x & 0x00000003) == 0) {n = n + 2; x = x >> 2;}
  9.    return n - (x & 1);
  10. }

复制代码

论坛徽章:
0
17 [报告]
发表于 2007-05-27 22:30 |只看该作者
假设该数为x,那么x - (x & (x - 1))就是一个2的冥,然后就再进行处理,比如说取对数(但取对数时间复杂度是不是常数我就不知道了)或者查表(至于怎么设计表格你自己想想或者其他弟兄给个方法)。

论坛徽章:
0
18 [报告]
发表于 2007-05-27 23:48 |只看该作者
这个就要看你在什么机器上跑了,有些机器比较怪异,直接就有这样的指令。

论坛徽章:
0
19 [报告]
发表于 2007-05-28 00:51 |只看该作者
考虑到《hackers delight》中的count_ones技巧, 有如下解决办法。


  1. int count_ones(unsigned int x)
  2. {
  3.     x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
  4.     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  5.     x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f);
  6.     x = (x & 0x00ff00ff) + ((x >> 8) & 0x00ff00ff);
  7.     x = (x & 0x0000ffff) + ((x >> 16) & 0x0000ffff);

  8.     return x;       
  9. }

  10. #define rfind_zeros(x) ((x)?count_ones((x)^((x)-1))-1:32)

  11. int main(void)
  12. {
  13.         int n = 0x1;
  14.         printf("%d\n", rfind_zeros(n));
  15.         return 0;
  16. }
复制代码

[ 本帖最后由 jigloo 于 2007-5-28 01:01 编辑 ]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
20 [报告]
发表于 2007-05-28 01:11 |只看该作者
原帖由 SuperZ 于 2007-5-27 23:48 发表
这个就要看你在什么机器上跑了,有些机器比较怪异,直接就有这样的指令。

对头,直接用汇编实现。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP