C++基础教程
——
作业及参考答案全部汇总文档
节4指针和数组阶段作业

最新版本V2.0
王道C++团队
COPYRIGHT ⓒ 2021-2024. 王道版权所有

基础题篇

Gn!

下面都是一些基础的语法、概念编程练习题。

数组与指针基础练习题1

Gn!

以下题目功能,都要求编写函数将数组作为参数传递来实现:

1.编写函数交换数组中两个下标的元素。函数声明如下:void swap(int *arr, int i, int j) 。要求不使用[]运算符,将[]还原成解引用运算符和指针加法来完成。

2.数组元素的逆序。要求使用[]运算符以及纯粹指针操作两种方式来完成。

3.数组元素求和。要求使用"*p++"语法结构来完成数组元素的累加 。

4.给定一个int数组以及一个目标值target,请编写函数找到这个目标值的下标,要求该函数没有返回值。(目标元素在数组中唯一,不考虑多次出现目标元素的情况)

5.编写一个函数,检查一个整数数组是否是回文,即正序与倒序相同。例如[1,2,3,2,1]就是回文的。要求使用指针的算术运算,不要使用取下标[]运算符。

6.给定一个非空整数数组src,再给定一个足够长的dest数组。编写一个函数 copy_array,使用 *p++ 复制src数组到dest数组。

注意:这道题目要把代码写得尽量简洁!!

7.给定一个整数数组,将所有奇数移到数组前面,偶数移到数组后面。(扩展题)

参考代码如下:

参考代码:

第一题非常简单,无非就是将"[]"运算符都还原成解引用的形式,参考代码如下:

第二题也非常简单,是上课讲过的,参考代码如下:

第三题参考代码如下:

第四题参考代码:

第五题参考代码:

第六题参考代码:

第七题参考代码,需要使用双指针法求解:

以上。

数组与指针基础练习题2

Gn!

第一题:

查找数组的最大值和最小值,但要将最大值作为返回值返回,最小值则依靠传入的指针完成赋值。

要求不能使用"[]"运算符。

函数的声明如下:

第二题:

求平均值,给定一个double数组,求平均值,并且返回。

要求使用while循环遍历数组,然后配合"*p++"的语法实现。

函数的声明如下:

参考代码如下:

参考代码:

第一题和课堂上讲的题目实现非常类似,参考代码如下:

第二题参考代码:

以上。

数组与指针基础练习题3

Gn!

编写函数,查找一个int数组中的最大元素和第二大元素,并将它们分别存放在由 largest 和 second_largest 指向的变量中。

按照下面的函数声明来实现这个函数。

注意:为了简化实现,数组不存在重复元素,请不要考虑存在重复元素的情况。

参考代码如下:

参考代码:

以上。

数组与指针基础练习题4

Gn!

基于以下函数声明,实现函数:

形参中的 total_sec 表示从凌晨00:00:00开始,到现在时间的秒数。

请将 total_sec 转化以时(0-23)、分(0-59)、秒(0-59)表示的时间,并存放到函数外部由指针 hour, minute, second 指向的变量中。

并在函数调用的位置,打印出当前的时间。

测试用例:

total_sec = 0,表示时间 00:00:00

total_sec = 9527,表示时间 02:38:47

total_sec = 3001,表示时间 00:50:01

参考代码如下:

参考代码如下:

以上。

扩展题篇

Gn!

以下题目都属于扩展题。

扩展:数组分区思想

Gn!

数组分区(Partitioning)是一种将数组元素重新排列的操作,使得符合某种条件的元素位于一侧,而不符合条件的元素位于另一侧。

数组分区在很多算法的实现当中,都是非常重要和关键的步骤,最典型的例子就是快速排序算法的实现。

除此之外,数组分区的应用还包括:

  1. 将整数数组分为奇数和偶数两部分,比如移动奇数到数组前部,偶数到后部。

  2. 分离负数和正数,将所有负数移至数组的一端,正数移到另一端。

  3. 字符串中删除某个字符。

  4. 荷兰国旗问题。

  5. ...

这里我们就以int数组实现奇偶分区来探讨一下数组分区的思想以及实现。

题目:

给定一个整数数组,将所有奇数移到数组前面,偶数移到数组后面。

首先,实现数组的分区操作,最容易想到且容易实现的应该是——利用临时数组实现分区。

从不使用额外空间和性能优化的角度出发,我们还有一种非常优秀的实现方式——双指针法。

所谓双指针法就是利用两个指针(数组可以基于双索引),来实现某些操作。双指针法在求解线性数据结构(数组/字符串/链表)的相关算法问题时,特别常用。

比如:

  1. 数组的分区操作。数组快速排序,数组逆序、二分查找、回文检查等都可以基于双指针法实现。

  2. 链表操作中的快慢指针法。可以用于求链表的中间结点,以及检查单链表是否有环等。

  3. 字符串操作中的删除某个字符,也可以基于双指针实现。

