大家好,我是TT。
通过前面几篇的内容,你已经了解了基本的程序结构。我们来简单总结一下,其中第一种结构就是顺序结构,它指的是我们所写的按照顺序执行的代码,执行完上一行,再执行下一行这种的。第二种就是分支结构,主要是用if条件分支语句来实现,主要特征是根据表达式的真假,选择性地执行后续代码。最后一种就是循环结构,用来重复执行某段代码的结构。
如果把程序比喻成工厂的话,现在你的工厂中已经有了各种各样的流水线,但这个工厂只是能生产产品还不行,还需要有存储的空间。这篇内容,我们来看看如何创建和使用工厂中的库房,这篇内容之后,你的程序工厂就可以开工了!
这篇内容的任务是这样的,程序中读入一个整数n,假设n不会大于,请输出1到n的每一个数字二进制表示中的1的个数。
我举个例子哈,当n等于7的时候,我们把1到7的每个数字的二进制表示罗列出来,会得到下表所示内容:
根据表1中的内容,如果你的程序编写成功的话,程序应该分别输出1、1、2、1、2、2、3,这些输出内容分别代表每个数字二进制表示中1的数量。
对于这个任务,你想写出来一个可行的程序不难,例如:我们可以循环n次,每次计算一个数字二进制中1的数量。怎么计算一个数字二进制中1的数量呢?这个问题,你可能想采用如下程序来进行实现:
我解释下上面这段程序,它每次都会判断n的二进制末尾是不是1,如果是1,计数量cnt就加1(+=表达式,我这里就不解释了,如果你不理解,可以自己查下),然后将n除以2,相当于去掉n的二进制表示的最后一位,这样就可以用O(logn)的时间复杂度(关于这个知识点,你也可以自行查阅相关资料,其实很简单)计算一个数字n二进制中1的数量。
以二进制数字为例,末尾是0,计数量cnt不进入计算;然后使用二进制除法,让除以2,即去掉最后一位的0,变成了11,此时末尾是1,计数量cnt就加1;11再除以2,变成了1,此时末尾是1,计数量cnt再次加1。最后的n等于1,再除以2,n变成了0,循环结束。
可以看到,当我们输入数字6,二进制的表示是时,整个程序中计数量cnt共计算了2次,所以最后的输出结果是2。
关于时间复杂度这个概念,后续我们还会进一步介绍,现在你可以简单地理解成为是程序运行的次数,例如n=8的时候,上面循环执行3次,也就是log以2为底8的对数的值。
如果你的方法像上面这么做的话,确实是一种可行的方法,可是效率不是很高。今天这个任务的要求是,对每一个数字,请用O(1)的时间复杂度计算得到其二进制表示中1的个数。O(1)也就是1次,或者是与问题规模n无关的有限次,例如:2次、3次均可。下面就让我们来看看如何完成这个任务吧。
1.数组:规模化存储工具
我要给你介绍的第一个帮助我们完成今天任务的工具是:数组。所谓数组,你可以把这两个字对调过来理解,即组数,一组数据。
以往我们定义的变量,都是单一变量,例如:一个整型变量,一个浮点型变量,等等。可当我们要同时记录n个整型数据的时候,通过以往的知识,你能实现这个需求么?注意,这个里面的n是通过读入的一个变量,通常情况会有一个最大范围,例如:n不会超过。你总不能定义个整型变量吧?
面对上面这种需求,数组就派上了用场,利用数组,我们可以定义存放一组数据的存储区,用法如下代码所示:
intarr[];
通过上述代码,我们很轻松的就定义了存储个整型变量的存储区arr。这里相当于向计算机申请了可以存储个整型变量的存储空间。第一个存储整型数据的内存空间,也就是第一个整型变量,就是arr[0],第二个整型变量是arr[1],以此类推。arr后面方括号里面的东西,我们称之为“数组下标”,数组下标从0开始,也就是说,代表个整型变量的数组,下标范围应该是0到,具体可以参考图1。
有了数组以后,你就可以轻松的完成读入n个整型数据的任务了,参考代码如下:
intn,arr[];
scanf("%d",n);
for(inti=0;in;i++)scanf("%d",arr);
代码中,第一行定义了一个整型变量n和一个最多存储个整型元素的数组空间。第二行接下来读入n的值,第三行利用循环结构循环n次,循环变量i取值从0到n-1,循环每次读入一个整型数据存放在arr里面。
这样一段程序执行完后,n个整型数据就被依次的存放在了arr[0]到arr[n-1]中。当你想在程序中使用第三个整型数据的时候,只需要访问arr[2]即可。当然,上述循环变量的取值范围也可以调整到1到n,这样做的话,相当于我们将n个整型数据存放在了arr[1]到arr[n]处。
2.字节与