2024-2025-1 20241325 《计算机基础与程序设计》
| 作业属于的课程:【计算机基础与程序设计:https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP】 |
| 作业的要求:https://www.cnblogs.com/rocedu/p/9577842.html#WEEK06 |
| 作业的目标:Polya如何解决问题 简单类型与组合类型 复合数据结构 查找与排序算法 算法复杂度 递归 代码安全 |
| 作业的网址: https://www.cnblogs.com/wangxianglong999/p/18523612 |
教材学习内容解决:
一、Polya的解题思路:
1.理解问题
2.拟定计划
3.执行计划
4.回顾
二、简单类型与组合类型:
1.特点的不同:
简单类型: 具有固定的大小和表示方式。例如,在许多编程语言中,整数类型通常占用一定数量的字节,并且以二进制补码的形式存储。
不能再被分解为其他更基本的类型。比如整数类型、字符类型、布尔类型等都是简单类型。
通常在内存中占据连续的存储区域,访问速度相对较快。
组合类型: 具有更复杂的结构,可以包含多个不同类型的元素。
通常需要更多的内存空间来存储,并且访问其中的元素可能需要一定的计算开销。
可以根据具体的需求进行灵活的定义和扩展。
2.使用区别: 简单类型适用于表示基本的数据值,而组合类型则可以用于表示更复杂的对象和数据结构。
三、复合数据结构
复合数据结构是由多种基本数据类型或其他复合数据结构组合而成的数据结构,它能够更加灵活地表示和处理复杂的数据。
Ⅰ常见的复合数据结构类型
-
数组
- 由相同类型的元素组成的有序集合。可以是一维数组、二维数组或多维数组。
- 特点:通过索引可以快速访问特定位置的元素,但大小通常在创建时确定,不易动态改变。
- 例如:一个存储整数的一维数组,可以用于记录一系列的成绩数据。
-
结构体
- 由不同类型的成员变量组成的复合数据类型。
- 特点:可以将不同类型的数据组合在一起,方便表示具有多个属性的对象。
- 例如:定义一个表示学生的结构体,包含学生的姓名(字符串类型)、年龄(整数类型)、成绩(浮点数类型)等成员变量。
-
链表
- 由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
- 特点:可以动态地添加和删除节点,适合频繁进行插入和删除操作的场景。
- 例如:实现一个链表来存储一系列整数,当需要添加新的整数时,可以在链表的任意位置插入新节点。
-
栈和队列
- 栈是一种后进先出(LIFO)的数据结构,而队列是一种先进先出(FIFO)的数据结构。
- 特点:栈常用于函数调用、表达式求值等场景;队列常用于任务调度、消息传递等场景。
- 例如:用栈来实现逆波兰表达式的求值,用队列来模拟银行排队系统。
-
树和图
- 树是一种层次结构的数据结构,每个节点可以有多个子节点。图是由顶点和边组成的非线性数据结构。
- 特点:树可以用于表示文件系统、组织结构等;图可以用于表示网络、社交关系等复杂的关系结构。
- 例如:用二叉树实现二叉搜索树,用于快速查找和插入元素;用图来表示城市之间的交通网络,以便进行路径规划。
Ⅱ、复合数据结构的优点
-
灵活性
- 可以根据具体需求组合不同类型的数据,更好地适应复杂的数据表示和处理要求。
-
可扩展性
- 可以方便地添加新的成员或修改现有结构,以满足不断变化的需求。
-
高效性
- 针对特定的问题,可以选择最适合的复合数据结构来提高数据处理的效率。
Ⅲ、复合数据结构的应用场景
-
数据库管理
- 数据库中的表可以看作是一种复合数据结构,由多个字段组成,用于存储和管理大量的数据。
-
操作系统
- 操作系统中的进程管理、内存管理等都涉及到各种复合数据结构的使用。
-
图形图像处理
- 图像可以用二维数组表示,图形的层次结构可以用树来表示。
-
算法设计
- 许多算法需要使用特定的复合数据结构来实现高效的计算,如排序算法、搜索算法等。
总之,复合数据结构在编程中起着重要的作用,它能够帮助我们更好地组织和处理复杂的数据,提高程序的效率和可读性。
四、查找和排序算法
查找和排序算法是计算机科学中非常重要的算法类型,它们在数据处理、数据库管理、搜索引擎等领域有着广泛的应用。
Ⅰ、查找算法
-
顺序查找
- 原理:从数据集合的一端开始,逐个检查每个元素,直到找到目标元素或遍历完整个集合。
- 特点:简单直观,适用于小型数据集合或无序数据集合。但对于大型数据集合,查找效率较低。
- 时间复杂度:在最好情况下,目标元素在第一个位置,时间复杂度为 O(1);在最坏情况下,目标元素在最后一个位置或不在集合中,时间复杂度为 O(n),其中 n 是数据集合的大小。
-
二分查找
- 原理:对于有序数据集合,每次将集合分成两部分,根据目标元素与中间元素的大小关系,确定在左半部分还是右半部分继续查找。
- 特点:查找效率高,适用于大型有序数据集合。但要求数据集合必须是有序的。
- 时间复杂度:时间复杂度为 O(log n),其中 n 是数据集合的大小。
-
哈希查找
- 原理:通过哈希函数将目标元素的关键值映射到一个特定的位置,然后在该位置进行查找。
- 特点:查找速度非常快,平均时间复杂度为 O(1)。但需要选择合适的哈希函数,以避免冲突。
- 时间复杂度:在理想情况下,时间复杂度为 O(1)。但在存在冲突的情况下,时间复杂度可能会增加。
Ⅱ、排序算法
-
冒泡排序
- 原理:重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。
- 特点:简单易懂,适用于小型数据集合。但效率较低,尤其是对于已经接近有序的数列。
- 时间复杂度:平均时间复杂度和最坏时间复杂度为 O(n²),其中 n 是数据集合的大小。最好时间复杂度为 O(n),当数据集合已经有序时。
-
快速排序
- 原理:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序。
- 特点:效率高,是实际应用中最常用的排序算法之一。但对于小规模数据集合,性能可能不如其他简单排序算法。
- 时间复杂度:平均时间复杂度为 O(n log n),其中 n 是数据集合的大小。最坏时间复杂度为 O(n²),当数据集合已经有序或逆序时。
-
归并排序
- 原理:将两个或多个有序的子序列合并成一个有序的序列。
- 特点:稳定,适用于大型数据集合。但需要额外的存储空间。
- 时间复杂度:时间复杂度始终为 O(n log n),其中 n 是数据集合的大小。
-
堆排序
- 原理:利用堆这种数据结构进行排序。首先将待排序的数列构建成一个大顶堆或小顶堆,然后将堆顶元素与最后一个元素交换,再调整堆,重复这个过程直到整个数列有序。
- 特点:效率高,不需要额外的存储空间。但实现相对复杂。
- 时间复杂度:时间复杂度为 O(n log n),其中 n 是数据集合的大小。
总之,查找和排序算法各有特点,在实际应用中需要根据具体情况选择合适的算法。对于小型数据集合,可以选择简单的算法;对于大型数据集合,需要考虑算法的效率和稳定性。
五、算法复杂度
算法复杂度是衡量算法效率的重要指标,它主要包括时间复杂度和空间复杂度。
Ⅰ、时间复杂度
-
定义
- 时间复杂度是指算法执行所需的时间与输入数据规模之间的关系。它反映了算法随着输入数据规模的增长,执行时间的增长趋势。
-
表示方法
- 通常用大 O 符号表示。例如,O(n)表示算法的执行时间与输入数据规模 n 成正比;O(n²)表示算法的执行时间与输入数据规模 n 的平方成正比。
-
常见时间复杂度类型及分析:
- O(1):常数时间复杂度,表示算法的执行时间不随输入数据规模的增长而增长。例如,访问数组中的特定元素,无论数组大小如何,时间都是固定的。
- O(log n):对数时间复杂度,表示算法的执行时间随着输入数据规模的增长而以对数方式增长。例如,二分查找算法,每次查找都将数据规模减半,所以时间复杂度为 O(log n)。
- O(n):线性时间复杂度,表示算法的执行时间与输入数据规模成正比。例如,遍历一个数组,时间与数组的大小成正比。
- O(n log n):线性对数时间复杂度,常见于一些高效的排序算法,如快速排序和归并排序。
- O(n²):平方时间复杂度,表示算法的执行时间与输入数据规模的平方成正比。例如,冒泡排序等简单的排序算法。
- O(2ⁿ):指数时间复杂度,表示算法的执行时间随着输入数据规模的增长呈指数增长。这种算法通常在输入数据规模较小时可行,但随着数据规模的增大,很快就会变得非常耗时。
Ⅱ、空间复杂度
-
定义
- 空间复杂度是指算法执行所需的存储空间与输入数据规模之间的关系。它反映了算法在运行过程中所占用的内存空间的增长趋势。
-
表示方法
- 同样用大 O 符号表示。例如,O(1)表示算法所需的存储空间是常数,不随输入数据规模的增长而增长;O(n)表示算法所需的存储空间与输入数据规模成正比。
-
常见空间复杂度类型及分析:
- O(1):常数空间复杂度,表示算法所需的存储空间不随输入数据规模的增长而增长。例如,一些只需要几个变量就能完成的算法。
- O(n):线性空间复杂度,表示算法所需的存储空间与输入数据规模成正比。例如,创建一个与输入数组大小相同的新数组。
- O(n²):平方空间复杂度,表示算法所需的存储空间与输入数据规模的平方成正比。这种情况相对较少见,通常出现在一些特殊的算法中。
在分析算法复杂度时,通常更关注时间复杂度,因为时间是算法执行效率的直接体现。但在某些情况下,空间复杂度也很重要,特别是在处理大规模数据或内存受限的环境中。
总之,算法复杂度是评估算法性能的重要指标,通过分析时间复杂度和空间复杂度,可以选择更高效的算法来解决实际问题。
六、递归
递归是一种编程技术,它允许函数在其定义中调用自身。
Ⅰ、递归的基本概念
-
定义
- 递归是一种解决问题的方法,它将问题分解为更小的子问题,直到子问题可以直接解决。然后,通过组合子问题的解来得到原始问题的解。
-
组成部分
- 递归函数通常由两部分组成:基本情况和递归情况。
- 基本情况是指可以直接解决的最小子问题。当函数遇到基本情况时,它不再进行递归调用,而是直接返回结果。
- 递归情况是指将问题分解为更小的子问题,并通过递归调用函数来解决这些子问题。
Ⅱ、递归的工作原理
-
调用过程
- 当函数调用自身时,程序会创建一个新的函数调用栈帧,用于存储函数的局部变量、参数和返回地址。
- 每次递归调用都会创建一个新的栈帧,直到达到基本情况。
- 当函数遇到基本情况时,它开始返回结果,并逐步弹出栈帧,将子问题的解组合起来,最终得到原始问题的解。
-
优点
- 递归可以使代码更加简洁和易于理解,特别是对于一些具有递归性质的问题,如树的遍历、阶乘计算等。
- 递归可以将复杂的问题分解为简单的子问题,从而更容易解决。
-
缺点
- 递归可能会导致栈溢出错误,特别是当递归深度较大时。因为每次递归调用都会创建一个新的栈帧,占用一定的内存空间。
- 递归的执行效率通常比非递归算法低,因为它需要额外的栈空间和函数调用开销。
Ⅲ、递归的应用场景
-
数学计算
- 计算阶乘、斐波那契数列等。
- 例如,计算阶乘可以用递归的方式实现:
factorial(n) = n * factorial(n-1)
,其中基本情况是factorial(0) = 1
。
-
数据结构操作
- 树的遍历、图的搜索等。
- 例如,二叉树的前序遍历可以用递归的方式实现:先访问根节点,然后递归遍历左子树和右子树。
-
问题求解
- 汉诺塔问题、八皇后问题等。
- 这些问题通常具有递归性质,可以通过递归的方式来求解。
总之,递归是一种强大的编程技术,但在使用时需要注意递归深度和执行效率等问题。在实际应用中,应根据具体情况选择是否使用递归,或者结合其他编程技术来解决问题。
七、代码安全
代码安全是软件开发中至关重要的一个方面,它涉及保护软件系统免受各种恶意攻击和漏洞的影响。
Ⅰ、代码安全的重要性
-
保护用户数据
- 确保用户的敏感信息,如个人身份信息、财务数据等,不被未经授权的访问、窃取或篡改。
- 防止数据泄露可能导致的严重后果,如身份盗窃、财务损失和声誉损害。
-
维护系统稳定性
- 防止恶意代码注入、缓冲区溢出等攻击,这些攻击可能导致系统崩溃、服务中断或性能下降。
- 确保软件系统能够持续稳定地运行,为用户提供可靠的服务。
-
遵守法律法规
- 许多国家和地区都有关于数据保护和信息安全的法律法规,确保代码安全是遵守这些法规的必要条件。
- 避免因违反法律法规而面临的法律责任和罚款。
Ⅱ、常见的代码安全问题
-
输入验证漏洞
- 未能对用户输入进行充分的验证和过滤,可能导致 SQL 注入、跨站脚本攻击(XSS)等安全问题。
- 例如,在 Web 应用中,如果对用户输入的表单数据没有进行严格的验证,攻击者可以通过构造恶意的输入来执行 SQL 查询或在网页中插入恶意脚本。
-
缓冲区溢出
- 当程序向缓冲区写入数据时,如果写入的数据超过了缓冲区的大小,就可能导致缓冲区溢出。
- 攻击者可以利用缓冲区溢出漏洞来执行恶意代码或获取系统权限。
-
权限提升漏洞
- 程序中存在的权限提升漏洞可能允许攻击者以较低权限的用户身份执行代码,从而获得更高的权限。
- 例如,在操作系统中,如果一个程序存在权限提升漏洞,攻击者可以利用这个漏洞来获取管理员权限。
-
代码注入漏洞
- 允许攻击者将恶意代码注入到程序中执行,可能导致严重的安全问题。
- 例如,在动态脚本语言中,如果对用户输入的脚本没有进行严格的过滤,攻击者可以注入恶意脚本并执行。
Ⅲ、提高代码安全的方法
-
输入验证和过滤
- 对用户输入进行严格的验证和过滤,确保输入的数据符合预期的格式和范围。
- 可以使用正则表达式、白名单和黑名单等技术来进行输入验证。
-
安全编码规范
- 遵循安全编码规范,如避免使用不安全的函数、正确处理错误和异常等。
- 例如,在 C 和 C++语言中,应避免使用容易导致缓冲区溢出的函数,如 strcpy 和 sprintf。
-
代码审查
- 进行定期的代码审查,以发现潜在的安全漏洞和错误。
- 代码审查可以由开发团队内部进行,也可以邀请外部安全专家参与。
-
安全测试
- 进行各种安全测试,如漏洞扫描、渗透测试等,以发现软件系统中的安全漏洞。
- 安全测试可以帮助开发团队在软件发布之前发现和修复安全问题。
-
权限管理
- 正确管理用户权限,确保用户只能访问他们被授权的资源。
- 可以使用访问控制列表(ACL)、角色-based 访问控制(RBAC)等技术来管理用户权限。
总之,代码安全是软件开发中不可忽视的一个方面。开发团队应该采取一系列措施来提高代码的安全性,保护用户数据和系统的稳定性。
苏格拉底式提问:
代码调试中的问题和解决过程
- 问题1:设置函数的时候无法使其赋值到变量上
- 问题1解决方案:将printf改成了return,就可以将返回值赋给变量
- 问题2:容易出现一些小的语法错误
- 问题2解决方案:边写边改
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 | |
第五周 | 500/1300 | 2/3 | 30/90 | |
第六周 | 300/800 | 2/5 | 30/90 |