作业信息
这个作业属于哪个课程 | <班级的链接>(如2024-2025-1-计算机基础与程序设计) |
---|---|
这个作业要求在哪里 | <作业要求的链接>(如2024-2025-1计算机基础与程序设计第六周作业) |
这个作业的目标 | <写上具体方面>自学教材《计算机科学概论(第七版)》第7章,并完成云班课测试,《C语言程序设计》第5章并完成云班课测试 |
作业正文 | 本博客链接 |
教材学习内容总结
一.《计算机科学概论》第七版第七章主要围绕问题求解与算法设计展开,内容如下:
- 问题求解:
- “如何解决它”理论的应用:乔治·波利亚(George Polya)提出的“如何解决它”列表原本是用于数学问题求解,将其中的文字未知量换成问题、数据换成信息、定理换成解决方案,该理论可适用于各种类型的问题求解。这为计算机领域的问题解决提供了一种通用的思考框架。
- 提出问题:对于接受的任务和自己设置的任务,应提出不同的问题。对于接受的任务,会有“何时、为什么、在哪里”等一系列疑问;对于自己设置的任务,则是下意识地思考相关问题,比如对问题的了解程度、解决方案的形态、是否存在特例以及如何判断找到了解决方案等。
- 寻找熟悉的情况:在计算机领域,识别相似情况非常重要。因为很多问题会不断以不同形式出现,好的程序员看到以前解决的任务或子任务,会直接选用已有的解决方案,这样可以提高问题解决的效率。
- 算法的定义:算法是在有限的时间内用有限的数据解决问题或子问题的明确指令集合。它是问题求解的核心,是计算机程序的基础。
- 计算机问题求解过程:首先要理解问题,然后分析问题、确定主要任务、编写其余模块,最后根据需要进行重组和改写。这是一个不断迭代和完善的过程,直到找到满意的解决方案。并且,在编写代码之前,应该先设计好算法。
- 测试算法:类似于数学问题中的检查结果,测试算法是为了确保算法的正确性和有效性。通过等价测试等方法来验证算法是否能够正确地推出答案。
- 有简单变量的算法:
- 带有选择的算法:涉及到根据不同的条件执行不同的操作,通常使用 if...else 等语句来实现。这种算法可以根据输入的不同情况,选择不同的处理方式,增加了程序的灵活性。
- 带有循环的算法:包括计数控制循环、时间控制循环等。计数控制循环是根据循环次数来执行循环体;时间控制循环则是根据时间条件来控制循环的执行。此外,还介绍了利用循环来求平方根的算法。
- 复杂变量:
- 数组:数组是同构项目的有名集合,即数组中的元素具有相同的类型。可以通过单个项目在集合中的位置(索引)来访问数组中的元素,这使得对大量数据的存储和操作变得更加方便和高效。
- 记录:与数组不同,记录是异构项目的有名集合,其中的元素可以具有不同的类型。可以通过名字单独访问记录中的项目,这类似于结构体在编程语言中的作用,能够将不同类型的数据组合在一起进行管理。
- 搜索算法:
- 顺序搜索:按照顺序依次遍历数组或数据集合中的元素,查找目标元素。这种搜索算法简单直观,但对于大型数据集合效率较低。
- 有序数组中的顺序搜索:在有序数组中进行顺序搜索时,可以利用数组的有序性,在查找过程中根据当前元素与目标元素的大小关系,提前判断是否需要继续搜索,从而提高搜索效率。
- 二分检索:二分检索算法假设要检索的数组是有序的,每次比较操作都可以将数组减少一半,从而快速找到目标元素。这种算法的效率较高,适用于大型有序数据集合的搜索。
- 排序:
- 选择排序:一种简单的排序算法,每次从待排序的数据集合中选择最小(或最大)的元素,将其放置在已排序的序列的末尾,直到所有元素都被排序。
- 冒泡排序:属于选择排序的一种变体,通过不断比较相邻的元素并交换它们的位置,将较大(或较小)的元素逐步“冒泡”到数组的末尾,从而实现排序。
- 插入排序:将待排序的元素逐个插入到已排序的序列中,在插入过程中找到合适的位置,使得插入后的序列仍然保持有序。
- 递归算法:
- 子程序语句:介绍了子程序的概念,子程序是可以被其他程序调用的程序段,递归算法中会频繁使用子程序。
- 递归阶乘:以阶乘为例,讲解了递归算法的实现。递归算法是一种直接或间接调用自身的算法,在阶乘的计算中,通过不断地调用自身来计算较小数的阶乘,直到达到基础情况(例如 0 的阶乘为 1),然后返回结果。
- 递归二分检索:将递归算法应用于二分检索中,进一步提高了算法的灵活性和可读性。
- 快速排序:一种高效的排序算法,通过选择一个基准元素,将数组分为两部分,小于基准元素的部分和大于基准元素的部分,然后对这两部分分别进行递归排序,最终实现整个数组的排序。
二.
《C 语言程序设计》第五章通常围绕程序的三种基本控制结构之一的循环结构展开,以下是其主要内容总结:
- 循环结构概述:
- 循环结构是程序中用来描述有规律的重复操作的一种结构,其特点是在一定条件下重复执行某一部分程序。循环结构中的条件表达式称为“循环条件”,重复执行的操作语句称为“循环体”。
- 各种循环语句:
- while 语句:
- 这是一种当型循环结构,先判断表达式,当表达式的值为真(非 0)时,执行循环体语句;若表达式值为假(0),则结束循环。
- 循环体有可能一次都不执行。
- 常用于不知道具体循环次数,但能根据某个条件来判断是否继续循环的情况。
- do-while 语句:
- 先执行一次循环体,然后再判断表达式。所以无论表达式最初是否为真,循环体至少会执行一次。
- 表达式后面必须加分号。
- for 语句:
- for 语句功能强大、使用广泛,既可以解决循环次数未知的问题,更适合解决循环次数已知的问题。
- 一般形式为'for(表达式 1;表达式 2;表达式 3)循环体语句'。表达式 1 通常用于初始化循环变量;表达式 2 是循环条件;表达式 3 用于更新循环变量。三个表达式都可以是任意类型的表达式,并且都可以省略,但分号不能省略。
- 存在多种使用形式,例如省略表达式 1 可将循环变量赋初值放在 for 之前;省略表达式 2 会形成死循环(应避免这样使用);省略表达式 3 可在循环体语句中加入修改循环变量的值的语句。
- while 语句:
- 循环嵌套:
- 一个循环结构的循环体中包含另一个完整的循环结构,称为循环嵌套。外层循环每执行一次,内层循环都会完整地执行一轮。
- 外层循环可以包含两个以上的内层循环,但内层循环之间不能相互交叉。
- 常用于处理多维数组、表格等具有二维或多维结构的数据,以及需要多重循环控制的复杂逻辑。
- 控制循环的语句:
- break 语句:在循环语句和 switch 语句中,用于终止并跳出循环体或开关体,并且只能终止并跳出最近一层的结构。
- continue 语句:结束本次循环,跳过循环体中尚未执行的语句,直接进行下一次是否执行循环体的判断。continue 仅用于循环语句中。
教材中的问题与解决过程(先问AI)
问题1:return的作用
- 函数返回值
- 在C语言中,函数是一段可以重复使用的代码块,
return
语句主要用于从函数中返回一个值。当一个函数被调用时,它可以通过return
语句将计算得到的值传递回调用者。 - 例如,下面是一个简单的函数,用于计算两个整数的和并返回结果:
int add(int a, int b) { int sum = a + b; return sum; }
- 在这个函数
add
中,计算了a
和b
的和并存储在变量sum
中,然后通过return sum
将sum
的值返回给调用这个函数的地方。如果在主函数中调用add
函数,就可以得到这个和的值。 - 函数的返回值类型必须与函数定义时声明的返回值类型一致。在上面的例子中,函数
add
的返回值类型是int
,所以返回的sum
也必须是int
类型的值。
- 在C语言中,函数是一段可以重复使用的代码块,
- 结束函数执行
return
语句一旦执行,函数就会立即停止执行,并且将控制权交还给调用者。这意味着return
语句之后的函数代码不会再被执行。- 例如:
int divide(int a, int b) { if (b == 0) { printf("除数不能为0\n"); return -1; } int result = a / b; return result; }
- 在这个
divide
函数中,如果除数b
为0,就会打印错误信息并通过return -1
返回一个错误码,此时函数执行结束,后面的int result = a/b;
和return result;
都不会再执行。
- 返回指针
return
语句还可以用于返回指针。指针是一个变量,它存储的是另一个变量的地址。- 例如,下面是一个函数,用于返回一个数组的首地址:
int* getArray() { static int array[5] = {1, 2, 3, 4, 5}; return array; }
- 这个函数
getArray
返回了一个指向int
类型的指针,这个指针指向静态数组array
的首地址。需要注意的是,当返回指针时,要确保指针指向的内存是有效的,并且在函数返回后仍然可以访问。在这个例子中,使用了静态数组,因为静态数组在程序的整个生命周期内都存在,所以返回它的地址是安全的。
- 无返回值函数(
void
类型函数)中的return
- 对于
void
类型的函数,return
语句可以用于提前结束函数的执行,而不返回一个具体的值。 - 例如:
void printMessage() { printf("这是一条消息\n"); return; }
- 在这个
printMessage
函数中,return
语句可以省略,因为函数执行到最后也会结束。但是如果在函数中间想要提前结束函数,就可以使用return
语句。例如:
void processData(int data) { if (data < 0) { printf("数据不能为负数\n"); return; } // 对非负数据进行处理的代码 }
- 在这个函数中,如果
data
是负数,就会打印错误信息并通过return
语句提前结束函数,从而避免对负数数据进行不必要的处理。
- 对于
问题2:循环中注意的事项
- 循环条件的设定
- 避免死循环:循环条件是决定循环是否继续执行的关键因素。如果循环条件始终为真,就会导致死循环。例如,在
while
循环中,若写成while(1)
且循环体中没有可以跳出循环的语句(如break
),循环将无限执行下去。这种情况可能是因为编程疏忽,例如忘记更新循环条件中涉及的变量。 - 合理的边界条件:要明确循环的起始和结束条件。以
for
循环为例,在遍历一个长度为n
的数组arr
时,循环条件通常设为for(int i = 0; i < n; i++)
,这里i < n
就是合理的边界条件,确保循环能够正确地访问数组中的每个元素,而不会越界。如果写成i <= n
就会导致数组访问越界,可能会引发程序崩溃或产生不可预期的结果。
- 避免死循环:循环条件是决定循环是否继续执行的关键因素。如果循环条件始终为真,就会导致死循环。例如,在
- 循环变量的使用
- 正确初始化:循环变量需要在合适的位置进行初始化。在
for
循环中,循环变量的初始化通常在for
语句的第一部分完成,如for(int i = 0;...
。对于while
和do - while
循环,要在循环开始前手动初始化循环变量。例如,在while
循环中int i = 0; while(i < 10){...i++;}
,如果忘记初始化i
,程序可能会出现未定义行为。 - 适当更新:循环变量必须在循环体中得到及时更新,否则可能导致死循环。例如,在
for
循环for(int i = 0; i < 10;){...}
中,如果忘记在循环体中更新i
,循环条件i < 10
将永远满足,从而产生死循环。同时,更新循环变量的方式要符合循环的逻辑。比如在计算等差数列的和的循环中,循环变量可能按照固定的公差进行更新。 - 变量作用域:在
for
循环(C99及以上标准)中,循环变量的作用域仅限于循环内部。例如for(int i = 0; i < 10; i++){...}
,i
在循环外部是不可访问的。但在一些旧的编译器或者不符合C99标准的环境中,可能会有不同的情况,需要注意循环变量的作用域对程序其他部分的影响。
- 正确初始化:循环变量需要在合适的位置进行初始化。在
- 循环体内部逻辑
- 语句顺序:循环体中的语句执行顺序很重要。例如,在一个对数组元素进行操作的循环中,先进行元素读取,再进行元素修改的顺序可能会影响结果。假设有一个数组
arr
,在while
循环中int i = 0; while(i < 5){int temp = arr[i]; arr[i] = temp * 2; i++;}
,先读取元素到temp
,再修改数组元素,这样的顺序是合理的。如果顺序颠倒,可能会得到错误的结果。 - 避免复杂嵌套导致混乱:当有循环嵌套时,要清楚内层循环和外层循环的作用。例如,在打印九九乘法表时,通常会使用双层
for
循环,外层循环控制行数,内层循环控制列数。for(int i = 1; i <= 9; i++){for(int j = 1; j <= i; j++){printf("%d * %d = %d ", j, i, i*j);}printf("\n");}
,如果对循环嵌套的逻辑理解不清晰,可能会导致乘法表打印错误或者出现逻辑混乱。
- 语句顺序:循环体中的语句执行顺序很重要。例如,在一个对数组元素进行操作的循环中,先进行元素读取,再进行元素修改的顺序可能会影响结果。假设有一个数组
- 数据类型相关问题
- 数据溢出:在涉及数值计算的循环中,要注意数据溢出问题。例如,在计算阶乘的循环中,
int
类型的变量可能会因为数值过大而溢出。假设计算n
的阶乘,int result = 1; for(int i = 1; i <= n; i++){result *= i;}
,当n
较大时,result
可能会超出int
类型的表示范围。在这种情况下,可以考虑使用long long
类型或者其他更合适的数据类型来避免数据溢出。 - 浮点数精度:对于浮点数循环计算,可能会出现精度损失问题。例如,在一个累加小浮点数的循环中,由于浮点数在计算机内部是以二进制形式存储的,可能会出现精度损失。
float sum = 0.0f; for(int i = 0; i < 1000; i++){sum += 0.1f;}
,理论上sum
应该等于100.0f,但实际上可能会因为精度问题而出现偏差。
- 数据溢出:在涉及数值计算的循环中,要注意数据溢出问题。例如,在计算阶乘的循环中,
基于AI的学习
w:我在学习C语言循环的知识,请以苏格拉底的方式提问,一次一个问题
AI:好的,那我们开始。
首先,你知道循环在程序中的主要作用是什么吗?
w:简化程序
AI:循环是如何简化程序的呢?
w:减少对某段程序的重复使用
AI:那循环具体是怎么做到减少对某段程序的重复使用的呢?
w:重复进行某种指令
AI:循环中重复进行的指令是固定不变的吗?
w:是的
AI:如果循环中的指令一直固定不变,会不会在某些情况下导致问题呢?
w:可能陷入死循环
AI:那怎么避免陷入死循环呢?
w:明确退出的条件
AI:如何确定合适的退出条件呢?
w:可以确保循环结束
AI:那么如何确保循环一定能在合适的时候结束呢?
w:可以使用break或者函数
AI:“使用 break” 具体是在什么情况下使用呢?
w:如Switch循环中的每个case语句结束
AI:在 switch 语句中使用 break 来结束每个 case 是很常见的做法。但是在循环中使用 break,会不会带来一些潜在的问题呢?比如破坏了循环原本的逻辑完整性?
w:不会
AI:为什么不会破坏循环原本的逻辑完整性呢?
w:可以通过代码来确定结束的时刻
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第五周 | 900/1500 | 1/2 | 20/30 | |
第六周 | 1100/1600 | 1/4 | 18/38 | |
第七周 | 1100/1800 | 0/7 | 22/60 | |
第八周 | 1100/2100 | 0/9 | 30/90 |