算法基础笔记整理

合集下载

算法基础(详细全面)

算法基础(详细全面)
第1章 算法基础
1.1 算法 1.2 算法分析 1.3 算法的运行时间
1.1.1 冒泡排序
1.1 算 法
冒泡排序(bubble sort)属于基于交换思想的排序方法。它将 相邻的两个元素加以比较,若左边元素值大于右边元素值,则 将这两个元素交换;若左边元素值小于等于右边元素值,则这 两个元素位置不变。右边元素继续和下一个元素进行比较,重 复这个过程,直到比较到最后一个元素为止。
3
do if A[j] < A[j - 1
4
then exchange A[j] A[j - 1
图1-1说明了输入实例为A = 〈5, 2, 4, 6, 1, 3〉时, 算法BUBBLE SORT的工作过程。对于外层for循环的每一次迭 代,则在A[i]位置产生当前元素比较范围A[i..n]内的一个 最小值。下标i从数组第一个元素开始, 从左向右直至数组中最 后一个元素。深色阴影部分表示数组元素A[1..i]构成已排好 的序列,浅色阴影部分表示外层循环开始时的下标i。数组元素 A[i +1..n]表示当前正在处理的序列。
下面, 我们考察这些性质是如何对冒泡排序成立的。 首先 证明内层for循环的不变式。
· 循环不变式:A[j]是A[j..length[A]]中的最小元素。
· 初始: 在内循环第一次开始迭代之前,j =length[A], 因此,子数组A[length[A]..length[A]] 中只包含一个元 素, 也即子数组中的最小元素, 此时, 循环不变式成立。
(9) “and”和“or”是布尔运算符。当对表达式“x and y”
求值时,首先计算x的值,
FALSE,则整个表达式
的值为FALSE,我们也无需计算y的值;如果x的值为TRUE,

算法基本知识点总结

算法基本知识点总结

算法基本知识点总结一、算法的基本概念1. 算法的定义算法是用来解决特定问题的有限步骤的有序集合。

算法是一种计算方法,可以描述为一系列清晰的步骤,用来解决特定问题或执行特定任务。

2. 算法的特性(1)有穷性:算法必须在有限的步骤内结束。

(2)确定性:对于相同输入,算法应该产生相同的输出。

(3)可行性:算法必须可行,即算法中的每一步都可以通过已知的计算机能力来执行。

3. 算法的设计目标(1)正确性:算法应该能够解决给定的问题。

(2)可读性:算法应该易于理解和解释。

(3)高效性:算法应该能在合理的时间内完成任务。

二、算法的复杂度分析1. 时间复杂度算法的时间复杂度表示算法执行所需的时间长度,通常用“大O记法”表示。

时间复杂度反映了算法的运行时间与输入规模之间的关系。

常见的时间复杂度包括:(1)O(1):常数时间复杂度,表示算法的运行时间与输入规模无关。

(2)O(logn):对数时间复杂度,表示算法的运行时间与输入规模的对数成正比。

(3)O(n):线性时间复杂度,表示算法的运行时间与输入规模成正比。

(4)O(nlogn):线性对数时间复杂度,表示算法的运行时间与输入规模和对数成正比。

(5)O(n^2):平方时间复杂度,表示算法的运行时间与输入规模的平方成正比。

(6)O(2^n):指数时间复杂度,表示算法的运行时间与输入规模的指数成正比。

2. 空间复杂度算法的空间复杂度表示算法执行所需的内存空间大小。

常见的空间复杂度包括:(1)O(1):常数空间复杂度,表示算法的内存空间与输入规模无关。

(2)O(n):线性空间复杂度,表示算法的内存空间与输入规模成正比。

三、常见的算法设计思想1. 贪心算法贪心算法是一种选取当前最优解来解决问题的算法。

贪心算法的核心思想是从问题的某一初始解出发,通过一系列的局部最优选择,找到全局最优解。

2. 动态规划动态规划是一种将原问题分解成子问题来求解的方法。

动态规划通常适用于具有重叠子问题和最优子结构性质的问题。

高中数学算法初步知识点整理

高中数学算法初步知识点整理

高中数学算法初步知识点整理高中数学算法初步知识点:考点(必考)概要1、算法的概念:①由基本运算及规定的运算顺序所构成的完整的解题步骤,或者是按照要求设计好的有限的计算序列,并且这样的步骤或序列能解决一类问题。

②算法的五个重要特征:ⅰ有穷性:一个算法必须保证执行有限步后结束;ⅱ确切性:算法的每一步必须有确切的定义;ⅲ可行性:算法原则上能够精确地运行,而且人们用笔和纸做有限次即可完成;ⅳ输入:一个算法有0个或多个输入,以刻划运算对象的初始条件。

所谓0个输入是指算法本身定出了初始条件。

ⅴ输出:一个算法有1个或多个输出,以反映对输入数据加工后的结果。

没有输出的算法是毫无意义的。

2、程序框图也叫流程图,是人们将思考的过程和的顺序进行分析、整理,用规定的文字、符号、图形的组合加以直观描述的方法(1)程序框图的基本符号:(2)画流程图的基本规则:①使用标准的框图符号②从上倒下、从左到右③开始符号只有一个退出点,结束符号只有一个进入点,判断符号允许有多个退出点④判断可以是两分支结构,也可以是多分支结构⑤语言简练⑥循环框可以被替代3、三种基本的逻辑结构:顺序结构、条件结构和循环结构(1)顺序结构:顺序结构描述的是是最简单的算法结构,语句与语句之间,框与框之间是按从上到下的顺序进行的。

(2)条件结构:分支结构的一般形式两种结构的共性:①一个入口,一个出口。

特别注意:一个判断框可以有两个出口,但一个条件分支结构只有一个出口。

②结构中每个部分都有可能被执行,即对每一个框都有从入口进、出口出的路径。

以上两点是用来检查流程图是否合理的基本方法(当然,学习循环结构后,循环结构也有此特点)(3)循环结构的一般形式:在一些算法中,经常会出现从某处开始,按照一定条件,反复执行某一处理步骤的情况,这就是循环结构,反复执行的处理步骤为循环体,显然,循环结构中一定包含条件结构。

循环结构又称重复结构,循环结构可细分为两类:①如左下图所示,它的功能是当给定的条件成立时,执行A框,框执行完毕后,再判断条件是否成立,如果仍然成立,再执行A框,如此反复执行框,直到某一次条件不成立为止,此时不再执行A框,从b离开循环结构。

Acwing算法笔记

Acwing算法笔记

Acwing算法笔记1.基础算法 —— 代码模板链接常⽤代码模板1——基础算法排序⼆分⾼精度前缀和与差分双指针算法位运算离散化区间合并2.数据结构 —— 代码模板链接常⽤代码模板2——数据结构链表与邻接表:树与图的存储栈与队列:单调队列、单调栈kmpTrie并查集堆Hash表C++ STL使⽤技巧3.搜索与图论 —— 代码模板链接常⽤代码模板3——搜索与图论DFS与BFS树与图的遍历:拓扑排序最短路最⼩⽣成树⼆分图:染⾊法、匈⽛利算法4.数学知识 —— 代码模板链接常⽤代码模板4——数学知识质数约数欧拉函数快速幂扩展欧⼏⾥得算法中国剩余定理⾼斯消元组合计数容斥原理简单博弈论5.动态规划背包问题线性DP区间DP计数类DP数位统计DP状态压缩DP树形DP记忆化搜索1.常⽤代码模板1——基础算法快速排序算法模板 —— 模板题 AcWing 785. 快速排序void quick_sort(int q[], int l, int r){undefinedif (l >= r) return;do j -- ; while (q[j] > x);if (i < j) swap(q[i], q[j]);}quick_sort(q, l, j), quick_sort(q, j + 1, r);}归并排序算法模板 —— 模板题 AcWing 787. 归并排序void merge_sort(int q[], int l, int r){undefinedif (l >= r) return;int mid = l + r >> 1;merge_sort(q, l, mid);merge_sort(q, mid + 1, r);int k = 0, i = l, j = mid + 1;while (i <= mid && j <= r)if (q[i] < q[j]) tmp[k ++ ] = q[i ++ ];else tmp[k ++ ] = q[j ++ ];while (i <= mid) tmp[k ++ ] = q[i ++ ];while (j <= r) tmp[k ++ ] = q[j ++ ];for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];}整数⼆分算法模板 —— 模板题 AcWing 789. 数的范围bool check(int x) {/* ... */} // 检查x是否满⾜某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使⽤:int bsearch_1(int l, int r){undefinedwhile (l < r){undefinedint mid = l + r >> 1;if (check(mid)) r = mid; // check()判断mid是否满⾜性质else l = mid + 1;}return l;}// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使⽤:int bsearch_2(int l, int r){undefinedwhile (l < r){undefinedint mid = l + r + 1 >> 1;if (check(mid)) l = mid;else r = mid - 1;}return l;}浮点数⼆分算法模板 —— 模板题 AcWing 790. 数的三次⽅根bool check(double x) {/* ... */} // 检查x是否满⾜某种性质double bsearch_3(double l, double r){undefinedconst double eps = 1e-6; // eps 表⽰精度,取决于题⽬对精度的要求while (r - l > eps){undefineddouble mid = (l + r) / 2;if (check(mid)) r = mid;else l = mid;}return l;}⾼精度加法 —— 模板题 AcWing 791. ⾼精度加法// C = A + B, A >= 0, B >= 0vector<int> add(vector<int> &A, vector<int> &B){undefinedif (A.size() < B.size()) return add(B, A);vector<int> C;int t = 0;for (int i = 0; i < A.size(); i ++ ){undefined}if (t) C.push_back(t);return C;}⾼精度减法 —— 模板题 AcWing 792. ⾼精度减法// C = A - B, 满⾜A >= B, A >= 0, B >= 0vector<int> sub(vector<int> &A, vector<int> &B){undefinedvector<int> C;for (int i = 0, t = 0; i < A.size(); i ++ ){undefinedt = A[i] - t;if (i < B.size()) t -= B[i];C.push_back((t + 10) % 10);if (t < 0) t = 1;else t = 0;}while (C.size() > 1 && C.back() == 0) C.pop_back();return C;}⾼精度乘低精度 —— 模板题 AcWing 793. ⾼精度乘法// C = A * b, A >= 0, b > 0vector<int> mul(vector<int> &A, int b){undefinedvector<int> C;int t = 0;for (int i = 0; i < A.size() || t; i ++ ){undefinedif (i < A.size()) t += A[i] * b;C.push_back(t % 10);t /= 10;}while (C.size() > 1 && C.back() == 0) C.pop_back();return C;}⾼精度除以低精度 —— 模板题 AcWing 794. ⾼精度除法// A / b = C ... r, A >= 0, b > 0vector<int> div(vector<int> &A, int b, int &r){undefinedvector<int> C;r = 0;for (int i = A.size() - 1; i >= 0; i -- ){undefinedr = r * 10 + A[i];C.push_back(r / b);r %= b;}reverse(C.begin(), C.end());while (C.size() > 1 && C.back() == 0) C.pop_back();return C;}⼀维前缀和 —— 模板题 AcWing 795. 前缀和S[i] = a[1] + a[2] + ... a[i]a[l] + ... + a[r] = S[r] - S[l - 1]⼆维前缀和 —— 模板题 AcWing 796. ⼦矩阵的和S[i, j] = 第i⾏j列格⼦左上部分所有元素的和以(x1, y1)为左上⾓,(x2, y2)为右下⾓的⼦矩阵的和为:S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]⼀维差分 —— 模板题 AcWing 797. 差分给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c⼆维差分 —— 模板题 AcWing 798. 差分矩阵给以(x1, y1)为左上⾓,(x2, y2)为右下⾓的⼦矩阵中的所有元素加上c:S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c双指针算法 —— 模板题 AcWIng 799. 最长连续不重复⼦序列, AcWing 800. 数组元素的⽬标和for (int i = 0, j = 0; i < n; i ++ ){undefinedwhile (j < i && check(i, j)) j ++ ;// 具体问题的逻辑}常见问题分类:(1) 对于⼀个序列,⽤两个指针维护⼀段区间(2) 对于两个序列,维护某种次序,⽐如归并排序中合并两个有序序列的操作离散化 —— 模板题 AcWing 802. 区间和vector<int> alls; // 存储所有待离散化的值sort(alls.begin(), alls.end()); // 将所有值排序alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素⼆分求出x对应的离散化的值int find(int x) // 找到第⼀个⼤于等于x的位置{undefinedint l = 0, r = alls.size() - 1;while (l < r){undefinedint mid = l + r >> 1;if (alls[mid] >= x) r = mid;else l = mid + 1;}return r + 1; // 映射到1, 2, ...n}区间合并 —— 模板题 AcWing 803. 区间合并// 将所有存在交集的区间合并void merge(vector<PII> &segs){undefinedvector<PII> res;sort(segs.begin(), segs.end());int st = -2e9, ed = -2e9;for (auto seg : segs)if (ed < seg.first){undefinedif (st != -2e9) res.push_back({st, ed});st = seg.first, ed = seg.second;}else ed = max(ed, seg.second);if (st != -2e9) res.push_back({st, ed});segs = res;}2.常⽤代码模板2——数据结构单链表 —— 模板题 AcWing 826. 单链表// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表⽰当前⽤到了哪个节点int head, e[N], ne[N], idx;// 初始化void init(){undefinedhead = -1;idx = 0;}// 在链表头插⼊⼀个数avoid insert(int a){undefinede[idx] = a, ne[idx] = head, head = idx ++ ;}// 将头结点删除,需要保证头结点存在void remove(){undefinedhead = ne[head];// e[]表⽰节点的值,l[]表⽰节点的左指针,r[]表⽰节点的右指针,idx表⽰当前⽤到了哪个节点int e[N], l[N], r[N], idx;// 初始化void init(){undefined//0是左端点,1是右端点r[0] = 1, l[1] = 0;idx = 2;}// 在节点a的右边插⼊⼀个数xvoid insert(int a, int x){undefinede[idx] = x;l[idx] = a, r[idx] = r[a];l[r[a]] = idx, r[a] = idx ++ ;}// 删除节点avoid remove(int a){undefinedl[r[a]] = l[a];r[l[a]] = r[a];}栈 —— 模板题 AcWing 828. 模拟栈// tt表⽰栈顶int stk[N], tt = 0;// 向栈顶插⼊⼀个数stk[ ++ tt] = x;// 从栈顶弹出⼀个数tt -- ;// 栈顶的值stk[tt];// 判断栈是否为空if (tt > 0){undefined}队列 —— 模板题 AcWing 829. 模拟队列1. 普通队列:// hh 表⽰队头,tt表⽰队尾int q[N], hh = 0, tt = -1;// 向队尾插⼊⼀个数q[ ++ tt] = x;// 从队头弹出⼀个数hh ++ ;// 队头的值q[hh];// 判断队列是否为空if (hh <= tt){undefined}2. 循环队列// hh 表⽰队头,tt表⽰队尾的后⼀个位置int q[N], hh = 0, tt = 0;// 向队尾插⼊⼀个数q[tt ++ ] = x;if (tt == N) tt = 0;// 从队头弹出⼀个数hh ++ ;if (hh == N) hh = 0;// 队头的值{undefined}单调栈 —— 模板题 AcWing 830. 单调栈常见模型:找出每个数左边离它最近的⽐它⼤/⼩的数int tt = 0;for (int i = 1; i <= n; i ++ ){undefinedwhile (tt && check(stk[tt], i)) tt -- ;stk[ ++ tt] = i;}单调队列 —— 模板题 AcWing 154. 滑动窗⼝常见模型:找出滑动窗⼝中的最⼤值/最⼩值int hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){undefinedwhile (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗⼝while (hh <= tt && check(q[tt], i)) tt -- ;q[ ++ tt] = i;}KMP —— 模板题 AcWing 831. KMP字符串// s[]是长⽂本,p[]是模式串,n是s的长度,m是p的长度//求模式串的Next数组:for (int i = 2, j = 0; i <= m; i ++ ){undefinedwhile (j && p[i] != p[j + 1]) j = ne[j];if (p[i] == p[j + 1]) j ++ ;ne[i] = j;}// 匹配for (int i = 1, j = 0; i <= n; i ++ ){undefinedwhile (j && s[i] != p[j + 1]) j = ne[j];if (s[i] == p[j + 1]) j ++ ;if (j == m){undefinedj = ne[j];// 匹配成功后的逻辑}}Trie树 —— 模板题 AcWing 835. Trie字符串统计int son[N][26], cnt[N], idx;// 0号点既是根节点,⼜是空节点// son[][]存储树中每个节点的⼦节点// cnt[]存储以每个节点结尾的单词数量// 插⼊⼀个字符串void insert(char *str){undefinedint p = 0;for (int i = 0; str[i]; i ++ ){undefinedint u = str[i] - 'a';if (!son[p][u]) son[p][u] = ++ idx;p = son[p][u];}cnt[p] ++ ;}// 查询字符串出现的次数int query(char *str){undefinedint p = 0;for (int i = 0; str[i]; i ++ ){undefinedint u = str[i] - 'a';if (!son[p][u]) return0;p = son[p][u];}//(1)朴素并查集:int p[N]; //存储每个点的祖宗节点// 返回x的祖宗节点int find(int x){undefinedif (p[x] != x) p[x] = find(p[x]);return p[x];}// 初始化,假定节点编号是1~nfor (int i = 1; i <= n; i ++ ) p[i] = i;// 合并a和b所在的两个集合:p[find(a)] = find(b);//(2)维护size的并查集:int p[N], size[N];//p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表⽰祖宗节点所在集合中的点的数量// 返回x的祖宗节点int find(int x){undefinedif (p[x] != x) p[x] = find(p[x]);return p[x];}// 初始化,假定节点编号是1~nfor (int i = 1; i <= n; i ++ ){undefinedp[i] = i;size[i] = 1;}// 合并a和b所在的两个集合:size[find(b)] += size[find(a)];p[find(a)] = find(b);//(3)维护到祖宗节点距离的并查集:int p[N], d[N];//p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离// 返回x的祖宗节点int find(int x){undefinedif (p[x] != x){undefinedint u = find(p[x]);d[x] += d[p[x]];p[x] = u;}return p[x];}// 初始化,假定节点编号是1~nfor (int i = 1; i <= n; i ++ ){undefinedp[i] = i;d[i] = 0;}// 合并a和b所在的两个集合:p[find(a)] = find(b);d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量堆 —— 模板题 AcWing 838. 堆排序, AcWing 839. 模拟堆// h[N]存储堆中的值, h[1]是堆顶,x的左⼉⼦是2x, 右⼉⼦是2x + 1// ph[k]存储第k个插⼊的点在堆中的位置// hp[k]存储堆中下标是k的点是第⼏个插⼊的int h[N], ph[N], hp[N], size;// 交换两个点,及其映射关系void heap_swap(int a, int b){undefinedswap(ph[hp[a]],ph[hp[b]]);swap(hp[a], hp[b]);{undefinedint t = u;if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;if (u != t){undefinedheap_swap(u, t);down(t);}}void up(int u){undefinedwhile (u / 2 && h[u] < h[u / 2]){undefinedheap_swap(u, u / 2);u >>= 1;}}// O(n)建堆for (int i = n / 2; i; i -- ) down(i);//⼀般哈希 —— 模板题 AcWing 840. 模拟散列表//(1) 拉链法int h[N], e[N], ne[N], idx;// 向哈希表中插⼊⼀个数void insert(int x){undefinedint k = (x % N + N) % N;e[idx] = x;ne[idx] = h[k];h[k] = idx ++ ;}// 在哈希表中查询某个数是否存在bool find(int x){undefinedint k = (x % N + N) % N;for (int i = h[k]; i != -1; i = ne[i])if (e[i] == x)return true;return false;}//(2) 开放寻址法int h[N];// 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插⼊的位置int find(int x){undefinedint t = (x % N + N) % N;while (h[t] != null && h[t] != x){undefinedt ++ ;if (t == N) t = 0;}return t;}字符串哈希 —— 模板题 AcWing 841. 字符串哈希核⼼思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低⼩技巧:取模的数⽤2^64,这样直接⽤unsigned long long存储,溢出的结果就是取模的结果typedef unsigned long long ULL;ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64// 初始化p[0] = 1;for (int i = 1; i <= n; i ++ ){undefinedh[i] = h[i - 1] * P + str[i];p[i] = p[i - 1] * P;}// 计算⼦串 str[l ~ r] 的哈希值3.常⽤代码模板3——搜索与图论树与图的存储树是⼀种特殊的图,与图的存储⽅式相同。