下面我们将采用两种双指针法来实现数组奇偶分区。

方式一:双指针夹逼交换元素法

参考代码如下:

方式二:双索引单向分区法

参考代码如下:

以上。

扩展:合并两个有序子数组

Gn!

给定两个有序的整数子数组,然后将它们合并到一个足够长的新数组中,合并后的结果数组也应当是有序的。

比如:

数组1:[1, 3, 5, 6, 7]

数组2:[2, 3, 4, 8]

合并后的结果数组3:[1, 2, 3, 3, 4, 5, 6, 7, 8]

提示:整个合并的过程类似"穿针引线",利用两个索引逐一比较两个数组的元素大小,然后把较小元素放入数组3中。"穿针引线"结束,最终:

  1. 一定会有一个数组元素被全部被赋值到数组3当中了

  2. 另一个数组元素一定还有剩余

那就把剩余数组的元素全部复制到数组3的后面即可。

基于上述思想,参考代码如下:

参考代码:

以上。

扩展:分离非负数以及正数

Gn!

给定一个整数数组,请将所有非正数(包含负数和0)全部移到数组开头,正数则全部移到数组末尾,要求原地完成,不使用额外内存空间。

比如:

数组[1, -2, 3, 0, -9, 0, 10, 3]

最终分组完成后的效果应该是[非正数(包含0), 正数](稳定性不做要求)

提示:仍然可以基于双指针单向分区或夹逼法求解。

参考代码如下:

参考代码:

解法一:双索引单向分区法

解法二:双索引双向夹逼交换元素法

以上。

扩展:荷兰国旗问题

Gn!

荷兰国旗问题(也称为三色排序问题)是一个计算机科学中的经典问题,常用于讨论快速排序算法的三向分区(three-way-partitioning)策略。

这个问题来源于荷兰国旗的三种颜色:红色、白色和蓝色,目标是将含有三种颜色的条带(通常用0, 1, 2来代表三种颜色)重新排序,使得同一颜色的条带聚集在一起,并且顺序是红、白、蓝(或0、1、2)。

现在给定一个整型数组,其中包含不确定数量的三个元素0、1、2,请将该整数数组分区为三个部分:0在前面,1在中间,2在最后面。

举例:

整型数组为:[0, 1, 2, 2, 1, 0, 0, 2, 1, 1, 0, 2]

分区后的结果是:[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]

由于进行的是三向分区,那么单纯的双指针法就无法实现了,这时要使用"三指针法"。其算法的思路是:

  1. 创建一个"左索引left"指向数组左边界(首元素),创建一个"右索引right"指向数组的右边界(尾元素),创建一个"中间索引mid"开始时也指向数组首元素

  2. 利用中间索引mid来遍历整个数组。

  3. 左索引left的作用是:标记下一个0元素应该放置的位置(小于基准值的元素应放置的位置)

  4. 中间索引mid的作用是:标记下一个1元素应该放置的位置(等于基准的元素应放置的位置)

  5. 右索引right的作用是:标记下一个2元素应该放置的位置(大于基准的元素应放置的位置)

核心操作思路是:

遍历数组,条件是mid <= high,在这个过程中:

  1. 如果 mid 位置的元素是0,则需要将mid位置和left位置的元素交换,然后 leftmid索引都加1。这里为什么两个索引都需要加1呢?请看下图:

    荷兰国旗问题-图解1

  2. 如果 mid位置的元素是1,那么不需要任何交换,只需要mid索引加1即可。这个很好理解,不解释了。

  3. 如果mid位置的元素是2,则需要将mid位置和right位置的元素交换,然后 right 索引需要减1。这里的问题是:为什么mid索引就不需要加1了呢?仍然请看下图:

    荷兰国旗问题-图解2

遍历结束时,数组的三个分区就分区完成了。

参考代码实现如下:

参考代码如下:

以上。

扩展:三向分区负数、0以及正数

Gn!

如果你已经搞清楚了荷兰国旗问题,那么这个问题就比较简单了。

比如:

数组[1, -2, 3, 0, -9, 0, 10, 3]

最终分组完成后的效果应该是[负数, 0, 0, 正数](稳定性不做要求)

思路是:仍然是三个索引:

  1. left索引标记下一个负数放置的位置

  2. mid索引用于遍历数组,并且标记0元素放置的位置

  3. right索引用标记下一个正数放置的位置

核心操作逻辑是:

  1. 当mid索引发现一个负数时,交换left和mid索引位置的元素,并后移1位mid和left索引(原理是一样的)

  2. 当mid索引发现一个0时,不需要交换元素,仅需要mid索引后移1位

  3. 当mid索引发现一个正数时,交换right和mid索引位置的元素,仅后移1位right索引,mid索引不动。

当mid索引遍历完整个数组,这个三向分区操作就完成了。

参考代码实现如下:

参考代码如下:

以上。

The End