贪心算法
贪心算法(greedy algorithm)。贪心算法有很多经典的应用,比如霍夫曼编码(Huffman Coding)、Prim 和 Kruskal 最小生成树算法、还有 Dijkstra 单源最短路径算法。最小生成树算法和最短路径算法我们后面会讲到,所以我们今天讲下霍夫曼编码,看看它是如何利用贪心算法来实现对数据压缩编码,有效节省数据存储空间的。
贪心算法(greedy algorithm)。贪心算法有很多经典的应用,比如霍夫曼编码(Huffman Coding)、Prim 和 Kruskal 最小生成树算法、还有 Dijkstra 单源最短路径算法。最小生成树算法和最短路径算法我们后面会讲到,所以我们今天讲下霍夫曼编码,看看它是如何利用贪心算法来实现对数据压缩编码,有效节省数据存储空间的。
我们前面讲过,递归的思想就是,将大问题分解为小问题来求解,然后再将小问题分解为小小问题。这样一层一层地分解,直到问题的数据规模被分解得足够小,不用继续递归分解为止。
如果我们把这个一层一层的分解过程画成图,它其实就是一棵树。我们给这棵树起一个名字,叫作递归树。我这里画了一棵斐波那契数列的递归树,你可以看看。节点里的数字表示数据的规模,一个节点的求解可以分解为左右子节点两个问题的求解。