大学计算机科学算法知识点归纳总结

大学计算机科学算法知识点归纳总结

大学计算机科学算法知识点归纳总结计算机科学的一个重要分支就是算法,它是解决问题的具体步骤和方法的集合。

通过学习和掌握算法知识,我们可以更加高效地解决各种问题。

本文将对大学计算机科学中常见的算法知识点进行归纳总结。

一、排序算法排序算法是计算机科学中最基本也是最常用的算法之一。

它将一组元素按照特定的规则进行重新排列。

以下是几种常见的排序算法:1. 冒泡排序(Bubble Sort)冒泡排序通过相邻元素的比较和交换来实现排序,每一轮将最大的元素冒泡到末尾。

2. 插入排序(Insertion Sort)插入排序通过将元素逐个插入已经有序的部分来实现排序。

3. 快速排序(Quick Sort)快速排序是一种基于分治法的排序算法,通过选择一个基准元素和其它元素进行比较和交换来实现排序。

4. 归并排序(Merge Sort)归并排序是一种基于分治法的排序算法,将待排序序列分为若干个子序列,分别进行排序后再合并。

二、查找算法查找算法是在给定的数据集合中找到指定元素的算法。

以下是几种常见的查找算法:1. 顺序查找(Sequential Search)顺序查找是一种逐个比较的查找算法,从列表的开头依次比较每个元素,直到找到目标元素或遍历完整个列表。

