2024-2025-1 20241307《计算机基础与程序设计》第八周学习总结
作业信息
这个作业属于哪个课程 | (2024-2025-1-计算机基础与程序设计) |
---|---|
这个作业要求在哪里 | (2024-2025-1计算机基础与程序设计第八周作业) |
这个作业的目标 | |
作业正文 | (2024-2025-1 学号20241307《计算机基础与程序设计》第八周学习总结) |
教材学习内容总结
计算机科学概论第七版第九章重点围绕数据结构展开深入探讨,其内容对理解计算机如何有效组织和处理信息起着关键作用。
一、数据结构基础
数据结构是数据元素以及数据元素之间的关系的集合,它关乎数据在计算机中的存储、组织和操作方式,其设计的优劣直接影响程序的效率与功能实现。
二、线性结构
数组
数组是一种连续存储的数据结构,所有元素在内存中依次排列。它的优点是能够通过下标快速随机访问元素,时间复杂度为 。例如,在一个存储整数的数组 int arr[100]; 中,可以直接通过 arr[5] 来访问索引为 5 的元素。
然而,数组的大小在创建时就需要确定,并且在运行过程中难以动态扩展。插入和删除操作相对复杂,在数组中间插入或删除一个元素时,需要移动其后的所有元素,平均时间复杂度为 ,其中 是数组的长度。
链表
链表由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。链表分为单链表、双链表和循环链表等类型。单链表中每个节点只有一个指向下一节点的指针;双链表则有向前和向后两个指针,方便双向遍历;循环链表的最后一个节点指向头节点,形成一个环。
链表的优势在于动态分配内存,插入和删除操作相对简单,只需修改相关节点的指针即可,时间复杂度为 (对于已知位置的插入和删除)。但链表的随机访问效率较低,需要从头节点开始遍历,平均时间复杂度为 。例如,要访问链表中的第 个元素,需要从头开始依次遍历 个节点。
三、受限线性结构
栈
栈是一种遵循后进先出(LIFO)原则的数据结构。它只有一个开口,数据的插入(入栈)和删除(出栈)操作都在栈顶进行。栈在计算机科学中有诸多应用,如函数调用时保存局部变量和返回地址、表达式求值等。例如,在计算表达式 3 + 4 * 2 时,运算符的处理可以借助栈来实现正确的运算顺序。
栈的基本操作包括 push(入栈)、pop(出栈)和 top(查看栈顶元素)等。其实现可以基于数组或链表,数组实现的栈在空间利用上相对固定,而链表实现的栈则更具灵活性。
队列
队列遵循先进先出(FIFO)原则,有队头和队尾两个端点。元素从队尾加入(入队),从队头取出(出队)。队列常用于任务调度、缓冲等场景,例如在操作系统中,进程等待 CPU 资源时可以按照队列的顺序依次执行。
队列的操作主要有 enqueue(入队)、dequeue(出队)和 front(查看队头元素)等。与栈类似,队列也可以用数组或链表来实现,数组实现的队列可能会面临假溢出等问题,需要采用循环队列等技术来优化;链表实现的队列则在动态管理上更具优势。
四、非线性结构
树
树是一种层次化的数据结构,由节点和边组成,有一个根节点,每个节点可以有零个或多个子节点。二叉树是树结构中的一种特殊类型,其每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树在搜索、排序等算法中有广泛应用,如二叉搜索树,其左子树的所有节点值小于根节点值,右子树的所有节点值大于根节点值,这使得查找、插入和删除操作的平均时间复杂度为 。
树的遍历方式有前序遍历(根节点 - 左子树 - 右子树)、中序遍历(左子树 - 根节点 - 右子树)和后序遍历(左子树 - 根节点 - 右子树)等,不同的遍历方式适用于不同的应用场景,如中序遍历二叉搜索树可以得到一个有序序列。
图
图是一种更为复杂的非线性数据结构,由顶点和边组成,可以表示对象之间的多对多关系。图分为有向图和无向图,有向图的边有方向,无向图的边没有方向。图在计算机网络、社交网络、交通规划等领域有大量应用。例如,在社交网络中,用户可以看作顶点,用户之间的好友关系可以看作边。
图的表示方法主要有邻接矩阵和邻接表。邻接矩阵是一个二维矩阵,若顶点 和顶点 之间有边,则矩阵中对应的元素为 1(或边的权重),否则为 0;邻接表则是为每个顶点建立一个链表,链表中存储与该顶点相邻的顶点信息。图的遍历算法包括深度优先搜索(DFS)和广度优先搜索(BFS),深度优先搜索沿着一条路径尽可能深地探索,直到无法继续或达到目标,然后回溯;广度优先搜索则逐层地对图进行探索,先访问离起始顶点最近的顶点。
通过对本章的学习,能够深入理解不同数据结构的特性、操作方式以及应用场景,从而在计算机程序设计和问题解决中,根据实际需求选择合适的数据结构,以提高程序的效率、优化资源利用并实现复杂的功能。
- 《C 语言程序设计》第 7 章:
- 函数的基本概念:
- 函数是为了实现模块化程序设计,将一个大的程序分解为多个相对独立且具有特定功能的模块,每个模块就是一个函数。函数具有特定的功能,完成特定的任务,方便程序的编写、调试和维护。
- 函数的定义:
- 无参函数:定义时函数名后面的括号为空或写
void
,函数体内包含声明部分和语句部分,用于完成特定的操作,例如function_name() { /* 函数体 */ }
或function_name(void) { /* 函数体 */ }
的形式。 - 有参函数:定义时函数名后面括号内有参数列表,指定函数接收的参数的名字和类型,以便在调用函数时向其传递数据,形式为
function_name(parameter_list) { /* 函数体 */ }
。
- 无参函数:定义时函数名后面的括号为空或写
- 函数的调用:
- 调用形式:通过函数名加上括号,并在括号内传入实际参数来调用函数。实际参数可以是常量、变量或表达式,函数调用时系统会把实参的值传递给形参。
- 调用过程:程序执行到函数调用语句时,会暂停当前函数的执行,将控制权转移到被调用函数,被调用函数执行完毕后,将结果返回给调用者,程序继续执行调用函数后的代码。
- 函数的声明和函数原型:
- 如果使用用户自己定义的函数,且该函数的位置在调用它的函数之后,需要在主调函数中对被调用函数进行声明。声明的作用是将函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。函数声明和函数定义中的函数首部基本相同,只是声明多一个分号。
- 特殊的函数特性:
- 嵌套调用:一个函数可以在其函数体内调用其他函数,形成函数的嵌套调用,增加了程序的复杂性和灵活性。
- 递归调用:函数直接或间接调用自身的过程称为递归调用。递归调用常用于解决具有重复子问题或可以逐步分解为相同子问题的问题,例如一些数学计算、树状结构的遍历等。
- 数组作为函数参数:数组可以作为函数的参数传递,传递时实际上传递的是数组的首地址,因此在被调用函数中可以对数组元素进行操作,从而影响到主调函数中的数组。
- 函数的基本概念:
教材学习中的问题和解决过程(先问 AI)
- 问题1:在使用数组时,可能会不小心访问超出数组范围的元素。
- 问题1解决方案:仔细检查数组的下标范围,确保循环或索引操作不会超出数组定义的大小。在上述示例中,将循环条件改为 i < 5 即可正确访问数组元素。
- 问题2:在处理字符数组表示的字符串时,可能忘记字符串结尾的 '\0' 字符,或者在字符串操作函数使用上出现错误。节点之间的关联方式。
- 问题2解决方案:在初始化字符数组表示字符串时,确保预留 '\0' 的位置并正确赋值。可以修改为 char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; 。或者使用字符串常量初始化,如 char str[] = "Hello"; ,编译器会自动添加 '\0' 。
- 问题3:在使用二维数组时,对行和列的索引顺序、内存布局等理解不清,导致数据访问错误。
- 问题3解决方案:明确二维数组在内存中是按行存储的,即先存储第一行的所有元素,再存储第二行,以此类推。在访问二维数组元素时,外层循环对应行索引,内层循环对应列索引,仔细检查循环中的索引使用是否正确,将上述代码中的 matrix[i][j] 改为 matrix[j][i] 以正确赋值。
基于AI的学习
代码调试中的问题和解决过程
- 问题1:指针未初始化导致错误访问内存
- 问题1解决方案:在使用指针之前,一定要先让指针指向有效的内存地址。可以通过动态内存分配(如 malloc 函数)或者让指针指向已存在的变量地址。
- 问题2:数组下标越界错误难以察觉
- 问题2解决方案:仔细检查数组循环的边界条件,确保下标不会超出数组的合法范围。在这个例子中,将循环条件 i <= 5 改为 i < 5 即可。另外,可以使用调试工具(如 gdb ),在循环中设置断点,观察每次循环时的下标值,以便及时发现问题。
- 问题3:函数传递数组参数时,在函数内修改数组未达到预期效果
- 问题3解决方案:在 C 语言中,当数组作为函数参数传递时,实际上传递的是数组的首地址(指针)。如果在函数内修改数组元素未生效,可能是因为代码存在其他逻辑错误或者对数组传递机制理解有误。在上述代码中,如果没有其他错误,应该是可以成功修改数组元素的。但如果发现没有修改成功,可以检查是否有其他地方对 myArray 进行了重新赋值或者存在代码逻辑错误,如在函数调用之前有其他错误操作覆盖了 myArray 的值。同时,可以通过调试工具单步执行函数调用过程,查看数组元素在函数内的修改情况以及函数返回后主函数中数组元素的值变化,以确定问题所在。
其他(感悟、思考等,可选)
学习 C 语言程序设计第七章与计算机科学概论第九章后,我深感编程世界的深邃与奇妙。C 语言中数组与指针的灵活运用,让我意识到内存管理的精妙与复杂,它犹如一把双刃剑,既能高效构建程序,稍有不慎也会引发难以察觉的错误。计算机科学概论则让我站在宏观角度,理解数据结构在计算机体系中的核心地位。这使我明白,编程不只是代码的堆砌,更是对数据的精心组织与逻辑构建,每一个变量、每一段代码都在塑造着数字世界的微观与宏观架构,学习之路漫漫,却充满探索的乐趣与收获的满足。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 4/4 | 18/38 | |
第三周 | 500/1000 | 5/7 | 22/60 | |
第四周 | 500/1300 | 6/9 | 30/90 | |
第五周 | 1000/1400 | 7/9 | 60/90 | |
第六周 | 1200/1500 | 8/9 | 70/90 | |
第七周 | 1400/1600 | 9/10 | 80/100 | |
第八周 | 1600/1700 | 10/11 | 100/100 |