通过这个例子,你对递归树的样子应该有个感性的认识了,看起来并不复杂。现在,我们就来看,如何用递归树来求解时间复杂度。
归并排序的原理我就不详细介绍了,如果你忘记了,可以回看一下第 12 节的内容。归并排序每次会将数据规模一分为二。我们把归并排序画成递归树,就是下面这个样子:
以自解压版为例
https://mirrors.tuna.tsinghua.edu.cn/msys2/distrib/x86_64/msys2-base-x86_64-20230718.sfx.exe
1. 下载自解压程序
https://mirrors.tuna.tsinghua.edu.cn/msys2/distrib/x86_64/msys2-base-x86_64-20230718.sfx.exe
2. 双击 ucrt64.exe 进入终端并执行
1 | pacman -S --needed base-devel mingw-w64-x86_64-toolchain |
创建 hello.c,输入以下代码:
1 | #include <stdio.h> |
编译器可以将源代码转换成机器语言,在编译过程中,会找出错误并报告。这个阶段的输入是在编辑期间产生的文件,常称为源文件。
gcc -c hello.c
注:GCC 是由 GNU 开发的编程语言编译器,用来编译 C 语言程序。
链接器将源代码文件中由编译器产生的各种对象模块组合起来,再从 C 语言提供的程序库中添加必要的代码模块,将它们组合成一个可执行文件。
gcc -o hello hello.o
多数情况下,我们可以通过 gcc -o hello hello.c 命令,调用编译器 GCC 对文件 abc.c 进行编译,完成了 “预处理-编译-汇编-链接”,生成了可执行文件 hello。
./hello
Visual Studio 是非常全能的选择,界面也较为现代。
程序:一组计算机能识别和执行的指令。每一条指令是计算机执行特定的操作;计算机的一切操作都是由程序控制的,离开程序,计算机将一事无成。
[发展阶段]
(1)问题分析 (2)设计算法 (3)编写程序 (4)对源程序进行编辑,编译和连接 (5)运行程序,分析结果
Visual Studio Code - Code Editing. Redefined
可通过使用 “Configure Display Language” 命令可以切换中英文。
按 Ctrl + Shift + P 调出命令面板,然后开始键入 “display” 以筛选和显示配置显示语言命令。
C++ programming with Visual Studio Code 文档
什么是算法
一个程序主要包括一下两个方面的信息(1)对数据的描述 (2)对操作的描述
我们不要以为只有计算的问题才有算法,广义的说,为解决一个问题而采取的方法和步骤称为算法。
算法的特性
(1)有穷性 (2)稳定性 (3)有零个或多个输入 (4)有一个或多个输出 (5)有效性
怎样表示一个算法
(1)自然语言表示 (2)流程图表示 (3)N-S图表示 (4)伪代码表示 (5)计算机语言表示
结构化程序设计方法
(1)自顶向下 (2)逐步细化 (3)模块化设计 (4)结构化编码
程序编译时出现以下提示,是 没将stdio.h 包含在代码中
[Warning] incompatible implicit declaration of built-in function ‘printf’
C 语言编程由函数构成,每个函数由变量定义说明和算法执行两大部分组成。
3 种常见数据类型
计算机高级语言中,数据的两种表现形式
[1] 常量
(1)整型常量 + 号可省略,- 号不可省,默认为 int,超出为 long,如果需要手动表示,则后加 L 或者 l(L 更突出),但都是 4 个字节
(2)实型常量,十进制小数形式和指数形式 (float 和 double 型,字面量 3.0 默认为 double 类型,当然可加 F 或 f 表示成 float 类型)
(3)字符常量,由一对单引号引起,其内部存储的对应字符的 ASCII 码,包括普通字符和转义字符
转义字符及其作用
1 | \n 换行 |
(4)字符串常量
(5)符号常量(例如 #define PI 3.1415)
[2] 变量:变量必须先定义后使用
[3] 常变量 const int a = 3;
[4] 标识符:对变量名,符号常量名,函数,数组,类型等命名的有效字符序列
[int]整型 vc 中四个字节,在存储单元中的存储方式是整数的补码, 范围是 -2(31) 到 2(31)-1 即 -2147483648 到 2147483647,无符号为 0-4294967295
[short]短整型
[long]长整型 在 vc 中与 int 一样在 C 语言中,有 [signed] long [int],即在有些条件下括号内的是可以省略的。
[char]字符型 -128-127 无符号为 0-255 以整数形式(字符的 ASCII 码)存在内存
[float]单精度浮点型 字节数 4 有效数字 6(指小数部分) 也就是 float 能得到 6 位小数,数值范围 0 以及正负 1.2*10(-38 次方) 到 3.4*10(38 次方)

[double]双精度浮点型 字节数 8 有效数字 15 数值范围 0 及 2.3*10(-308次方) 到 1.7*10(308)
对于字符型,只要有单撇号扩起来的的单个字符或转义字符,对于数值常量按以下规律
整型 不带小数点的数值,在一个整数的末尾加大写字母 L 或小写字母 l,表示是长整型都分配四个字节,因此没有必要用 long int 型。
浮点型常量 凡小数形式或指数形式出现的实数,如 10.0 是浮点型常量。可以在常量的末尾加专用字符,强制指定常量的类型加 F/f 表示 float 型,分配四个字节。如果在实型常量后面加 L/l,则表示指定此常量为 long double
运算符和表达式
(1)基本的运算符
(2)自增自减运算符
(3)表达式和运算符的优先级与结合性
(4)不同类型数据间的混合运算
(5)强制类型 转换运算符
(double)a;
(int)(x+y);
(float)(5%3)
其基本形式为(类型名)(表达式)
(6)C 运算符
C 语句及其作用及其分类 声明部分不是语句,它不产生机器指令,只是对有关数据的声明。
一个函数由数据声明部分和执行语句执行.

C 语言分为以下 5 类
(1)控制语句
(2)函数调用语句 由一个函数调用加一个分号组成
(3)表达式语句
(4)空语句
(5)复合语句:复合语句常用在 if 语句或循环中,此时程序需要连续执行一组语句。而且在复合语句中最后一句的分号不能省略不写。
1 | printf 函数中常用格式字符 |
对于 float 和 double 型, 请分别用 scanf("%f", &inch) 和 scanf("%lf", &inch) 进行输入
字符数据的输入与输出
getchar() 这里无参数
putchar(c1)
puts(字符数组); // 会在字符串最后自动加上 ‘\0’ 最终转换为 ‘\n’ 作为换行的意思,所以 putchar() 也有一样的作用
gets(字符数组)
以上都是一些非格式化的输入/输出
使用数学公式
1 | #include <stdio.h> |
i+j 指的是 i()+j
谭浩强著《C 程序设计》