2. 二分查找(Binary Search)二分查找是一种基于分治法的查找算法,通过将待查找的区间不断缩小,最终找到目标元素。

三、图算法图是由节点和边组成的一种数据结构,图算法是解决图相关问题的一种算法。

以下是几种常见的图算法:1. 深度优先搜索(Depth First Search)深度优先搜索是一种遍历和搜索图的算法,它以深度优先的方式访问节点。

2. 广度优先搜索(Breadth First Search)广度优先搜索是一种遍历和搜索图的算法,它以广度优先的方式访问节点。

3. 最小生成树(Minimum Spanning Tree)最小生成树是一个无环连通子图,它是图中边的一种子集,使得树上所有边的权值之和最小。

算法与程序设计复习知识点

算法与程序设计复习知识点

算法与程序设计复习知识点算法与程序设计复习知识点1. 算法基础1.1. 算法的定义算法是解决特定问题的一系列清晰指令的有限序列,用来描述解决问题的步骤和方法。

1.2. 算法的特性输入:一个算法必须具有零个或多个输入。

输出:一个算法必须具有一个或多个输出。

明确性:算法的每一步骤必须清晰明确,无二义性。

有限性:算法必须在有限的步骤之后终止。

可行性:算法的每一步都可以通过执行有限次来完成。

