C 编程/初学者练习
- 变量名可以以数字开头吗?
- 变量名可以以印刷符号开头吗(例如 #、*、_)?
- 举一个 C 变量名的例子,它将不起作用。为什么它不起作用?
- 列出 C 中至少三种数据类型。
- 在您的计算机上,每个数据类型需要多少内存?
- 哪些数据类型可以互换使用?为什么?
- 这些使用是否存在任何限制?
- 如果有,它们是什么?
- 是否需要做任何特殊的事情才能使用替代数据类型?
- 我们用于数据类型的名称(例如“int”、“float”)可以作为变量使用吗?
- 您将如何将值 3.14 赋值给名为 pi 的变量?
- 是否可以将int赋值给double?
- 反过来是否可行?
- 新学生常犯的一个错误是反转赋值语句。假设您想将变量“pi”中存储的值赋值给另一个变量,例如“pi2”。
- 正确的语句是什么?
- 反过来是什么?这是否是一个有效的 C 语句(即使它给出错误的结果)?
- 如果您想将一个常量值(如 3.1415)赋值给“pi2”
- a. 正确的语句将是什么样子?
- b. 反过来将是一个有效的 C 语句还是无效的 C 语句?
1. 编写一个程序,提示用户输入一个字符串(选择最大长度),并打印其反转。
2. 编写一个程序,提示用户输入一个句子(同样,选择最大长度),并将每个单词单独打印在一行上。
1. 编写一个函数,输出一个高度和宽度为n的直角等腰三角形,因此n = 3将看起来像
* ** ***
2. 编写一个函数,输出一个高度为2n-1,宽度为n的侧向三角形,因此n = 4的输出将为
* ** *** **** *** ** *
3. 编写一个函数,输出一个高度为n,宽度为2n-1的直角三角形;n = 6的输出将为
* *** ***** ******* ********* ***********
1. 构建一个程序,其中控制从 main 传递到四个不同的函数,并进行 4 次调用。
2. 现在在 main 中创建一个 while 循环,并在其中包含函数调用。在循环开始时请求输入。如果用户按下 Q,则结束 while 循环。
3. 接下来添加条件语句,以便在用户输入数字时调用函数,例如 1 调用 function1,2 调用 function 2 等。
4. 让 function 1 调用 function a,function a 调用 function b,function b 调用 function c
5. 绘制一个程序流程图,使用箭头指示控制流向。
1. 编写一个函数来检查整数是否为负数;声明应类似于 bool is_positive(int i);
2. 编写一个函数,将浮点数提高到整数幂,例如,当您使用它时
float a = raise_to_power(2, 3); //a gets 8
float b = raise_to_power(9, 2); //b gets 81
float raise_to_power(float f, int power); //make this your declaration
1. 编写一个函数来计算一个数是否为素数。如果它是素数则返回 1,如果不是素数则返回 0。
2. 编写一个函数来确定小于 n 的素数数量。
3. 编写一个函数来使用牛顿法查找平方根。
4. 编写函数来计算三角函数。
5. 尝试编写一个随机数生成器。
6. 编写一个函数来确定 2 到 100 之间的素数。
1. 编写一个 C 程序,使用给定长度 n 生成一个随机整数数组,并使用归并排序算法对其进行递归排序。
- 归并排序算法是一个递归算法。
- 对一个元素数组进行排序很容易。
- 对两个一个元素数组进行排序,需要合并操作。合并操作将两个已排序的数组视为列表,并比较列表的头部,哪个头部较小,该元素就被放在已排序的列表上,并且该列表的头部就被剔除,因此下一个元素成为该列表的头部。这样做直到其中一个列表耗尽,然后将另一个列表复制到已排序列表的末尾。
- 递归发生是因为合并两个一个元素数组会产生一个两个元素的已排序数组,该数组可以与以相同方式产生的另一个两个元素的已排序数组合并。这会产生一个已排序的 4 元素数组,同样适用于另一个已排序的 4 元素数组。
- 因此,基本的归并排序是检查要排序的列表的大小,如果它大于 1,则将数组分成两部分,并对两个部分再次调用归并排序。之后,在大小相同的临时空间中合并两个部分,然后将最终的已排序数组复制回原始数组。
2. 二叉堆
- 二叉最大堆或最小堆是一种有序结构,其中某些节点保证大于其他节点,例如父节点与两个子节点。二叉堆可以存储在一个数组中,其中,
- 给定一个位置i(父节点),i*2是左子节点,i*2+1是右子节点。
- (C 数组从位置 0 开始,但 0 * 2 = 0,0 *2 + 1= 1,这是不正确的,因此将堆从位置 1 开始,或者为父节点到子节点的计算添加 1,并为子节点到父节点的计算减去 1)。
- 尝试使用铅笔和纸张对其进行建模,使用 10 个随机未排序的数字,并将它们中的每一个插入到一个包含 10 个元素的“堆排序”数组中。
- 要插入堆,请尾部添加,然后如果更高,则交换父节点,直到父节点更高。
- 要删除堆的顶部,请将尾部移到顶部,然后推迟更高子节点或下沉,直到没有子节点更高。
- 尝试使用笔和纸来计算数字 10、4、6、3、5、11。
- 答案是 11、5、10、3、4、6。
- 练习:现在尝试使用从尾到顶和向下筛选(或交换更高子节点)的方法移除 11, 5, 10, 3, 4, 6 中的每个顶部元素,以获得数字
降序排列。
- 优先级队列允许元素以优先级插入,并根据优先级提取。(这可能很有用,如果元素具有配对结构,一部分是键,另一部分是数据。否则,它只是排序机制)。
- 练习:使用上述插入到尾部/挑战父节点和删除头部/最后到头部/延迟更高子节点技术,实现堆排序或优先级队列。
迪杰斯特拉算法是一种使用优先级队列的搜索算法。它从将起始节点插入优先级队列中,优先级值为 0 开始。所有其他节点都以优先级值为 N 插入。每个节点都有一个指向其他节点的邻接列表、到起始节点的当前距离和指向用于计算当前节点的先前节点的先前指针。邻接列表的替代方案是邻接矩阵,它需要 n x n 布尔邻接关系。
该算法基本上迭代优先级队列,移除头部节点,检查相邻节点,并使用头部节点距离与相邻节点距离的总和更新距离。
在更新每个节点之后,对该节点使用额外的操作 **“更新优先级”**
当节点的距离小于其父节点(对于此优先级队列,父节点的距离小于子节点)时,节点将与父节点交换。
在此之后,当节点的距离大于一个或多个子节点的距离时,它将与距离最小的子节点交换,因此距离最小的子节点成为距离更大的兄弟节点的父节点,以及距离更大的当前节点的父节点。
通过更新优先级,当前节点的相邻节点的回溯指针将更改为当前节点。
当目标节点成为移除的当前节点时,该算法结束,并且可以通过跟踪回溯指针记录到起始节点的路径,然后执行诸如快速排序分区之类的操作来反转数组的顺序,以给出从起始节点到目标节点的最短路径。
3. 编写一个 C 程序,使用快速排序分区交换算法递归排序。
- 你可以使用 Q1 中的“驱动程序”或随机数测试数据。在归并排序中。这被称为“重用”,在一般情况下是鼓励的。
- 重用的优势是编写时间、调试时间和测试时间更少。
- 分区交换的概念是随机选择一个分区元素,并将需要排序的所有内容放入 3 个等价类
类:小于分区值的元素,分区元素,以及大于(和等于)分区值的元素。
- 这可以在不分配超过一个用于交换两个元素的临时元素空间的情况下完成。例如,用于整数数据的临时整数。
- 但是,使用原始数组空间应该放置分区元素的位置是未知的。
- 这通常通过将分区放置在要排序的数组的末尾来实现,然后放置两个指针,一个在数组的开头,
另一个在分区元素旁边的元素上,并重复扫描左指针向右,右指针向左。
- 左扫描在找到大于或等于分区的元素时停止,右扫描在找到小于分区值的元素时停止,
并交换它们,这会使用额外的临时空间。
- 如果左扫描到达分区元素,它将始终停止,它是最后一个元素;这意味着整个数组都小于分区值。
- 如果右扫描到达第一个元素,则整个数组都大于分区,需要对其进行测试,否则扫描不会停止。
- 当左指针和右指针交叉时,外循环退出。在交换之前应测试指针交叉和外循环退出
否则,右指针可能会交换之前由左指针扫描过的小于分区元素。
- 最后,需要将分区元素放置在左分区和右分区之间,一旦指针交叉。
- 在指针交叉时,左指针可能停留在分区元素在数组中的最后一个位置,而右指针没有越过
最后一个元素之前的元素。当所有元素都小于分区时,就会发生这种情况。
- 如果选择右指针与分区交换,则会导致错误状态,其中左数组的最后一个元素将小于分区元素的值。
- 如果选择左指针与分区交换,则左数组将小于分区,并且分区将与值大于分区或分区本身的元素交换。
- 必须检查对 2 元素 **无序** 数组进行快速排序的极端情况。
- 左指针停留在第一个 **无序** 元素上。右指针从第一个 **无序** 元素开始,但外循环退出,因为它是最左边的元素。然后,分区元素与左指针的第一个元素交换,现在这两个元素 **有序**。
- 在 2 元素 **有序** 数组的情况下,最左边的指针跳过第一个元素,它小于分区,并在分区上停止。右指针从第一个元素开始,并退出,因为它是在第一个位置。指针已经交叉,所以外循环退出。分区与自身交换,因此保持了顺序。
- 完成交换后,应递增左指针并递减右指针,因此不会再次扫描相同的位置,因为可能导致无限循环(可能是在左指针在元素等于或大于分区时退出,而右元素等于分区值时)。一种实现方法,Sedgewick,以左指针减一和右指针
加一作为预期的初始扫描位置,并使用前递增和前递减运算符,例如 ( ++i, --i )。