基础算法模板
TIPKeep on updating…
Mater Theorem
主定理(Master Theorem)是分析递归法复杂度的重要定理。
Master 公式如下:
- 如果 , 那么复杂度为:
- 如果 , 那么复杂度为:
- 如果 , 那么复杂度为:
addtion: 的时间复杂度为
二分查找
// find max idx of num <= tarint binary_search() { int ans = -1; while (l <= r) { int m = l + ((r - 1) >> 2); // avoid memory overflow if (Array[m] >= tar) { r = m - 1; ans = m; } if (Array[m] < tar) { l = m + 1; } }
return ans;
}树的遍历
树的前序,中序,后序遍历
以下图中的树为例

-
先序:中,左,右
期望输出:
1 2 4 5 3 6 7 -
中序:左,中,右
期望输出:
4 2 5 1 6 3 7 -
后序:左,右,中
期望输出:
4 5 2 6 7 3 1
递归版
前序遍历:
void printPreorder(treeNode *root) { if (root == nullptr) return;
cout << root->val << " "; printPreorder(root->left); printPreorder(root->right);}中序遍历:
void printInorder(treeNode *root) { if (root == nullptr) return;
printInorder(root->left); cout << root->val << " "; printInorder(root->right);}后序遍历:
void printPostorder(treeNode *root) { if (root == nullptr) return;
printPostorder(root->left); printPostorder(root->right); cout << root->val << " ";}栈实现版
NOTE递归法的实现依赖于语言底层实现的系统栈。会将当前没有运行完毕的函数压入系统栈(递归序)。
使用栈的方式实现树的遍历,本质上就是使用内存栈代替系统栈。可以通过理解系统栈的运行机制来实现通过内存栈来代替系统栈。节点入栈等同于将未处理的节点进行记录,通过之后的出栈
pop操作再重新处理该节点。同时还有一个小技巧,上述的“处理节点”,等同于“处理以节点为根节点的子树”。
对于前序遍历,使用栈实现的步骤如下:
- 打印栈顶元素,栈中弹出
- 如果右节点不为空,压入右节点
- 如果左节点不为空,压入左节点
- 重复1,2,3直到栈为空
代码如下:
void printPreorder_stack(treeNode *root) { if (!root) return;
std::stack<treeNode> st; st.push(*root); while (!st.empty()) { treeNode tmp = st.top(); cout << tmp.val << " "; st.pop(); if (tmp.right) st.push(*tmp.right); if (tmp.left) st.push(*tmp.left); } return;}NOTE在前序遍历中,我们会先优先处理栈顶元素,之后在考虑将栈顶元素的左右节点入栈
对于中序遍历,使用栈实现步骤如下:
- 子树左边界进栈,直到左边界为空
- 栈中弹出节点,打印,节点右树重复 1
- 直到没有子树,且栈为空
代码如下:
void printInorder_stack(treeNode *root) { if (!root) return;
std::stack<treeNode> st; treeNode *head = root; // 认为是子树的头节点 while (!st.empty() || head != nullptr) { if (head) { st.push(*head); head = head->left; } else { head = &st.top(); st.pop(); cout << head->val << " "; head = head->right; } }}NOTE在中序遍历中,我们会先找到树最深的左节点。通过
head指针,可以标记当前正在处理的子树
对于后序遍历,有两种实现方式:两个栈版,一个栈版。前者比较好理解,所以将两种版本都放在这里进行参考:
- 两个栈版:
先序为中,左,右。很自然能联想到先’序:中,右,左(上述代码中的压入顺序调整一下即可),那么后序就是将先’序倒置,只需要使用另一个栈收集先’的输出,最后将这个收集栈打印出来即可
- 将栈顶元素收集到收集栈,弹出
- 左节点存在,入栈
- 右节点存在,入栈
- 重复1,2,3直到栈空
代码如下:
void printPostorder_twoStack(treeNode *root) { if (!root) return;
std::stack<treeNode> st; std::stack<treeNode> collect; st.push(*root); while (!st.empty()) { treeNode tmp = st.top(); collect.push(tmp); st.pop(); if (tmp.left) { st.push(*tmp.left); } if (tmp.right) { st.push(*tmp.right); } }
while (!collect.empty()) { cout << collect.top().val << " "; collect.pop(); }}- 一个栈版本:
- 初始化指针
head指向头节点,cur指向当前遍历节点,根节点入栈 - 判断左树是否处理过,没有处理入栈
- 判断右树是否处理过,没有处理入栈
- 左右树都处理过了,则打印当前节点,
head指向栈顶,重复2,3
代码如下:
void printPostorder_sigStack(treeNode *root) { if (!root) return;
std::stack<treeNode *> st; st.push(root); treeNode *head = root; while (!st.empty()) { treeNode *cur = st.top(); if (cur->left != nullptr && head != cur->left && head != cur->right) { st.push(cur->left); } else if (cur->right != nullptr && head != cur->right) { st.push(cur->right); } else { cout << cur->val << " "; head = st.top(); st.pop(); } }}NOTE后序遍历与中序遍历相似的地方是,后序遍历也需要先找到最深的根。不同的是中序遍历是找到最深的子树之后,回到根节点,但后序遍历需要先完全处理
cur为根节点的子树。因此使用head标记已经处理完的子树,按照先左后右的顺序处理深层的子树。
排序
归并排序
归并排序是归并思想在排序上的应用。将排序的复杂度降到了
排序的主要思想:
- 将问题从中点拆分
- 通过
merge合并两部分的结果
以5个数的归并排序为例,可以将问题划分成如下图所示:

可以看到在划分的最后,节点已经不能再划分,只能向上执行merge操作
归并排序完整代码:
#include <iostream>
using namespace std;
const int N = 10001;int n;int arr[N];int tmp[N];
void merge(int l, int m, int r) { int lp = l; int rp = m + 1; int begin = 0; while (lp <= m && rp <= r) { tmp[begin++] = arr[lp] > arr[rp] ? arr[rp++] : arr[lp++]; }
while (rp <= r) { tmp[begin++] = arr[rp++]; } while (lp <= m) { tmp[begin++] = arr[lp++]; }
for (int i = 0; i < begin; i++) { arr[l + i] = tmp[i]; }}
void merge_sort(int l, int r) { if (l >= r) return;
int m = (l + r) >> 1; merge_sort(l, m); merge_sort(m + 1, r);
merge(l, m, r);}
int main() { cin >> n; for (int i = 0; i < n; i++) { int val; cin >> val; arr[i] = val; }
merge_sort(0, n - 1); for (int i = 0; i < n; i++) { cout << arr[i] << " "; }
return 0;}测试链接:洛谷P1177 【模板】排序