1.3. 算法的复杂度算法的复杂度是衡量算法性能的指标,主要包括时间复杂度和空间复杂度。

时间复杂度:描述算法执行所需的时间量与输入数据规模之间的关系。

空间复杂度:描述算法执行所需的存储空间量与输入数据规模之间的关系。

2. 程序设计基础2.1. 编程语言选择合适的编程语言,根据问题需求和自身编程经验选择合适的语言,常见的编程语言包括C、C++、Java、等。

2.2. 数据类型在程序中使用合适的数据类型可以更好地组织和操作数据,常见的数据类型有:整型、浮点型、字符型、字符串型、数组、结构体、指针等。

2.3. 控制结构控制结构用来控制程序的执行流程,主要包括选择结构(if-else语句、switch语句)和循环结构(for循环、while循环)。

2.4. 函数函数是一段独立完成特定任务的代码块,函数可以提高代码的重用性和可维护性,降低代码的复杂度。

2.5. 数据结构数据结构是组织和存储数据的方式,不同的数据结构适用于不同的问题场景,常见的数据结构包括数组、链表、栈、队列、树、图等。

3. 常见算法3.1. 排序算法常见的排序算法包括:冒泡排序、选择排序、插入排序、快速排序、归并排序等。

3.2. 查找算法常见的查找算法包括:顺序查找、二分查找、哈希查找等。

