编程之美之二进制数中1的个数

2024-02-19 03:48

本文主要是介绍编程之美之二进制数中1的个数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题:

对于一个字节(8bit)的变量,求其二进制中1的个数,要求算法的执行效率尽可能的高。

例如把9表示成二进制是1001,有2位是1,因此如果输入9,1的个数为2。


解法一:

可以举一个8位二进制的例子。对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位)。如果除的过程中有余,那么久表示当前位置有一个1。

以10100010为例:

第一次除以2时,商为1010001,余为0

第二次除以2时,商为101000,余为1

因此,考虑利用整形数据除法的特点,通过相除和判断余数的值进行分析。

[cpp]  view plain copy
  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.          if(a % 2 == 1)  
  7.          {  
  8.               count++;    
  9.          }  
  10.          a = a / 2;  
  11.     }  
  12.     return count;  
  13. }  

解法二:位操作

使用位操作同样达到相除的目的。

使用与操作(&)来判断最后一位是不是1,判断完后向右移一位,继续判断。

可以把这个八位数与00000001进行与操作,如果结果为1则表示这个八位数最后一位为1,否则为0。

[cpp]  view plain copy
  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.          count += a & 0x01;  
  7.          a >>= 1;  
  8.     }  
  9.     return count;  
  10. }  

位操作要比除法取余操作效率要高许多。


解法三:

作者用到一个巧妙的方法,自己与自己减1相与,(例:10100010 & 10100001 = 10100000)从而到达消去最后一位1,通过统计循环次数达到计算1的个数的目的,这个方法减少了一定的循环次数。

具体解析看看原著。

[cpp]  view plain copy
  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.         a = a & (a-1);  
  7.         count++;  
  8.     }  
  9.     return count;  
  10. }  


解法四:分支操作

解法三的复杂度降到O(M). 其中M为1的个数。这效率已经足够高了。

如果还不满足,还有一种方法。既然才是一个8位的数据(0~255),可以直接0~255的情况罗列出来,使用分支操作,得到答案。

这个方法看似很直接,但是效率可能会比其他方法要低。具体情况具体分析。如果a = 0比较一次就会得到答案,但是a = 255比较255次才得到答案

[cpp]  view plain copy
  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     switch(a)  
  5.     {  
  6.         case 0x0:  
  7.              count = 0;  
  8.              break;  
  9.         case 0x1:  
  10.         case 0x2:  
  11.         case 0x4:  
  12.         case 0x8:  
  13.         case 0x10:  
  14.         case 0x20:  
  15.         case 0x40:  
  16.         case 0x80:  
  17.              count = 1;  
  18.              break;  
  19.         case 0x3:  
  20.         case 0x6:  
  21.         case 0xc:  
  22.         case 0x18:  
  23.         case 0x30:  
  24.         case 0x60:  
  25.         case 0xc0:  
  26.              count = 2;  
  27.              break;   
  28.         //.....  
  29.     }  
  30.     return count;  
  31. }  


解法五:查表法

直接把0~255相应1的个数直接存在数组中,采取以空间换取时间。

[cpp]  view plain copy
  1. int CountTable[256] =       
  2. {          
  3.          0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,  
  4.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  5.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  6.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  7.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  8.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  9.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  10.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  11.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  12.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  13.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  14.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  15.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  16.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  17.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  18.          4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8          
  19. };  
  20.   
  21. int Count(int a)  
  22. {  
  23.     return CountTable[a];  
  24. }  

这篇关于编程之美之二进制数中1的个数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/723398

相关文章

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

spoj705( 求不相同的子串个数)

题意:求串s的不同子串的个数 解题思路:任何子串都是某个后缀的前缀,对n个后缀排序,求某个后缀的前缀的个数,减去height[i](第i个后缀与第i-1 个后缀有相同的height[i]个前缀)。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstrin

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)