第20章总结
本节阅读量:章节回顾
函数参数可以通过值、引用或地址传递。对基本数据类型和枚举类型使用按值传递。对结构体、类,或需要函数修改参数的场景,使用按引用传递。传递指针或内置数组时使用按地址传递。
值可以按值、引用或地址返回。大多数情况下,按值返回即可;但在处理动态分配的数据、结构体或类时,按引用或地址返回可能很有用。如果通过引用或地址返回,请记住不要返回已经超出作用域的内容。
函数指针允许我们将函数传递给另一个函数。这对于允许调用者自定义函数的行为很有用,例如列表的排序方式。
动态内存分配在堆上。
调用栈跟踪从程序开始到当前执行点的所有活动函数(那些已被调用但尚未终止的函数)。局部变量在栈上分配。栈的大小有限。vector可以用于实现类似栈的行为。
递归函数是调用自身的函数。所有递归函数都需要终止条件。
命令行参数允许用户或其他程序在启动时将数据传递到程序中。命令行参数始终是C样式字符串,如果需要数值,则必须转换为数字。
省略号允许您向函数传递可变数量的参数。然而,省略号参数不进行类型检查,也不知道传递了多少个参数。这些细节需要由程序员手动跟踪。
Lambda函数是可以嵌套在其他函数中的函数对象。它们不需要名称,与算法库结合使用非常有用。
习题
问题 1
为下列各种情况编写函数原型。必要时应使用const。
a) 一个名为max()的函数,接受两个double,返回其中较大的一个。
查看答案
|
|
b) 一个名为swap()的函数,交换两个整数。
查看答案
|
|
c) 一个名为getLargestElement()的函数,接受一个动态分配的整数数组,并以「调用者可以修改所返回元素的值」的方式返回其中最大的数字(不要忘记长度形参)。
查看答案
|
|
问题 2
下面这些程序有什么问题?
a)
|
|
查看答案
doSomething()返回了局部变量的引用,而这个局部变量会在doSomething结束时被销毁。
b)
|
|
查看答案
函数sumTo()没有终止条件。变量value最终会变成负数,函数会无限递归下去,直到栈溢出。
c)
|
|
查看答案
这两个divide函数不是不同的函数,因为它们的名字和形参都相同。另外还存在除以0的隐患。
d)
|
|
查看答案
这个数组太大,无法在栈上分配,应当改为动态分配。
e)
|
|
查看答案
argv[1]可能不存在。即使存在,argv[1]也是一个字符串实参,不能通过赋值转换成整数。
问题 3
判断一个值是否存在于有序数组中的最佳算法叫做二分查找(binary search)。
二分查找的流程如下:
- 查看数组的中间元素(如果数组元素个数为偶数,则向下取整)。
- 如果中间元素大于目标元素,就丢弃数组较大的那一半(或者说在较小的一半中递归查找)。
- 如果中间元素小于目标元素,就丢弃数组较小的那一半(或者说在较大的一半中递归查找)。
- 如果中间元素等于目标元素,就返回中间元素的下标。
- 如果在丢弃整个数组后仍未找到目标元素,就返回一个表示「未找到」的哨兵值(这里我们用-1,因为它是无效的数组下标)。
由于每次迭代都能丢掉一半的数组,这个算法非常快。即使数组有一百万个元素,最多也只需要20次迭代就能确定某个值是否存在!不过它只能用于有序数组。
修改数组(例如丢弃数组中的一半元素)开销很大,因此通常我们不修改数组,而是用两个整数(min和max)保存我们当前关注的数组区间的最小和最大下标。
我们来看一个例子:给定数组{ 3, 6, 7, 9, 12, 15, 18, 21, 24 },目标值为7。起初min = 0、max = 8,因为我们要搜索整个数组(数组长度为9,因此最后一个元素的下标是8)。
- 第1趟)计算min(0)与max(8)的中点,为4。下标为4的元素值是12,大于目标值。由于数组是有序的,我们知道下标大于等于中点(4)的所有元素都太大了。因此min保持不变,把max设为3。
- 第2趟)计算min(0)与max(3)的中点,为1。下标为1的元素值是6,小于目标值。由于数组是有序的,我们知道下标小于等于中点(1)的所有元素都太小了。因此把min设为2,max保持不变。
- 第3趟)计算min(2)与max(3)的中点,为2。下标为2的元素值是7,正是目标值。因此返回2。
在C++20中,可以用std::midpoint计算中点。在C++20之前,需要自己计算中点——此时可以使用min + ((max - min) / 2)以避免溢出(当min和max都是正数时)。
给定下面这段代码:
|
|
a) 编写一个迭代版的binarySearch函数。
提示:当min下标大于max下标时,就可以确定目标元素不存在。
查看答案
|
|
b) 编写一个递归版的binarySearch函数。
查看答案
|
|
提示:
std::binary_search在值存在于有序列表中时返回true。
std::equal_range返回给定值第一个和最后一个元素的迭代器。
不要用这些函数来解本题,但将来如果需要二分查找,可以使用它们。