3.3. 图算法常见的图算法包括:深度优先搜索(DFS)、广度优先搜索(BFS)、最短路径算法(Dijkstra算法、Floyd-Warshall算法)等。

3.4. 动态规划动态规划是一种将复杂问题分解为简单子问题的方法,通过解决子问题来解决原始问题,常见的动态规划问题包括背包问题、最长公共子序列问题等。

数据结构与算法基础知识总结

数据结构与算法基础知识总结

数据结构与算法基础知识总结1 算法算法:是指解题方案的准确而完整的描述。

算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。

算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效的,是明确的,此顺序将在有限的次数下终止。

特征包括:(1)可行性;(2)确定性,算法中每一步骤都必须有明确定义,不充许有模棱两可的解释,不允许有多义性;(3)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止,包括合理的执行时间的含义;(4)拥有足够的情报。

算法的基本要素:一是对数据对象的运算和操作;二是算法的控制结构。

指令系统:一个计算机系统能执行的所有指令的集合。

基本运算和操作包括:算术运算、逻辑运算、关系运算、数据传输。

算法的控制结构:顺序结构、选择结构、循环结构。

算法基本设计方法:列举法、归纳法、递推、递归、减斗递推技术、回溯法。

算法复杂度:算法时间复杂度和算法空间复杂度。

