第一章 C语言基础
一、数据类型
1.1 数据类型介绍
C语言提供了丰富的数据类型来描述生活中的各种数据。使用整型类型描述整数;使用字符类型来描述字符,使用浮点型类型来描述小数。所谓的“类型”,就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型,才知道怎么操作数据。下面盘点一下c语言提供的各种数据类型:
1.2 字符型
1.3 整型
1.4 浮点型
1.5 布尔型
布尔类型的使⽤得包含头⽂件:<stdbool.h>
布尔类型变量的取值是:true或者false。
二、常量与变量
2.1 常量
1. 常量是固定值,在程序执行期间不能改变。这些固定的值,又叫做字面量。
2. 常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。
3. 常量的值在定义后不能进行修改.
例:声明常量:const int MAX_VALUE = 100(区别宏定义# define)。。
2.2 变量
在C语言中,我们可以认为变量是指向某一个块数据可以被修改的内存的标识符并且需要在使用前声明和定义。例如:
- 声明变量:int num;
- 定义变量:int num = 10;
三、运算符和表达式
C语言为了方便运算,提供了一系列操作符,其中有一组操作符叫“算术操作符”。分别是:+、-、=、*、/、%,这些操作符都是双目操作符。除此之外还有一些其他类别的操作符:
- 关系运算符:、<=、>=、==、!=
- 逻辑运算符:&&、||、!
- 赋值运算符:=、+=、-=、*=、/=
而表达式由运算符和操作数组成,如result =num1+num2。
四、基本语句
4.1 if语句
if语句中的表达式需要为真,简单来说就是非零,因为if只会执行“真”,假如为假则会执行else语句的内容,所以if语句用于根据条件执行不同的代码块。
4.2 else/if语句和嵌套
在 if/else 语句中,else可以与另⼀个if语句连⽤,从而构成多重判断。
例如当一个人颜值大于等于80是很好看,小于等于60是一般,60到80是好看:
4.3 switch语句
switch语句可以实现分支结构,但是它可以看成一种特殊的if/else的语句,⽤于判断条件有多个结果的情况。可以理解为它把多重的if/else 改成更易⽤、可读性更好的形式。
4.4 break
break于跳出循环或switch语句。以switch为例:
在上述例子中如果没有break,如果输入的day的值是1,那么打印的结果会是1 2 3 4。而不是我们想要的一个单独的1。也就是说它不会跳出来。
4.5 continue
continue用于跳过当前循环的剩余代码,进入下一次循环迭代。如果把上述代码的break换成continue:
那么它的打印结果会是1 2 3 4 6 7 8 9 10。因为continue是继续的意思,也就是说上述代码中当i等于5那么跳出此次循环,继续下一次循环,因此就不会打印5。它和break一个很大的差别就是break是跳出所有循环,而continue是跳出此次循环继续下一次循环。
4.6 for循环
1.for循环用于重复执行一段代码,因为其足够的简洁,因此使用的频率较高,其基本形式如下:
表达式1 ⽤于循环变量的初始化
表达式2 ⽤于循环结束条件的判断
表达式3 ⽤于循环变量的调整
- 再按照打印一到十来举例:
4.7 while循环
while 循环在循环开始前判断条件是否满足,然后重复执行和if语句十分类似,其的形式是:
只有当表达式为真的时候该循环才会继续下去。
4.8 do while语句
不同于for循环和while循环,do-while 循环先执行一次代码块,然后再执行while 后的判断表达式,若表达式为真,就会进行下⼀次,若表达式为假,则不再继续循环。其基本形式如下:
4.9 goto语句
用于无条件跳转到代码中的标签位置,应避免滥用。
上述代码中跳过了“printf("2\n")”这一行代码,因此只会打印1 3这两个V
goto语句如果使用的不当,就会导致在函数内部随意乱跳转,打乱程序的执行流程。但是goto语句的使用也会带来一定的便利,因此对于goto语句的使用要慎重。
五、c语言中的函数
5.1函数的概念
函数是一段完成特定任务的代码块,可以重复调用。函数通常由函数头和函数体组成。函数声明用于在使用函数前声明函数的原型,函数定义则包含函数的实际实现。
5.2 函数的声明和定义
5.3 函数的传参
函数接受参数,用于传递数据给函数。形式参数(形参)在函数声明和定义中声明,实际参数(实参)函数调用时提供。参数传递可以是值传递或指针传递。
5.4 函数的返回值
函数可以返回一个值,表示函数的输出。使用 return 语句返回值。
5.5 函数的递归
递归函数是指调用自己的函数。递归必须有一个终止条件,否则会导致无限递归。
5.6 其他知识
函数的重载、内联函数、函数指针、标准库函数、函数库……
六、数组
6.1 数组的概念
数组是⼀组相同类型元素的集合;从这个概念中我们就可以发现2个有价值的信息:数组中存放的是1个或者多个数据,但是数组元素个数不能为0。数组中存放的多个数据,类型是相同的。数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。
6.2 定义与初始化
使用方括号[ ]定义数组,在定义时初始化,例:
注意;上述定义中,数组的类型是:int add[5]。并且无论是哪种数组,它们的索引都是从0开始的。
6.3 一维数组
一维数组就是在一个数组内可以存入多个数值,例如a[10],那么a数组内存着10个数,编号从0开始,int a[10]={},其中a中的数组为int类型,char a[],其中为char类型。一般通过for循环语句对数组进行初始化。
6.4 多维数组
数组的元素都是内置类型的,如果我们把一维数组做为数组的元素,这时候
就是二维数组,二维数组作为数组元素的数组被称为三维数组,二维数组以上的
数组统称 为多维数组。多维数组是数组的数组,用于存储表格型数据。多维数组举例:
6.5 数组与数组指针
数组的名称就是数组的指针,不需要格外用&符号。例如,int* a = b,其中int b[10]={},a=b[0]的地址,a+1表示的是b[1]的值,a+2表示的是b[2]的值,以此类推。
七、指针
7.1 基本概念
通俗来讲,指针就是指向某个参数的地址的,指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。
7.2 指针与函数参数的传递
函数可以通过指针参数修改调用者传递的变量。
7.3 指针数组
指针数组是存储指针的数组,可以用于存储不同类型的数据。
7.4 数组指针
数组指针是指向数组的指针,可以用于遍历多维数组。
7.5 指针的运算
指针可以进行运算,如加法和减法,指针加一,指向下一个元素的位置。
7.6 指针与动态内存的分配
使用 malloc 函数动态分配内存,返回指向分配内存的指针,使用 free 函数释放动态分配的内存。
7.7 总代码示例
八、字符串
8.1 字符串表示和概念
字符串是字符的数组,以空字符 '\0' 结尾, 使用双引号 " 来表示字符串,如 "Hello, World!"。
8.2 字符串的初始化和访问
字符串可以通过字符数组或指针初始化,使用下标访问字符串中的字符,下标从0开始。
8.2 字符串库函数 – strlen
strlen 函数用于获取字符串的长度(不包括结尾的空字符)。
8.4 字符串库函数 - strcpy 和 strncpy
strcpy 函数用于复制字符串,strncpy 函数用于复制指定长度的字符串。
8.5 字符串库函数 - strcat 和 strncat
strcat 函数用于拼接字符串,strncat 函数用于拼接指定长度的字符串。
8.6 字符串库函数 - strcmp 和 strncmp
strcmp 函数用于比较字符串,返回0表示相等,strncmp 函数用于比较指定长度的字符串。
8.7 字符串库函数 - strchr 和 strrchr
strchr 函数用于查找字符在字符串中第一次出现的位置,strrchr 函数用于查找字符在字符串中最后一次出现的位置。
8.8 字符串库函数 – strstr
strstr 函数用于查找子字符串在字符串中第 一次出现的位置。
8.9 字符串库函数 – strtok
strtok 函数用于将字符串拆分为子字符串,需要连续调用,第一次传入原字符串,后续传入NULL。
8.10 总代码示例
九、结构体
9.1 基本概念
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
9.2 结构体的用法
主要有初始化和访问、嵌套、函数参数传递、大小与对齐几个方面,结构体是一种复合数据类型,它允许将不同的数据类型组合在一起。在初始化结构体时,可以为每个成员变量指定初始值,这可以通过直接列出值、使用点操作符指定每个成员的值,或者使用复合字面量来完成。访问结构体成员时,使用点操作符来获取或修改成员的值。结构体可以嵌套,即一个结构体可以包含另一个结构体作为其成员,这使得数据组织更加灵活。当结构体作为函数参数时,可以通过值传递或引用传递(指针传递)的方式进行,值传递不会改变原始数据,而引用传递则可以修改原始数据。结构体的大小和对齐是内存布局相关的属性,结构体的实际大小可能因为对齐规则而大于成员大小之和,这涉及到内存中的填充字节,对于内存管理和性能优化具有重要意义。
十、文件操作
10.1 打开和关闭
使用 fopen 函数打开文件,返回文件指针,使用 fclose 函数关闭文件,释放相关资源。
10.2 读取操作
使用 fscanf 函数从文件中读取格式化数据使用 fgets 函数读取一行文本。
10.3 写入操作
使用 fprintf 函数将格式化数据写入文件,使用 fputs 函数将字符串写入文件。
10.4 二进制文件的读写
使用二进制模式打开文件来进行二进制文件的读写操作,使用 fread 函数读取二进制数据,使用 fwrite 函数写入二进制数据。
10.5 文件位置指针
文件位置指针(文件偏移量)用于记录文 件读写的当前位置。使用 fseek 函数移动文件位置指针。使用 ftell 函数获取当前位置指针的偏移量
10.6 文件的错误处理
文件操作可能失败,需要进行错误处理。 使用 feof 函数检查文件是否到达文件末尾 。使用 ferror 函数检查文件操作是否出错。
10.7 文本文件和二进制文件的区别
文本文件包含可打印字符,可以由文本编 辑器打开。二进制文件包含非文本数据,无法直接由文本编辑器打开。使用不同的打开模式来操作文本文件和二进制文件。
10.8 文件复制程序 - 概述
编写一个程序,将一个文件的内容复制到另一个文件。
使用文件操作函数来读取和写入文件。
可以用于学习文件操作和内存管理。
10.9 文件复制程序 - 设计思路
打开源文件和目标文件。
逐行或逐字符读取源文件内容。
将读取的内容写入目标文件。
关闭源文件和目标文件。
第二章 数据结构
数组的补充:
- 数组的操作:插入、删除、更新。例如:
数组不仅可以存储数据,还可以进行插入 、删除和更新操作。插入:在特定位置添加新元素。删除:从数组中移除元素。更新:修改数组中的元素值。
- 插入:需求:在现实应用中,可能需要在数组中插入新数据。
示例场景:插入新的学生分数记录。
思路:找到插入位置,将插入位置之后的元素后移一位。插入新元素到目标。
- 删除:需求:在某些情况下,需要从数组中删除元素。
示例场景:删除某位学生的分数记录。
思路:找到要删除的元素位置,将该位置之后的元素前移一位。数组的大小减一。
- 更新:需求:更新数组元素,使其反映最新信息。
示例场景:更新学生分数。找到要更 新的元素位置,直接修改该位置的值。
一、节点操作
1.1 链表节点介绍
链表是由节点组成的动态数据结构,节点包含数据和指向下一个节点的指针。
1.2 创建链表节点
1.3 增加节点
1.3 查询节点
1.4 删除节点
1.6 打印节点
1.7 在指定位置插入节点
1.8 链表合并
1.9 一元多项式-节点
1.10 创建单项式节点
1.11 打印多项式
1.12 多项式相加函数
1.13 释放内存
第三章 图
一、队列
1.1 队列的概念
队列是一种线性数据结构,遵循先进先出(FIFO)的原则。类似于现实生活中的排队,先到先服务。
1.2 队列的特点
元素从队尾入队,从队头出队。具有头部和尾部,两端操作不同。
1.3 队列的入队
将元素添加到队列的尾部。
队列长度增加。
1.3 队列的出队
从队列的头部移除元素。
队列长度减少。
1.5 队列链表实现
二、图
2.1 图的基本概念
图是一种用于表示对象及其关系的数据结 构。 • 由节点(顶点)和边组成,用于模拟现实 中的关系网络。
2.2 图的组成部分
节点(顶点):表示图中的对象,可以有属性。
边:表示节点之间的关系,可以是有向或无向的。
2.3 无向图与有向图:
无向图:边没有方向,表示双向关系。
有向图:边有方向,表示单向关系。
2.4 加权图与带权图
加权图:边具有权重,表示节点间的成本或距离。
带权有向图:同时具有边的方向和权重
2.5 图的运用领域
社交网络:人际关系网络,如朋友、家人等。
路网和交通:道路和交通网络,路径规划。
计算机网络:服务器、路由器之间的连接。
2.6 图的数据结构
邻接矩阵:使用矩阵表示节点间的连接关系,适用于稠密图。
三、广度优先搜索(BFS)算法
3.1 算法介绍
广度优先搜索是一种图和树等数据结构的搜索算法,以层次逐步遍历节点,先访问近的节点,再访问远的节点。
3.2 应用领域
求解最短路径问题,查找图中节点之间的关系,二进制矩阵中的路径查找等。
3.3 BFS算法步骤
创建队列:初始化一个空队列,用于存储待访问的节点。
标记已访问节点:创建一个布尔数组(或哈希集合)来标记已访问的节点,避免重复访问。
从起始节点开始:将起始节点入队,并标记为已访问。
出队一个节点。
访问该节点。
将其未访问的邻居节点入队,并标记为已访问。
重复遍历过程,直到队列为空,得到搜索结果。
3.4 BFS算法特点
层次遍历:以层次逐步遍历节点,先近后远。
队列辅助:使用队列保证节点按照先进先出(FIFO)的顺序访问。
最短路径解决:在无权图中能够找到最短路径,有权图中找到非负权最短路径。
3.5 BFS算法实现:
四、深度优先搜索(DFS)算法
4.1 算法介绍
深度优先搜索是一种图和树等数据结构的搜索算法。从起始节点开始,尽可能深地探索一个分支,直到无法继续为止,然后回溯到上一层。
4.2 DFS算法步骤
创建标记数组:创建一个布尔数组(或哈希集合)来标记已访问的节点。
从起始节点开始:选择一个起始节点作为当前节点,并标记为已访问。
递归探索分支:递归地探索当前节点的邻居节点。对每个邻居节点递归应用DFS算法。
回溯:如果当前节点的所有邻居都已经访问过,回溯到上一层。在回溯过程中,继续探索其他未访问的分支。
得到搜索结果:继续递归探索,直到无法继续为止。
4.3 算法实现
五、Dijkstra算法
5.1 算法介绍:
Dijkstra算法是一种用于在加权图中找到最短路径的算法。通过逐步选择路径中的最短边,从一个起始节点到其他所有节点的最短距离。
仅适用于非负权重图。
5.2 算法步骤:
创建节点集合和距离数组:创建一个节点集合和一个距离数组,用于存储起始节点到其他节点的最短距离。
初始化距离数组:初始化距离数组,起始节点距离设为0,其他节点距离设为无穷大。
选择最短距离节点:从未访问节点中选择距离最短的节点。将其标记为已访问。
更新最短距离:更新以选定节点为中心,相邻节点的距离。如果经过选定节点到达相邻节点的距离更短,更新距离。
重复步骤:重复步骤3和步骤4,直到所有节点都被访问。
5.3 Dijkstra算法特点:
单源最短路径:求解单个起始节点到其他所有节点的最短路径。
非负权重:仅适用于非负权重图,否则结果可能不准确。
基于贪心策略:使用贪心策略选择当前最短路径,逐步扩展。
5.4 算法实现
六、Bellman-Ford算法
6.1 算法介绍
Bellman-Ford算法用于在加权图中找到单源最短路径。能够处理带有负权边的图,但不能处理存在负权环的图。网络路由、路径规划、金融风险评估等领域。适用于带有负权边的情况。
6.2 算法步骤
①创建距离数组和前驱节点数组:创建一个距离数组和一个前驱节点数组,用于存储 最短路径和路径信息。
②初始化距离数组和前驱节点数组:将起始节点的距离设0,其他节点的距离设为无穷大。将所有节点的前驱节点设为空。
③松弛操作(Relaxation):如果通过某个节点可以获得更短的路径,更新距离和前驱节点。
④重复松弛操作:重复执行步骤3,直到没有路径可以继续优化。
⑤检测负权环:如果在步骤4后,仍然存在可以优化的路径,说明图中存在负权环。
6.3 算法特点
单源最短路径:求解单个起始节点到其他所有节点的最短路径。可处理负权边:适用于带有负权边的情况 ,但不能处理负权环。迭代次数:最多进行 n-1次迭代,其中n是节点数。
6.4 算法实现
第四章 算法设计与分析
一、算法
1.1 算法定义:
算法:是对特定问题求解方法(步骤)的一种描述,是指令的有限序列,其中每一条指令表示一个或多个操作。
1.2 算法特性:
有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。
确定性:算法中每一条指令必须有确切的含义。不存在二义性。且算法只有一个入口和一个出口。
可行性:一个算法是能行的。即算法描述的操作都可以通过已经实现的基本运算执行有限次实现。
输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象集合。
输出:一个算法有一个或多个输出,这些输出是同输入有着某些特定关系的量。
1.3 算法设计的要求:
正确性:算法应满足具体问题的需求。
可读性:算法应容易供人阅读和交流。可读性好的算法有助于对算法的理解修改。
健壮性:算法应具有容错处理。当输入非法或错误数据时,算法应能适当地作出反应或进行处理,而不会产生莫名其妙的输出结果。
通用性:算法应具有一般性,即算法的处理结果对于一般的数据集合都成立。
效率与存储量需求:效率指的是算法执行的时间;存储量需求指算法执行过程中所需要的最大存储空间。一般地,这两者与问题的规模有关
二、时间复杂度
算法中基本操作重复执行的次数是问题规模n的某个函数,其时间量度记作 T(n)=O(f(n)),称作算法的渐近时间复杂度,简称时间复杂度。
例:
,其时间复杂度为:O(n2) ,即为平方阶。
三、空间复杂度
算法编写成程序后,在计算机中运行时所需存储空间大小的度量。
一般地,算法的空间复杂度指的是辅助空间。
一维数组a[n]:空间复杂度 O(n)
二维数组a[n][m]:空间复杂度 O(n*m)
第五章 随机化算法
一、排序
1.1 排序
排序是将一批(组)仸意次序的记录重新排列成按关键字有序的记录序列的过程,其定义为:给定一组记录序列:{R1, R2 ,…, Rn},其相应的关键字序列是{K1, K2 ,…, Kn} 。确定1, 2, … n的一个排列P1, P2 ,…, Pn,使其相应的关键字满足如下非递减(或非递增)关系: Kp1≤Kp2 ≤…≤Kpn的序列{Kp1 ,Kp2 , …,Kpn} ,这种操作称为排序。排序算法主要包括:冒泡排序、插入排序、希尔排序、快速排序、选择排序、归并排序、计数排序。若数据量过大,那么还需要进行外部排序。每种排序方法都有自己的特点
1.2 排序的稳定性
若记录序列中有两个或两个以上关键字相等的记录: Ki =Kj(i≠j,i, j=1, 2, … n),且在排序前Ri先于Rj
(i<j),排序后的记录序列仍然是Ri先于Rj,称排序方法是稳定的,否则是不稳定的。
1.3 排序的分类
① 待排序的记录数不太多:所有的记录都能存
放在内存中进行排序,称为内部排序;
② 待排序的记录数太多:所有的记录不可能存放在内存中, 排序过程中必须在内、外存之间进行数据交换,这样的排序称为外部排序。
二、冒泡排序
2.1 介绍
冒泡排序:简单但低效的排序算法逐步比较和交换相邻元素,将最大(或最小)的元素“冒泡”到末尾。
2.2 步骤
从数组的第一个元素开始,逐一比较相邻的两个元素。如果顺序错误,交换这两个元素,将较大(或较小)的元素“冒泡”到右侧。继续对数组中的每一对相邻元素执行相同操作,直到最后一个元素。一轮比较后,最大(或最小)的元素已经在末尾,不再参不下一轮比较。重复执行步骤,每一轮比较都会确定一个元素的最终位置。
2.3 算法实现
2.4 优点和缺点:
优点:简单易懂,适用于小规模数据。
缺点:效率低,不适用于大规模或部分有序数据。
2.5 改进
三、计数排序
计数排序,又可以称为不选择排序,一般适用于数据范围较小比如(0~750),但是样本容量较大的数据集。计数排序的核心思想是把相同放在一起,然后进行排序。
第一步:首先应该计算出数据的范围(range=max-min+1),然后应该把每个相同数值出现的次数记录在一个数组当中。
其中的countArr[ ]是记录了相同数值出现的次数。
这个可以理解为起到了占位的作用。
sortedArr[ ]最终完成了排序。
这个是完整的代码:
时间复杂度为O(n + k),k为范围;空间复杂度为O(k)。
四、插入排序
插入排序就好比打扑克一样,每次摸牌前我们都已经把扑克牌的顺序已经排好了,没摸一次扑克牌我们就把摸到的排,按照顺序插入已经排好的序列里就行,所以,插入排序算法就一样。其核心代码实现如下图所示。
代码中的flag是未排序的数值,flag的前面是已经排好顺序的数组。然后依次向前查找排序。
五、归并排序
归并排序算法就是先把原来的数值进行一半的分割,一直一半分割直至变成单个元素,就是(0+n)/2,如果奇数情况,可以分成不均等的情况。完全分割完之后,然后按照原来分割的方向进行排序并且合并,最终完成排序。
其中上述代码中用了两次递归函数。
六、快速排序
快速排序算法是对冒泡排序算法的进阶版本,具体步骤就是首先先选择一个基准元素,然后与其进行比较来回跳跃。定义两个指针,一个指向数组起始,一个
指向数组末尾。移动左指针直到找到大于基准的元素,移动右指针直到找到小于基准的元素。交换左右指针指向的元素。
七、随机化算法
随机化算法是基于随机数生成器,计算机中的随机数生成器是伪随机数生成器,为何称为伪随机那是因为我们要操作时是利用了随机数种子。随机化算法在密码学方面有着重要的应用,我们日常用的短信验证码就是基于随机化算法的。
7.1 蒙特卡洛方法-随机抽样
7.1.1介绍:
随机抽样是蒙特卡洛方法的基础。它涉及从某个已知概率分布中抽取样本,以模拟问题的随机性。常见的随机抽样方法包括均匀随机抽样正态随机抽样等。通过足够多的随机样本,可以在问题的解空间中均匀分布样本,从而实现更准确的近似。蒙特卡洛方法涉及对生成的随机样本进行统计分析,如计算均值、方差等。根据大数定律,当样本数量足够大时,样本的平均值趋近于总体的均值,这种趋势可用于估计问题的解。将问题转化为可模拟的随机过程,通常需要明确定义随机变量和概率分布。问题建模是一个关键的步骤,它将问题的数学描述与随机性联系起来,从而使问题适用于蒙特卡洛方法。对于一个函数 f(x),我们希望计算在区间[a, b] 上的定积分。在区间 [a, b] 内随机生成 x 值,并计算 f(x),通过统计区间内的随机点数与落在函数下方的点数之比,可以估计定积分的值。估计的积分值为 (b - a) * (函数下方的点数)/ (总点数)。
7.1.2 收敛性与误差:
蒙特卡洛方法的误差通常随着样本数量的增加而减小,即估计值逐渐接近真实值。收敛性是指随着样本数量增加,估计值趋近于真实值的性质。随着样本数量的增加,误差会减小,但也需要权衡计算成本和结果精度。
7.1.3 随机数生成器:
随机数生成器是蒙特卡洛方法的基础,质量和性能对结果至关重要。随机数生成器应满足统计上的随机性、均匀性和独立性。伪随机数生成器(如线性同余法)可以在一定范围内模拟随机性,但更高级的密码学安全随机数生成器可提供更高质量的随机数。
7.1.4 应用领域:
蒙特卡洛方法广泛应用于金融风险评估、概率统计、物理模拟、优化问题、生物科学等众多领域。在金融中,它可用于估计投资组合风险;在物理模拟中,用于模拟粒子行为;在生物科学中,用于模拟分子运动等。
7.1.5 误差分析:
蒙特卡洛方法的结果通常伴随着一定的误差,误差可以通过统计方法进行分析。可以计算置信区间、方差等来估计误差的范围和稳定性。
7.1.6 并行计算:
蒙特卡洛方法天然适合并行计算,因为样本可以独立生成和处理。并行计算可显著加速大规模蒙特卡洛模拟。
7.1.7 随机性与确定性的权衡:
蒙特卡洛方法适用于无法求解精确解的复杂问题,但其结果仍受随机性影响。随机性带来近似性,但需要通过大量样本来减小误差,这可能涉及较高的计算成本。
7.1.8 布朗运动
定义:布朗运动是一种随机的、不规则的分子运动现象,其中微小颗粒(如微粒子、分子或颗粒)在液体或气体中由于分子碰撞而发生不规则的运动。
特点:布朗运动的运动路径是不规则且随机的,微小颗粒在不断受到分子撞击的影响下,沿着无规则的路径移动。布朗运动的速度是随机的,颗粒在短时间内可能会随机改变速度和方向。
原因:布朗运动的主要原因是液体或气体分子的热运动。微小颗粒与周围分子的碰撞会导致颗粒发生随机的运动。
数学模型:布朗运动可以用随机游走模型来描述,其中微小颗粒在每个时间步长内随机移动一定距离。
应用:布朗运动在许多领域有应用,如物理学、化学、生物学和金融等。它用于模拟分子扩散、颗粒的输运、金融市场的随机波动等。
布朗粒子模型:•布朗运动可以用布朗粒子模型来表示。在这个模型中,微小颗粒在时间步长内受到随机力的影响而改变速度和位置。
7.2拉斯维加斯算法
7.2.1 介绍:
拉斯维加斯算法是一种随机化算法,与传统随机化算法不同,它始终能够产生正确的输出。该算法的特点在于其运行时间是不确定的,因为它依赖于随机事件的发生。
7.2.2 运行时间的不确定性:
拉斯维加斯算法的运行时间并不是一个确定的值。算法会在有限时间内找到正确的解,但并不会在预定的时间内终止。运行时间由随机性决定。
7.2.3 正确性保证
拉斯维加斯算法保证总是能够产生正确的输出。尽管运行时间不确定,但它会不断重试,直到找到正确的解为止。
7.2.4 反复试验
算法通常需要多次重复试验,每次试验都使用不同的随机性。这些试验会持续进行,直到找到满足问题要求的正确解。
7.2.5 概率分析
尽管拉斯维加斯算法保证正确性,但我们可以通过概率分析来了解其平均运行时间和性能特征。概率分析可以提供算法在各种情况下的性能期望。
7.2.6 拉斯维加斯算法-求解圆周率
7.2.7 拉斯维加斯算法求解布朗运动
7.3 Fisher-Yates 随机洗牌算法
7.3.1 介绍:
Fisher-Yates 随机洗牌算法是一种常用于打乱数组顺序的有效算法,确保每种排列都是等概率出现的。
7.3.2 算法步骤:
从数组中最后一个元素开始,向前迭代到第一个元素,对于每个元素,随机选择一个位置,将该元素与所选位置的元素交换,在迭代过程中,对于当前位置 i,生成一个随机整数 j,满足 0 ≤ j ≤ i,将位置 i 处的元素与位置 j 处的元素换。
第六章 神经网络与人工智能
一、基本概念汇总
分类器:用于对数据进行分类的模型,例如区分毛虫和瓢虫。
预测器:接受输入并做出预测的模型,通过比较预测结果和真实示例来调整内部参数。
训练分类器:通过调整模型参数来优化分类器的性能。
布尔函数:逻辑函数,如AND、OR,用于处理二进制决策。
神经元:神经网络的基本单元,模拟生物神经元的行为。
激活函数:在神经元中用于引入非线性的函数,如Sigmoid或阶跃函数。
反向传播:一种用于训练神经网络的算法,通过计算误差梯度来更新权重。
梯度下降:优化算法,用于最小化损失函数,通过迭代调整权重来寻找最小值。
学习率:控制梯度下降步长的参数,影响学习过程的快慢。
过拟合:模型在训练数据上表现很好,但在新数据上表现不佳的现象。
二、推导
线性分类器:通过调整直线的斜率来区分两类数据。
误差计算:使用误差函数(如平方误差)来量化预测值和真实值之间的差异。
权重更新:根据误差梯度更新权重,公式为 ΔA = -η * (E * x),其中 η 是学习率,E 是误差,x 是输入。
反向传播:从输出层开始,逐层向后计算误差梯度,并更新每层的权diedie