CS50
文章目录
- 0.1 关于CS50对进制的介绍——二进制、八进制、十六进制。
- 0.2 计算机的组成结构——计算机由硬件和软件组成。
- 0.3 计算机的运行原理
- 0.4 计算机的编程语言
- 0.5 计算机的操作系统
- 0.6 计算机的网络
- 0.7 编译(complier):
- 0.8虚拟机(Virtual Machine):
- 0.9 数据库(Database):
- 0.10 云计算(Cloud Computing)
- Week-1-2 C语言概述
- 1.1 基本数据类型与变量:
- 1.1.1 数据类型:
- int(整型):
- float、double(浮点型):
- char(字符型):
- 1.1.2 变量定义与初始化:
- 1.2 运算符与表达式:
- 1.3 控制流语句:
- 1.3.1 条件语句(if-else):
- 1.4 循环语句:
- 1.4.1 for 循环:
- 1.4.2 while 循环:
- 1.4.3 do-while 循环:
- 1.4.4 break:
- 1.4.5 continue:
- 1.5 数组与字符串:
- 1.5.1 数组(Array):
- 1.5.2 字符串(String):
- 1.6 指针:
- 1.6.1 指针的概念:
- 1.6.2 指针的运算:
- 1.6.3指针与数组的关系:
- 1.6.4 指针作为函数参数:
- 1.7 函数:
- 1.7.1 函数的定义与调用:
- 1.7.1.1 函数的定义
- 1.7.1.2函数的调用
- 1.7.2 函数的参数传递:
- 1,7.2.1值传递:
- 1.7.2.2引用传递(通过指针实现):
- 1.7.2.3 函数的返回值:
- 1.8 结构体与共用体:
- 1.8.1 结构体:
- 1.8.2共用体:
- 9 文件操作:
- 9.1文件的打开与关闭:
- 9.2 文件的读写操作:
- Week-3 Algorithms
- 3.0关于CS50对此的介绍——即上界与下界的概念。
- 3.1 算法的基本概念:
- 定义:
- 3.2 效率衡量:
- 3.2.1 时间复杂度:
- 3.2.2 空间复杂度:
- 3.3 常见的搜索算法:
- 3.3.1 线性搜索(顺序搜索):
- 原理:
- 特点:
- 3.3.2 二分查找(折半查找):
- 原理:
- 特点:
- 3.3.3 冒泡排序:
- 原理:
- 特点:
- 3.3.4 选择排序:
- 原理:
- 特点:
- 3.3.5 插入排序:
- 原理:
- 特点:
- 3.3.6合并排序(归并排序):
- 原理:
- 特点:
- 4.递归:
- 定义:
- 特点:
- 分治策略:
- 概念:
- 优点:
- 算法的分析与优化:
- 分析:
- 优化:
- Week-4 Memory
- 4.1 内存地址与表示:
- 4.1.1 内存地址的概念:
- 4.1.2 取地址操作符:
- 4.2动态内存分配(Dynamic Memory Allocation):
- 4.2.1 malloc 函数:
- 4.2.2 内存的释放:
- 4.3 数据结构与内存:
- 4.3.1数组与指针的关系:
- 4.3.2 链表等动态数据结构:
- 4.4 内存相关的错误与调试:
- 4.4.1 内存泄漏:
- 4.4.2 缓冲区溢出(Buffer Overflow):
- 4.5使用工具调试:
- Week-5 Data Structures
- 5.1 链表(Linked Lists)
- 5.1.1 定义和特点:
- 5.1.2 应用场景:
- 5.2 栈(Stacks)
- 5.2.1 定义和特点:
- 5.2.2 应用场景:
- 5.3 队列(Queues)
- 5.3.1 定义和特点:
- 5.3.2 应用场景:
- 5.4树(Trees)
- 5.4.1 定义和特点:
- 5.4.2 应用场景:
- 5.5图(Graphs)
- 5.5.1 定义和特点:
- 5.5.2 应用场景:
- 5.6 哈希表(Hash Tables)
- 5.6.1 定义和特点:
- 5.6.2 应用场景:
- 5.7 堆(Heaps)
- 5.7.1 定义和特点:
- 5.7.2 应用场景:
- 5.8 集合(Sets)
- 5.8.1 定义和特点:
- 5.8.2 应用场景:
- 5.9 字典(Dictionaries)
- 5.9.1 定义和特点:
- 5.9.2 应用场景:
- Week-6 Python
- 6.1基础语法:
- 6.1.1变量与数据类型:
- 6.1.2运算符:
- 6.1.3 循环语句:
- for循环:
- while循环:
- break语句:
- continue语句:
- 6.1.4 字符串:
- 6.2 数据结构:
- 6.2.1 列表(List):
- 6.2.2 元组(Tuple):
- 6.2.3 字典(Dict):
- 6.2.4 集合(Set):
- 6.3 函数:
- 6.4文件操作:
- 6.4.1 打开一个文件用于写入
- 6.4.2 打开一个文件用于读取
- 6.5 模块与包:
- 6.6 异常处理:
- 6.7 面向对象编程(Object-Oriented Programming):
0.1 关于CS50对进制的介绍——二进制、八进制、十六进制。
二进制(Binary):0、1组成的数,以 2 为基数。base-2
八进制(Octal):0~7组成的数,以 8 为基数。base-8
十进制(Decimal):0~9组成的数,以 10 为基数。base-10
十六进制(Hexadecimal):09、AF(大小写皆可)组成的数,以 16 为基数。base-16
0.2 计算机的组成结构——计算机由硬件和软件组成。
硬件:计算机的硬件由处理器(中央处理器Central Processing Unit,CPU)、内存(Random Access Memory,RAM)、输入输出设备(Input/Output Device,I/O Device)、显示器(Display)、键盘、鼠标、硬盘等组成。)存储设备等组成。
软件:计算机的软件由操作系统、应用软件、网络软件等组成。
0.3 计算机的运行原理
基于二进制的。
计算机的每一个指令都是一个二进制的数字,每一个数据都是一个二进制的数字。
0.4 计算机的编程语言
C、C++、Java、Python、JavaScript、PHP、SQL、HTML、CSS、XML、JSON等。
0.5 计算机的操作系统
计算机的操作系统有Windows、Mac OS、Linux、Unix等。
0.6 计算机的网络
有TCP/IP协议、HTTP协议、FTP协议、SMTP协议等。
0.7 编译(complier):
将高级语言编译成机器语言。
汇编语言(assembly language):机器语言的助记符。
0.8虚拟机(Virtual Machine):
模拟计算机的运行环境。
虚拟机可以运行各种操作系统,包括Windows、Mac OS、Linux等。
虚拟机可以运行各种编程语言,包括C、C++、Java、Python、JavaScript、PHP、SQL、HTML、CSS、XML、JSON等。
0.9 数据库(Database):
关系型数据库:MySQL、Oracle、SQL Server等。存储、管理、检索数据。
0.10 云计算(Cloud Computing)
利用网络提供的计算资源。
Week-1-2 C语言概述
C
基础且底层的编程语言。
1.1 基本数据类型与变量:
1.1.1 数据类型:
int(整型):
用于表示整数,有不同的取值范围,如 short int、int、long int 和 long long int,具体的范围取决于编译器和系统。
例如,在常见的 32 位系统中,int 类型通常占用 4 个字节,取值范围是 -2147483648 到 2147483647。
float、double(浮点型):
用于表示带有小数部分的数字。float 一般占用 4 个字节,提供大约 6 到 7 位有效数字的精度;double 通常占用 8 个字节,精度更高,大约 15 到 16 位有效数字。
char(字符型):
用于存储单个字符,实际上是用整数来表示字符的 ASCII 码值。
例如,字符 ‘A’ 的 ASCII 码值是 65,在内存中 char 类型的变量存储的就是 65 这个整数。
1.1.2 变量定义与初始化:
变量必须先定义后使用,定义时要指定变量的类型和名称。
例如:int num; 定义了一个名为 num 的整型变量。
可以在定义变量的同时进行初始化,如 int count = 0;。如果没有初始化,变量的值是不确定的,使用未初始化的变量可能会导致程序出现错误的结果。
1.2 运算符与表达式:
算术运算符:
+、-、*、/ 分别表示加、减、乘、除运算。需要注意的是,整数除法会舍去小数部分,
例如 5 / 2 的结果是 2。
% 是取模运算符,用于求两个整数相除的余数,
例如 7 % 3 的结果是 1。
关系运算符:
==(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)用于比较两个值的大小关系,返回的结果是 true(真)或 false(假),在 C 语言中分别用整数 1 和 0 表示。
例如:if (a > b) 中的条件如果成立,a > b 的结果就是 1,否则是 0。
逻辑运算符:
&&(逻辑与):只有当两个操作数都为真时,结果才为真。
例如:if (a > 0 && b > 0) 表示当 a 和 b 都大于 0 时,条件成立。
||(逻辑或):只要两个操作数中有一个为真,结果就为真。
例如:if (a > 0 || b > 0) 表示只要 a 或 b 中有一个大于 0,条件就成立。
!(逻辑非):用于对一个逻辑值取反。
例如:if (!flag) 表示当 flag 为假时,条件成立。
赋值运算符:
= 是基本的赋值运算符,用于将一个值赋给一个变量。
例如:x = 10; 把 10 赋给变量 x。
还有复合赋值运算符,如 +=、-=、*=、/=、%= 等,它们是将运算和赋值操作组合在一起。
例如:x += 5; 相当于 x = x + 5;。
1.3 控制流语句:
1.3.1 条件语句(if-else):
if 语句用于根据一个条件来决定是否执行一段代码。
if (score >= 60) { printf("及格"); } 如果 score 变量的值大于等于 60,就会输出 "及格"。
if-else 语句可以在条件不满足时执行另外一段代码。
if (age >= 18) { printf("成年人"); } else { printf("未成年人"); } 根据 age 变量的值判断是成年人还是未成年人。
if-else if-else 结构来处理多个条件的情况。
if (score >= 90) { printf("优秀"); } else if (score >= 80) { printf("良好"); } else if (score >= 60) { printf("及格"); } else { printf("不及格"); }
1.4 循环语句:
1.4.1 for 循环:
for (初始化表达式; 条件表达式; 更新表达式) { 循环体 }。初始化表达式在循环开始时执行一次,用于初始化循环变量;条件表达式在每次循环开始前进行判断,如果为真则执行循环体,否则结束循环;更新表达式在每次循环体执行完后执行,用于更新循环变量。
for (int i = 0; i < 10; i++) { printf("%d ", i); }
会输出 0 到 9 的数字。
1.4.2 while 循环:
while (条件表达式) { 循环体 }。只要条件表达式为真,就会一直执行循环体。
int i = 0; while (i < 10) { printf("%d ", i); i++; } 与前面的 for 循环效果相同。
1.4.3 do-while 循环:
**do { 循环体 } while (条件表达式);。**先执行一次循环体,然后再判断条件表达式,如果为真则继续循环,否则结束循环。这种循环至少会执行一次循环体。例如:int i = 0; do { printf("%d ", i); i++; } while (i < 10);
跳转语句:
1.4.4 break:
用于跳出循环或 switch 语句。在循环中遇到 break 时,会立即结束循环;在 switch 语句中,用于跳出当前 case 分支。
1.4.5 continue:
用于跳过当前循环的剩余部分,直接进入下一次循环。例如:在一个循环中,如果某个条件满足,使用 continue 可以跳过后续的代码,直接进行下一次循环。
1.5 数组与字符串:
1.5.1 数组(Array):
定义数组时需要指定数组的类型、名称和大小。例如:int arr[10]; 定义了一个包含 10 个整数的数组。
数组的下标从 0 开始,访问数组元素时可以使用下标。例如:arr[0] 表示数组 arr 的第一个元素。索引从0开始
可以通过循环来遍历数组,对数组中的元素进行操作。例如:for (int i = 0; i < 10; i++) { arr[i] = i * 2; } 给数组 arr 的每个元素赋值。
1.5.2 字符串(String):
C 语言中没有专门的字符串类型,而是使用字符数组来表示字符串。例如:char str[] = “Hello”; 定义了一个字符串 str。string==char*
字符串以 ‘\0’ 作为结束标志,在处理字符串时需要注意字符串的长度和结束标志。计算长度时要+1
有一些字符串操作的函数,如 strlen() 用于计算字符串的长度(不包括结束标志 ‘\0’)、strcpy() 用于复制字符串、strcmp() 用于比较两个字符串等。例如:strcpy(dest, src); 将 src 字符串复制到 dest 字符数组中。
1.6 指针:
1.6.1 指针的概念:
指针是一个变量,它存储的是另一个变量的地址。通过指针可以间接访问变量的值。例如:int a = 10; int *p; p = &a; 定义了一个整型变量 a 和一个整型指针 p,并将 p 指向 a 的地址,那么 *p 就表示 a 的值,即 10。
1.6.2 指针的运算:
指针可以进行加减运算,但是指针的加减运算不是简单的数值加减,而是根据指针所指向的数据类型的大小来进行偏移。例如,如果 p 是一个指向 int 类型的指针,那么 p + 1 会指向数组的下一个 int 类型的元素的地址。
两个指向同一个数组的指针可以相减,结果是两个指针之间的元素个数的差值。
1.6.3指针与数组的关系:
数组名可以看作是一个指向数组第一个元素的指针。例如,对于数组 int arr[10];,arr 和 &arr[0] 是等价的,都表示数组的首地址。可以使用指针来访问数组元素,例如 int *p = arr; 后,p[i] 和 arr[i] 是等价的。
1.6.4 指针作为函数参数:
可以将指针作为函数的参数,这样可以在函数内部修改调用者传递的变量的值。例如:
调用 swap(&x, &y); 可以交换 x 和 y 的值。
1.7 函数:
1.7.1 函数的定义与调用:
1.7.1.1 函数的定义
包括函数的返回类型、函数名、参数列表和函数体。例如:int add(int a, int b) { return a + b; } 定义了一个名为 add 的函数,它接受两个 int 类型的参数,返回它们的和。
1.7.1.2函数的调用
需要提供与函数定义中参数列表相匹配的参数。例如:int result = add(3, 5); 调用 add 函数,并将 3 和 5 作为参数传递给函数,函数返回的结果赋值给 result 变量。
1.7.2 函数的参数传递:
1,7.2.1值传递:
在函数调用时,将实参的值复制给形参,函数内部对形参的修改不会影响到实参的值。
1.7.2.2引用传递(通过指针实现):
将实参的地址传递给形参,函数内部通过指针可以修改实参的值。
1.7.2.3 函数的返回值:
函数可以返回一个值,也可以没有返回值(返回类型为 void)。如果函数有返回值,在函数体中必须使用 return 语句返回一个值。
1.8 结构体与共用体:
关于点操作符(.)的使用:
用于访问结构体的成员:
// 定义一个结构体类型
struct Person {
char name[20];
int age;
float height;
};
int main() {
// 创建一个结构体变量并初始化
struct Person person = {"Alice", 25, 1.65};
// 使用点操作符访问结构体成员并输出
printf("Name: %s\n", person.name);
printf("Age: %d\n", person.age);
printf("Height: %.2f\n", person.height);
// 修改结构体成员的值
person.age = 26;
person.height = 1.70;
// 再次输出结构体成员的值
printf("\nAfter modification:\n");
printf("Name: %s\n", person.name);
printf("Age: %d\n", person.age);
printf("Height: %.2f\n", person.height);
return 0;
}
1.8.1 结构体:
typedef struct { int age; char name[20]; float score; } Student;
结构体是一种用户自定义的数据类型,可以将不同类型的变量组合在一起。例如:
定义了一个名为 Student 的结构体类型,包含 name、age 和 score 三个成员。
可以定义结构体变量,并访问结构体成员。
例如
struct Student stu; stu.age = 20; strcpy(stu.name, "John"); stu.score = 85.5;
1.8.2共用体:
共用体是一种特殊的结构体,所有成员共享同一块内存空间,同一时间只能存储一个成员的值。例如:
定义了一个名为 Data 的共用体类型,它的成员 i、f 和 c 共享同一块内存空间。
9 文件操作:
9.1文件的打开与关闭:
使用 fopen() 函数打开文件,返回一个文件指针;
使用 fclose() 函数关闭文件。
例如:FILE *fp = fopen("data.txt", "r");
以只读方式打开名为 data.txt 的文件,如果打开成功,fp 指向该文件;操作完成后,使用 fclose(fp); 关闭文件。
9.2 文件的读写操作:
fscanf() 和 fprintf() 函数用于格式化的文件读写,类似于 scanf() 和 printf() 函数。
例如:fscanf(fp, “%d”, &num); 从文件 fp 中读取一个整数并存储到 num 变量中;fprintf(fp, “%d”, num); 将 num 变量的值写入到文件 fp 中。
fgetc() 和 fputc() 函数用于逐个字符的文件读写。
例如:char ch = fgetc(fp); 从文件 fp 中读取一个字符并赋值给 ch;fputc(ch, fp); 将字符 ch 写入到文件 fp 中。
*关于对文件的操作,还有一些常用的函数:
“r”:以只读方式打开文件。
“w”:以写方式打开文件,并覆盖原有内容。
“a”:以追加模式打开文件,在文件末尾添加内容。
“r+”:以读写方式打开文件。
“w+”:以读写方式打开文件,并覆盖原有内容。
“a+”:以读写方式打开文件,在文件末尾添加内容。
“b”:以二进制模式打开文件。
“t”:以文本模式打开文件。
“|”:用于设置文件操作的选项。
*
Week-3 Algorithms
3.0关于CS50对此的介绍——即上界与下界的概念。
上界:指的是算法的最高可能的输入值。用O表示法(Big O notation)
下界:指的是算法的最低可能的输入值。用Ω表示法(Omega notation)
当O=Ω时,表示算法的输入值范围是确定的。用θ表示法(Theta notation)
3.1 算法的基本概念:
定义:
算法是解决特定问题的一系列明确的、可执行的步骤。它是一种逻辑上的解决方案,用于指导计算机完成特定的任务。
3.2 效率衡量:
3.2.1 时间复杂度:
衡量算法运行时间随输入规模增长的速度。常见的时间复杂度有 O(1)(常数时间)、O(n)(线性时间)、O(n^2)(平方时间)、O(nlogn)(线性对数时间)O(logn)(对数时间)等。
3.2.2 空间复杂度:
衡量算法在运行过程中所占用的额外存储空间。算法可能需要额外的空间来存储中间结果、数据结构等。
3.3 常见的搜索算法:
3.3.1 线性搜索(顺序搜索):
原理:
按顺序遍历列表中的每个元素,将其与目标元素进行比较,直到找到匹配的元素或遍历完整个列表。
特点:
简单直观,适用于小型数据集或未排序的数据集,但效率较低,时间复杂度为O(n) 。
3.3.2 二分查找(折半查找):
原理:
适用于已排序的数据集。每次将数据集分成两半,根据目标元素与中间元素的大小关系,确定在左半部分还是右半部分继续查找,重复这个过程直到找到目标元素或确定目标元素不存在。
特点:
效率较高,时间复杂度为O(nlogn) ,但要求数据集必须是有序的。
常见的排序算法:
3.3.3 冒泡排序:
原理:
通过多次比较相邻的两个元素,将较大(或较小)的元素交换到正确的位置。每次遍历都会将当前未排序部分中的最大(或最小)元素移动到末尾。
特点:
简单易懂,但效率较低,时间复杂度为**O(n^2) **。
3.3.4 选择排序:
原理:
每次从未排序的部分中选择最小(或最大)的元素,将其与未排序部分的第一个元素交换,逐步构建已排序的部分。
特点:
与冒泡排序相比,交换次数较少,但时间复杂度仍为O(n^2) 。
3.3.5 插入排序:
原理:
将未排序的元素逐个插入到已排序的部分中,保持已排序部分的有序性。
特点:
对于接近有序的数据集效率较高,平均时间复杂度为O(n^2) ,但在最好情况下可以达到O(n) 。
3.3.6合并排序(归并排序):
原理:
采用分治策略,将数据集分成较小的子数据集,分别进行排序,然后将已排序的子数据集合并成一个完整的有序数据集。
特点:
时间复杂度为O(nlogn) ,空间复杂度为O(n) ,具有较高的效率和稳定性,适用于大型数据集。
4.递归:
定义:
递归是一种函数调用自身的技术。在递归函数中,问题被分解为更小的子问题,直到子问题可以直接解决,然后将子问题的解组合起来得到原问题的解。
特点:
可以使代码简洁、清晰,但如果递归深度过大,可能会导致栈溢出等问题。例如,使用递归实现的斐波那契数列计算,代码简洁,但对于较大的输入可能会非常耗时。
分治策略:
概念:
分治策略是将一个大问题分解为多个较小的、相互独立的子问题,分别解决子问题,然后将子问题的解合并起来得到原问题的解。合并排序就是分治策略的一个典型应用。
优点:
可以降低问题的复杂度,提高算法的效率,适用于解决具有重复性结构的问题。
算法的分析与优化:
分析:
通过对算法的时间复杂度和空间复杂度进行分析,可以评估算法的效率和资源占用情况。在实际应用中,需要根据问题
的规模和资源限制选择合适的算法。
优化:
可以通过改进算法的逻辑、选择更合适的数据结构、减少不必要的操作等方式来优化算法,提高算法的性能。例如,对于频繁查找操作,可以使用哈希表等数据结构来提高查找效率
Week-4 Memory
4.1 内存地址与表示:
4.1.1 内存地址的概念:
内存是以字节为单位的一片连续存储空间,每个字节都有唯一的编号,这个编号就是内存的 “地址”。计算机系统通过内存地址来对内存进行管理,地址从 0 开始顺序依次编号。在 C 语言中,使用十六进制数来表示内存地址会更方便,通常会看到类似 “0x7ffc3a7cffbc” 这样的十六进制地址表示形式。
4.1.2 取地址操作符:
在 C 语言中,“&” 是取地址操作符。例如 &n 可以获取变量 n 的内存地址。而 %p 是用于打印地址(指针)的格式化说明符,在 printf 函数中可以使用 **%p **来打印变量的内存地址。
4.2动态内存分配(Dynamic Memory Allocation):
4.2.1 malloc 函数:
malloc 是 C 语言中的一个标准库函数,用于在程序运行时动态地分配内存空间。例如 int *x = malloc(sizeof(int)) 表示请求系统为一个 int 类型的变量分配内存空间,并将返回的内存地址赋给指针 x。使用 malloc 函数时,需要包含 <stdlib.h> 头文件。
4.2.2 内存的释放:
当不再需要使用通过 malloc 分配的内存空间时,必须使用 **free **函数释放内存,否则会导致内存泄漏。例如 free(x) 可以释放指针 x 所指向的内存空间。
4.3 数据结构与内存:
4.3.1数组与指针的关系:
数组名在很多情况下会被隐式地转换为指向数组第一个元素的指针。这意味着可以通过指针来操作数组,例如可以使用指针来遍历数组元素。但需要注意的是,数组的大小在声明时就已经确定,无法在运行时动态地改变数组的大小。
4.3.2 链表等动态数据结构:
由于指针的存在,可以实现像链表这样的动态数据结构。链表中的每个节点都包含一个数据部分和一个指向下一个节点的指针部分,这样可以根据需要在运行时动态地添加或删除节点,克服了数组无法动态改变大小的限制。
4.4 内存相关的错误与调试:
4.4.1 内存泄漏:
如果程序中不断地使用 malloc 分配内存,但没有及时使用 free 释放,就会导致内存泄漏。随着程序的运行,系统的可用内存会越来越少,最终可能导致程序崩溃。
4.4.2 缓冲区溢出(Buffer Overflow):
当向一个缓冲区(例如数组)写入的数据超过了缓冲区的大小,就会发生缓冲区溢出。这可能会导致程序出现异常行为,甚至可能被攻击者利用来执行恶意代码。
4.5使用工具调试:
CS50 课程中可能会介绍一些工具来帮助调试内存相关的问题,例如 valgrind。valgrind 可以分析程序的内存使用情况,检测是否存在内存泄漏、缓冲区溢出等问题。
关于对指针(Pointer)的介绍,请看上文。
Week-5 Data Structures
5.1 链表(Linked Lists)
5.1.1 定义和特点:
链表是由一系列节点组成的线性数据结构,每个节点包含数据和指向下一个节点的指针。
链表可以在运行时动态地添加和删除节点,因此非常灵活。
5.1.2 应用场景:
当需要频繁地插入和删除元素时,链表比数组更高效。例如,在实现栈和队列等数据结构时,链表是一个很好的选择。
5.2 栈(Stacks)
5.2.1 定义和特点:
栈是一种后进先出(LIFO)的数据结构。可以把栈想象成一叠盘子,最后放上去的盘子最先被拿走。
栈的操作主要有入栈(push)和出栈(pop),以及查看栈顶元素(peek)。
5.2.2 应用场景:
函数调用栈是栈的一个典型应用。在程序执行过程中,每次调用函数时,都会将函数的参数、局部变量等信息压入栈中,当函数返回时,这些信息从栈中弹出。
5.3 队列(Queues)
5.3.1 定义和特点:
队列是一种先进先出(FIFO)的数据结构。就像排队一样,先进入队列的元素先被处理。
队列的操作主要有入队(enqueue)和出队(dequeue),以及查看队首元素(peek)。
5.3.2 应用场景:
操作系统中的任务调度、打印机的打印任务队列等都是队列的实际应用。
5.4树(Trees)
5.4.1 定义和特点:
树是一种非线性数据结构,由节点和边组成。每个节点可以有多个子节点。
树的特点包括层次结构、递归定义等。常见的树有二叉树、二叉搜索树等。
5.4.2 应用场景:
文件系统的目录结构、数据库中的索引结构等都可以用树来表示。
5.5图(Graphs)
5.5.1 定义和特点:
图是一种由节点(顶点)和边组成的非线性数据结构。边可以是有向的或无向的,并且可以带有权重。
图的表示方法有邻接矩阵和邻接表等。
5.5.2 应用场景:
地图导航、社交网络分析、网络路由等问题都可以用图来建模。
5.6 哈希表(Hash Tables)
5.6.1 定义和特点:
哈希表是一种通过哈希函数将键映射到值的数据结构。它可以快速地进行插入、删除和查找操作。
哈希表的性能取决于哈希函数的质量和处理冲突的方法。
5.6.2 应用场景:
数据库系统、缓存系统等需要快速查找和存储数据的场景中经常使用哈希表。
5.7 堆(Heaps)
5.7.1 定义和特点:
堆是一种特殊的树形数据结构,可以用来实现优先队列。堆的特点是父节点的值总是大于或等于其子节点的值。
5.7.2 应用场景:
优先队列、排序算法、图论算法、堆排序等。
5.8 集合(Sets)
5.8.1 定义和特点:
集合是一种无序的、元素不能重复的数据结构。
集合的操作主要有**添加(add)、删除(remove)、查找(contains)**等。
5.8.2 应用场景:
集合可以用来存储元素,并进行快速查找、删除操作。
5.9 字典(Dictionaries)
5.9.1 定义和特点:
字典是一种键-值对的数据结构。字典的键必须是唯一的,值可以重复。
字典的操作主要有**添加(add)、删除(remove)、查找(get)**等。
5.9.2 应用场景:
字典可以用来存储键值对,并进行快速查找、删除操作。
关于对数组的介绍请看上文。
Week-6 Python
6.1基础语法:
6.1.1变量与数据类型:
Python 常见的数据类型有整数(int)、浮点数(float)、布尔值(bool,注意在 Python 中True和False的首字母需大写)、字符串(str)等。
比如定义一个整数变量x = 10,布尔变量is_true = True。
可以使用type()函数来查看变量的数据类型,例如print(type(x))会输出<class ‘int’>。
6.1.2运算符:
算术运算符,如+(加)、-(减)、*(乘)、/(除)、%(取余)、**(幂运算)等。例如2 ** 3的结果是8。
比较运算符,用于比较两个值的大小关系,如==(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)。
在条件判断中经常使用,例如if x > y:。
逻辑运算符,包括and(与)、or(或)、not(非),
用于组合多个条件判断。比如if x > 0 and x < 10:表示x在 0 到 10 之间(不包括 0 和 10)。
控制结构:
条件语句:使用if、elif(多个条件判断时使用,相当于其他语言中的else if)、else来进行条件判断。例如:
if x < 10:
print("x 小于 10")
elif x < 20:
print("x 大于等于 10 且小于 20")
else:
print("x 大于等于 20")
6.1.3 循环语句:
for循环:
通常用于遍历一个可迭代对象,如列表、元组、字符串等。
for i in range(1, 11):
print(i)
while循环:
通常用于条件判断,当条件满足时,循环体会被执行。
i = 1
while i <= 10:
print(i)
i += 1
break语句:
用于跳出循环。
continue语句:
用于跳过当前循环的剩余语句,直接开始下一轮循环。
6.1.4 字符串:
字符串是以单引号或双引号括起来的一系列字符。
字符串的拼接可以使用+运算符,例如"Hello" + “World"的结果是"HelloWorld”。
字符串的索引从 0 开始,可以用方括号[]来访问字符串中的字符。
字符串的长度可以使用len()函数来获取。
字符串的格式化可以使用%运算符,例如"Hello, %s!" % “World"的结果是"Hello, World!”。
字符串的切片可以使用[start🔚step]语法,其中start是切片的起始位置,end是切片的结束位置(不包含),step是步长。
字符串的常用方法有lower()、upper()、split()、join()等。
字符串的编码可以使用encode()方法,例如"你好".encode(“utf-8”)的结果是b’\xe4\xbd\xa0\xe5\xa5\xbd’。
字符串的解码可以使用decode()方法,例如b’\xe4\xbd\xa0\xe5\xa5\xbd’.decode(“utf-8”)的结果是"你好"。
字符串的格式化可以使用format()方法,例如"{} is {} years old".format(“John”, 25)的结果是"John is 25 years old"。
字符串的格式化可以使用f-string,例如name = “John”,age = 25,print(f"{name} is {age} years old")的结果是"John is 25 years old"。
字符串的格式化可以使用字符串模板,例如name = "John" age = 25 template = "Hello, {name}, you are {age} years old." print(template.format(name=name, age=age))
的结果是"Hello, John, you are 25 years old."。
字符串的格式化可以使用字符串模板,例如name = "John" age = 25 template = "Hello, {name}, you are {age} years old." print(template.format_map(vars()))
的结果是"Hello, John, you are 25 years old."。
字符串的格式化可以使用字符串模板,例如name = "John" age = 25 template = "Hello, {name}, you are {age} years old." print(template.format_map(locals()))
的结果是"Hello, John, you are 25 years old."。
6.2 数据结构:
6.2.1 列表(List):
列表是一个有序的可变容器,可以容纳不同类型的元素。定义一个列表可以使用方括号[],例如my_list = [1, "apple", True]
。
可以通过索引访问列表中的元素,索引从 0 开始。例如my_list[0]会访问到列表中的第一个元素1。
支持添加、删除、修改元素等操作。例如使用append()方法在列表末尾添加元素,remove()方法删除指定元素,pop()方法删除并返回指定位置的元素。
6.2.2 元组(Tuple):
元组与列表类似,但元组是不可变的,即创建后不能修改其元素。定义元组使用圆括号(),例如my_tuple = (1, 2, 3)
。
元组通常用于存储一些固定不变的数据,比如函数返回多个值时可以使用元组。
6.2.3 字典(Dict):
字典是一种无序的键值对集合,使用花括号{}定义。例如my_dict = {"name": "John", "age": 25}
。
通过键来访问对应的值,例如my_dict["name"]
会返回"John"。
可以添加、修改、删除键值对。例如使用my_dict["gender"] = "male"
可以添加一个新的键值对。
6.2.4 集合(Set):
集合是一个无序的、不包含重复元素的容器。使用花括号{}或者set()函数来创建集合。例如my_set = {1, 2, 3, 3}
,最终my_set中只会包含{1, 2, 3}。
集合支持并集、交集、差集等操作,例如union()、intersection()、difference()方法。
6.3 函数:
函数是一段可重复使用的代码块,用于完成特定的任务。定义函数使用def关键字,例如:
def add_numbers(x, y):
return x + y
可以有参数和返回值,也可以没有参数或没有返回值。调用函数时,传入相应的参数即可得到返回值。例如result = add_numbers(3, 5),result的值为8。
函数可以嵌套定义,即在一个函数内部定义另一个函数。
6.4文件操作:
Python 可以使用open()函数来打开文件,使用read()、write()等方法来读取和写入文件内容。例如:
6.4.1 打开一个文件用于写入
ile = open("my_file.txt", "w")
file.write("Hello, World!")
file.close()
6.4.2 打开一个文件用于读取
file = open("my_file.txt", "r")
content = file.read()
print(content)
file.close()
为了确保文件正确关闭,可以使用with语句,它会在代码块执行完毕后自动关闭文件。例如:
with open("my_file.txt", "r") as file:
content = file.read()
print(content)
6.5 模块与包:
模块是一个包含 Python 代码的文件,包是一个包含多个模块的文件夹。可以使用import语句来导入模块或包。例如import math可以导入 Python 的数学模块,然后使用math.sqrt()来计算平方根。
可以给模块或包起别名,以便更方便地使用。例如import numpy as np,之后可以使用np来代替numpy。
6.6 异常处理:
在程序运行过程中可能会出现错误或异常情况,使用try、except、else、finally语句来处理异常。例如:
x = int(input("请输入一个数字:"))
except ValueError:
print("输入的不是数字,请重新输入。")
else:
print("输入的数字是:", x)
finally:
print("程序结束。")
通过捕获特定类型的异常,可以对不同的错误情况进行不同的处理,提高程序的健壮性。
6.7 面向对象编程(Object-Oriented Programming):
面向对象编程是 Python 的重要特性之一,它将数据和操作数据的方法封装在一起,形成类和对象。
定义类使用class关键字,类中可以包含属性和方法。例如:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print(f"大家好,我叫{self.name},今年{self.age}岁。")
通过类创建对象,使用对象可以调用类中的方法和访问属性。例如:
person = Person(“张三”, 20)
person.say_hello()