算法时间复杂度是指执行算法所需要的计算工作量。

算法空间复杂度是指执行这个算法所需要的内存空间。

2 数据结构的基本基本概念数据结构研究的三个方面:(1)数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构;(2)在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;(3)对各种数据结构进行的运算。

数据结构是指相互有关联的数据元素的集合。

数据的逻辑结构包含:(1)表示数据元素的信息;(2)表示各数据元素之间的前后件关系。

数据的存储结构有顺序、链接、索引等。

线性结构条件:(1)有且只有一个根结点;(2)每一个结点最多有一个前件,也最多有一个后件。

非线性结构:不满足线性结构条件的数据结构。

3 线性表及其顺序存储结构线性表由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。

在复杂线性表中,由若干项数据元素组成的数据元素称为记录,而由多个记录构成的线性表又称为文件。

算法与程序设计复习知识点

算法与程序设计复习知识点

算法与程序设计复习知识点算法与程序设计复习知识点一、数据结构1.数组1.1 一维数组1.1.1 定义和初始化1.1.2 访问和修改元素1.1.3 数组的长度和容量1.1.4 数组的扩容和缩容1.2 二维数组1.2.1 定义和初始化1.2.2 访问和修改元素1.2.3 数组的长度和容量1.2.4 数组的扩容和缩容2.链表2.1 单链表2.1.1 节点定义2.1.2 头节点和尾节点 2.1.3 插入节点2.1.4 删除节点2.2 双链表2.2.1 节点定义2.2.2 头节点和尾节点 2.2.3 插入节点2.2.4 删除节点3.栈和队列3.1 栈3.1.1 定义和基本操作 3.1.2 栈的应用3.2 队列3.2.1 定义和基本操作3.2.2 队列的应用4.树4.1 二叉树4.1.1 定义和基本操作4.1.2 先序遍历、中序遍历和后序遍历 4.2 二叉搜索树4.2.1 定义和基本操作4.2.2 查找、插入和删除节点4.3 平衡二叉树4.3.1 定义和基本操作4.3.2 平衡因子和旋转操作4.4 堆4.4.1 定义和基本操作4.4.2 堆排序二、常用算法1.排序算法1.1 冒泡排序1.2 插入排序1.3 选择排序1.4 快速排序1.5 归并排序1.6 堆排序1.7 计数排序1.8 桶排序1.9 基数排序2.查找算法2.1 顺序查找2.2 二分查找2.3 哈希查找2.4 平衡二叉搜索树查找2.5 B+树查找3.图算法3.1 图的表示和基本操作 3.2 深度优先搜索3.3 广度优先搜索3.4 最小树3.5 最短路径3.6 图的遍历4.动态规划算法4.1 背包问题4.2 最长公共子序列4.3 最短编辑距离4.4 最大子序列和三、程序设计1.编程语言1.1 C语言1.1.1 基本语法1.1.2 数据类型和变量 1.1.3 控制语句1.1.4 函数和指针1.2 C++语言1.2.1 基本语法1.2.2 类和对象1.2.3 继承和多态2.算法设计和分析2.1 时间复杂度和空间复杂度2.2 递归和迭代2.3 动态规划和贪心算法2.4 分治算法2.5 回溯算法附件:●示例代码●算法示意图法律名词及注释:1.著作权:对作品享有的权利,包括复制权、发行权、展览权等。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法重点总结一、引言——算法基本概念1.什么是算法:有限指令序列,对某个问题能够得出正确答案的规则集合2.算法的特点:确定性,可终止性,可行性,输入,输出3.算法规模:问题实例的大小,输入的大小4.基本运算:主要的、关键的、耗时的最小操作5.算法正确性及复杂度证明方法:反证法、数学归纳法(p(a)成立,且对每个n>a,只要p(n-1)成立,p(n)一定成立)6.算法分析标准:正确性、工作量、占用空间量:算法运行过程中的内存占用情况、简单性和清晰性、最优性(即算法的上界(工作量的上界)等于求解问题的下界(问题固有的复杂度))7.算法选择方法:经验法和理论法(常用)8.算法的时间复杂度表示方法:大O表示上界,Ω表示下界,Θ表示同阶9.选择排序:每次选择序列中最小值放在有序序列尾部(与无序数列头部元素交换)10.插入排序:将当前元素与前向有序数列比较,查找插入位置,移动后插入二、贪心算法1.贪心算法的一般特性1)优化问题:建立候选对象集2)建立对象集合:划分解对象集和抛弃对象集3)求解终止函数:判断解对象集是否是问题的解或者求解是否结束(未必是最优解)4)可行解函数:判断候选对象集元素是否可以加入到当前解的对象集中(未必是最优解)5)选择函数:指出哪个剩余的候选对象最有可能构成问题的解6)目标函数:给出问题的解(1)找最少硬币数,候选对象集{100,25,10,5,1}(2)一选到的硬币集和未被选的硬币集(3)判断解函数(solution),检查目前已选的硬币集中的金额是否等于要找的钱数(4)如果集合中硬币钱数不超过应找金额,则该集合是可行的(5)选择函数(selection),从未选硬币集合中找一个面值最大的硬币(6)目标函数(object):计算硬币金额4.图:最小生成树算法的一般特性1)优化问题:建立候选图的边集2)建立集合:已选中的边集MST,未选边集E-MST3)求解终止函数:如果MST构成生成树,则它是一个解4)解存在函数:候选边加入MST构不成回路,则该边可以加入MST5)选择函数:prim算法选择U和V-U之间的最小边加入MST;KrusKal算法从未选边中选最小边加入MST6)目标函数:计算MST中边权值和5.Kruskal算法思想(1)将所有边按权由小到大排列;(2)MST置空;(3)依次取最小边(u,v):* 若(u,v)加入MST不构成回路则将(u,v)加入MST;* 若MST中的边达到n-1条,则结束;Kruskal算法证明:归纳G的边数归纳基础:当G只有一条边,显然G就是最小生成树;归纳假设:设T中有s<n-1条边时,T是有希望成为最有解的。

当向T中再加一条最小边(u,v)时,且进入后不会使T构成回路。

原T中有若干联通分量,加入(u,v)后,减少一个。

所以加入后T仍然是有希望成为最有解的。

所以算法结束后,T中有n-1条边,构成了生成树,且为最优。

6.Prim算法思想(1)解集合T为空,B为任意顶点(2)从B和V-B之间的边中选一最小边(u,v), u属于B,v属于V-B(3)将(u,v)加入T,将v加入B(4)重复(2)-(3)n-1次Prim算法证明:归纳于T中边的数目,如果T在任何步骤都是有希望的,则往T里加一条边后,仍然是有希望的。

7.图:单源最短路径(非负边)Dijkstra算法O(n2)Function Dijkstra(L[1..n,1..n]) : array[2..n]array D[2..n]C={2,3,…,n}for i=2 to n do D[i]=L[1,i]for i=2 to n dov=some element of C minimizing D[v]C=C\{v}for each w∈C doD[w]=min{D[w],D[v]+L[v,w]}return DDijkstra算法证明:(数学归纳法)(a)如果一个顶点i满足i<>1,且i在S中,则D[i]给出了从源到i的最短路径长度。

(b)一个顶点i不在S中,则D[i]给出了从源到i的最短特殊路径长度。

(i的前驱在S中)8.贪心算法背包问题(可分割)Function knapsack(w[1..n],v[1..n]):array[1..n]for i=1 to n do x[i]=0weight=0;while weight<W doi=the best remaining object {seletion}if weight+w[i]<=W then x[i]=1weight=weight+w[i]else x[i]=(W-weight)/w[i]weight=Wreturn x如果根据v/w(价重比)降序顺序选择物品,则knapsack算法可以找到最优解9 贪心算法删数问题算法思想:利用数组(优化问题),输入数字序列组成待选集合,用初始输入数字序列作为解集合和初始抛弃集合为空(建立对象集合)。

循环中,每次从解集合中去除一个数加入到抛弃集合中(可行解函数),使得解集合数列最大(选择函数),循环结束(求解终止函数)后所得解集合为所求最大值(目标函数)。

选择函数:从高位向低位,比较相邻两位数字大小,若高位比低位数字大,则将高位加入到抛弃集合中,若高位比低位小,则向低位移动继续比较。

10 贪心算法会场安排问题算法思想:利用数组(优化问题),记录活动开始时间和结束时间,按结束时间排序建立待选集合,初始解集合为空(建立对象集合)。

循环中,从待选集合中选择结束时间较早的活动,令其与解集合最后一项活动比较两者是否相容(待选会议开始时间大于解集合中会议结束时间),若两者相容,则将待选会议加入到解集合中,若不相容,抛弃当前待选会议,从待选集合中选择下一项。

三、分治算法(递归分治算法)1.分治算法的一般三要素:(1)定义一个最小规模的问题,并给出其解(2)把复杂的问题划分为同类型的若干规模较小的子问题,并分别解决子问题(3)把各子问题的解组合起来,即可得到原问题的解算法思想:比较两个有序数列首部,取较小值放入解集合,并删除其在原数列中的数据。

若某一数列为空,则依次取非空数列元素加入解集合即可。

若两个数列无序,则将两个无序数列递归分割,最终得到两个只有一个算法思想:1.先从数列中取出一个数作为基准数。

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

算法思想:1.最简单问题:n=0,解是12. 问题分解:an=an-1*a四、动态规划算法1.动态算法基本思想:用表记录已解决子问题的答案,需要时再找出已求得的答案,避免重复计算,即用空间换取时间,提高解题效率。

2.动态规划设计方法:(1)基于递归算法设计动态规划算法:递归算法对分解的每个子问题都要递归求解,其中可能有许多子问题重复计算,导致效率低下。

为避免这种重复,可以将递归算法改写为动态规划算法;(2)基于问题结构设计;3.动态规划的基本步骤:(1)找出最优解的性质,并刻画其结构特征。

(2)递归地定义最优值。

(3)以自底向上的方式计算出最优值。

(4)根据计算最优值时得到的信息,构造一个最优解。

(该步骤是求最优解的必须步骤)4.最优性原则(principle of optimality):构造最优解所面临的子问题解都是最优的。

解决一个问题的过程中,需要依次作出n个决策D1,D2,…Dn,若这个决策序列是最优的,对于任何一个整数k,1<k<n,不论前面k个决策是怎样的,以后的最优决策只取决于前面的决策,即前k个是最优的,则k+1也是最优的。

5.动态规划算法的两个特性:(1)最优子性质:最优解只依赖于子问题的最优解;(2)递归结构。

6.动态规划背包问题:算法思想:建立二维数组m[n][c],m[ i ][ j ] 表示在面对物品i时,背包容量为j的情况下所能获得的最大价值。

若容量j小于物品重量w[i]时,不拿取物品,于是m[i][j]=m[i-1][j];若容量j大于物品重量w[i]时,则考虑拿不拿物品i,比较拿i与不拿i的收益价值,m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i])。

依次规则建立(1)最优解结构:将矩阵Ai乘到Aj简记为A[i:j](1<=i<=j<=n),其最少数乘次数为m[i][j],原问题的最优值为m[1][n](即矩阵链不需要断开),当i=j时(只有一个矩阵),m[i][j]=0;(2)递归定义最优值:当i=j时,m[i][j]=0;当i<j时,若计算A[i:j]的最优次序在k和k+1之间断开,则有m[i][j]=min{m[i][k]+m[k+1][j]+pi-1*pk*pj} (i<=k<=j),若将对应于m[i][j]的断开位置记为s[i][j],在计算出最优值m[i][j]后,可以递归地由s[i][j]构造出相应的最优解(3)递归计算最优解:动态规划计算时,依照递归式以自底向上的方式进行计算。

在计算过程中,保存已解决的子问题答案。

每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算,最终得到多项式时间的算法。

时间复杂度O(n3)(4)构造最优解:从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n])。

同理,每个部分的最优加括号方式又可以根据数组s的相应元素得出。

照此递推下去,最终可以确定A[1:n]算法思想:如有两个序列(S1={1,3,4,5,6,7,7,8}和S2={3,5,7,4,8,6,7,8,2})。

假如S1的最后一个元素 与 S2的最后一个元素相等,那么S1和S2的LCS 就等于 {S1减去最后一个元素} 与 {S2减去最后一个元素} 的 LCS 再加上 S1和S2相等的最后一个元素。

假如S1的最后一个元素 与 S2的最后一个元素不等(本例子就是属于这种情况),那么S1和S2的LCS 就等于:{S1减去最后一个元素} 与 S2 的LCS , {S2减去最后一个元素} 与 S1 的LCS 中的最大的那个序列。

(1)最优解结构:设序列 X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则: 若xm=yn ,则zk=xm=yn 且Zk-1是Xm-1和Yn-1的LCS ; 若xm ≠yn 且zk ≠xm ,则Z 是Xm-1和Y 的LCS ; 若xm ≠yn 且zk ≠yn ,则Z 是X 和Yn-1的LCS 。

相关文档
最新文档