bt

Full tutorial on data structure and algorithms

· 106 min read · 数据结构 , 算法 , 考试

All code C and C++ double versions. C uses new/delete + class + STL.


Contents

  1. 复杂度分析
  2. 树与二叉树
  3. 图
  4. 查找
  5. 排序

1. Complexity analysis

1.1 Time complexity

** One sentence: The number of code executions and the number of data n. **

// O(n) — 循环一次
for (int i = 0; i < n; i++) {
printf("%d\n", i);
}
// O(n²) — 嵌套循环
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("%d %d\n", i, j);
}
}
// O(log n) — 每次砍一半
int i = n;
while (i > 1) {
i = i / 2; // 比如二分查找
}
// O(1) — 管你 n 多大,我一步完事
int x = arr[5]; // 数组下标访问

** Common sorting:**

| Complicatedness Name Example |--------|------|------| | O(1) constant | array random access | | O(log n) logarithmic diagonal search, balance tree | O(n) | Linear | Run through arrays | | O(n log n) | Linear logarithm | O(n2) | square | bubble sorting, selection sorting | | O(n) | Retrogression of Fibonacci

1.2 Space complexity

** How much extra memory your algorithm uses. **

// O(1) 空间 — 只用了几个变量
int sum(int arr[], int n) {
int total = 0;
for (int i = 0; i < n; i++) {
total += arr[i];
}
return total;
}
// O(n) 空间 — 新建了一个等长数组
int* double_arr(int arr[], int n) {
int* result = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
result[i] = arr[i] * 2;
}
return result; // 调用者负责 free
}

1.3 Time complexity of regression

Master Theorem:

T(n) = a × T(n/b) + f(n)
情况1:f(n) = O(n^(log_b(a) - ε)) → T(n) = Θ(n^(log_b(a)))
情况2:f(n) = Θ(n^(log_b(a))) → T(n) = Θ(n^(log_b(a)) × log n)
情况3:f(n) = Ω(n^(log_b(a) + ε)) → T(n) = Θ(f(n))

** Field inspection (direct back):**

| Algorithms, cylindrical, repulsive, complex, cylindrical. |------|--------|--------| | |T(n)=T(n/2)+O(1)|O(logn)| | Grouping |T(n)=2T(n/2)+O(n)|O(n logn)| | Across the fork tree |T(n)=2T(n/2)+O(1)|O(n)| | |T(n)=2T(n/2)+O(n)|O(n logn)|


2. Trees and fork trees

2.1 Basic concepts of trees

A ← 根节点 (root)
/ \
B C ← 内部节点 (internal node)
/ \ \
D E F ← 叶节点 (leaf node)

** Core terms:**

  • ** Height**: the number of sides from this node to the longest leaves. Leaf height = 0.
  • Depth (Depth): number of sides from root to node. Root depth = 0.
  • ** (Degree)**: There are several children at one node.
  • ** Subtree**: a tree rooted at a certain node.

Bream of Children (most common)

// ===== C 版 =====
typedef struct TreeNode {
int val;
struct TreeNode* first_child; // 第一个孩子
struct TreeNode* next_sibling; // 下一个兄弟
} TreeNode;
// ===== C++ 版 =====
struct TreeNode {
int val;
TreeNode* first_child = nullptr;
TreeNode* next_sibling = nullptr;
};

** Most of the scenes are directly on the list of children:**

// C++ 推荐
#include <vector>
struct TreeNode {
int val;
std::vector<TreeNode*> children;
};

2.2 Diagonal trees

** Trees with up to two children per node. **

// ===== C 版 =====
typedef struct BinTreeNode {
int val;
struct BinTreeNode* left;
struct BinTreeNode* right;
} BinTreeNode;
// 创建节点
BinTreeNode* create_node(int val) {
BinTreeNode* node = (BinTreeNode*)malloc(sizeof(BinTreeNode));
node->val = val;
node->left = NULL;
node->right = NULL;
return node;
}
// ===== C++ 版 =====
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

2.2.1 THREE COURSE - THE CORE

1
/ \
2 3
/ \ \
4 5 6
前序 (根左右): 1 2 4 5 3 6
中序 (左根右): 4 2 5 1 3 6
后序 (左右根): 4 5 2 6 3 1
层序 (bfs): 1 2 3 4 5 6
// ===== C 版:递归 =====
void preorder(BinTreeNode* root) {
if (!root) return;
printf("%d ", root->val);
preorder(root->left);
preorder(root->right);
}
void inorder(BinTreeNode* root) {
if (!root) return;
inorder(root->left);
printf("%d ", root->val);
inorder(root->right);
}
void postorder(BinTreeNode* root) {
if (!root) return;
postorder(root->left);
postorder(root->right);
printf("%d ", root->val);
}
// ===== C++ 版:递归 =====
void preorder(TreeNode* root) {
if (!root) return;
cout << root->val << " ";
preorder(root->left);
preorder(root->right);
}
// ===== C 版:迭代前序 =====
// 栈:先压右再压左,弹出时先左后右
void preorder_iter(BinTreeNode* root) {
if (!root) return;
BinTreeNode** stack = (BinTreeNode**)malloc(100 * sizeof(BinTreeNode*));
int top = -1;
stack[++top] = root;
while (top >= 0) {
BinTreeNode* node = stack[top--];
printf("%d ", node->val);
if (node->right) stack[++top] = node->right;
if (node->left) stack[++top] = node->left;
}
free(stack);
}
// ===== C 版:迭代中序(一路往左走)=====
void inorder_iter(BinTreeNode* root) {
BinTreeNode** stack = (BinTreeNode**)malloc(100 * sizeof(BinTreeNode*));
int top = -1;
BinTreeNode* cur = root;
while (cur || top >= 0) {
while (cur) { // 一路走到最左
stack[++top] = cur;
cur = cur->left;
}
cur = stack[top--]; // 弹出最左
printf("%d ", cur->val);
cur = cur->right; // 转向右子树
}
free(stack);
}
// ===== C 版:迭代后序(前序(根右左) 反转)=====
void postorder_iter(BinTreeNode* root) {
if (!root) return;
int* result = (int*)malloc(100 * sizeof(int)); // 存结果
int idx = 0;
BinTreeNode** stack = (BinTreeNode**)malloc(100 * sizeof(BinTreeNode*));
int top = -1;
stack[++top] = root;
while (top >= 0) {
BinTreeNode* node = stack[top--];
result[idx++] = node->val; // 存放(根右左顺序)
if (node->left) stack[++top] = node->left;
if (node->right) stack[++top] = node->right;
}
// 反转输出
for (int i = idx - 1; i >= 0; i--) {
printf("%d ", result[i]);
}
free(result);
free(stack);
}
// ===== C++ 版:迭代(用 STL stack)=====
#include <stack>
#include <vector>
void preorder_iter(TreeNode* root) {
if (!root) return;
std::stack<TreeNode*> stk;
stk.push(root);
while (!stk.empty()) {
TreeNode* node = stk.top(); stk.pop();
cout << node->val << " ";
if (node->right) stk.push(node->right);
if (node->left) stk.push(node->left);
}
}
void inorder_iter(TreeNode* root) {
std::stack<TreeNode*> stk;
TreeNode* cur = root;
while (cur || !stk.empty()) {
while (cur) {
stk.push(cur);
cur = cur->left;
}
cur = stk.top(); stk.pop();
cout << cur->val << " ";
cur = cur->right;
}
}
void postorder_iter(TreeNode* root) {
if (!root) return;
std::vector<int> result;
std::stack<TreeNode*> stk;
stk.push(root);
while (!stk.empty()) {
TreeNode* node = stk.top(); stk.pop();
result.push_back(node->val);
if (node->left) stk.push(node->left);
if (node->right) stk.push(node->right);
}
for (auto it = result.rbegin(); it != result.rend(); ++it) {
cout << *it << " ";
}
}
// ===== 层序遍历 (BFS) =====
// C 版:用数组模拟队列
#include <stdio.h>
#include <stdlib.h>
void level_order(BinTreeNode* root) {
if (!root) return;
BinTreeNode** queue = (BinTreeNode**)malloc(100 * sizeof(BinTreeNode*));
int front = 0, rear = 0;
queue[rear++] = root;
while (front < rear) {
BinTreeNode* node = queue[front++];
printf("%d ", node->val);
if (node->left) queue[rear++] = node->left;
if (node->right) queue[rear++] = node->right;
}
free(queue);
}
// C++ 版:用 std::queue
#include <queue>
void level_order(TreeNode* root) {
if (!root) return;
std::queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front(); q.pop();
cout << node->val << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}

2.3 Trident Search Tree (BST)

**Rule: the value of the left tree < the root value < the value of the right tree. **

8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
// ===== C 版 =====
#include <stdio.h>
#include <stdlib.h>
typedef struct BSTNode {
int val;
struct BSTNode* left;
struct BSTNode* right;
} BSTNode;
BSTNode* bst_create(int val) {
BSTNode* node = (BSTNode*)malloc(sizeof(BSTNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
// 查找:一路比大小
BSTNode* bst_search(BSTNode* root, int val) {
BSTNode* cur = root;
while (cur) {
if (val == cur->val)
return cur;
else if (val < cur->val)
cur = cur->left;
else
cur = cur->right;
}
return NULL;
}
// 插入
BSTNode* bst_insert(BSTNode* root, int val) {
if (!root) return bst_create(val);
BSTNode* cur = root;
while (1) {
if (val < cur->val) {
if (cur->left)
cur = cur->left;
else {
cur->left = bst_create(val);
break;
}
} else {
if (cur->right)
cur = cur->right;
else {
cur->right = bst_create(val);
break;
}
}
}
return root;
}
// 找最小值
BSTNode* bst_min(BSTNode* node) {
while (node->left) node = node->left;
return node;
}
// 删除
BSTNode* bst_delete(BSTNode* root, int val) {
if (!root) return NULL;
if (val < root->val)
root->left = bst_delete(root->left, val);
else if (val > root->val)
root->right = bst_delete(root->right, val);
else {
// 情况1+2:0个或1个孩子
if (!root->left) {
BSTNode* tmp = root->right;
free(root);
return tmp;
}
if (!root->right) {
BSTNode* tmp = root->left;
free(root);
return tmp;
}
// 情况3:两个小孩 → 找后继(右子树最小),替换
BSTNode* successor = bst_min(root->right);
root->val = successor->val;
root->right = bst_delete(root->right, successor->val);
}
return root;
}
// ===== C++ 版 =====
class BST {
public:
struct Node {
int val;
Node* left;
Node* right;
Node(int x) : val(x), left(nullptr), right(nullptr) {}
};
Node* root = nullptr;
Node* search(int val) {
Node* cur = root;
while (cur) {
if (val == cur->val) return cur;
cur = (val < cur->val) ? cur->left : cur->right;
}
return nullptr;
}
void insert(int val) {
if (!root) { root = new Node(val); return; }
Node* cur = root;
while (true) {
if (val < cur->val) {
if (cur->left) cur = cur->left;
else { cur->left = new Node(val); break; }
} else {
if (cur->right) cur = cur->right;
else { cur->right = new Node(val); break; }
}
}
}
Node* _min(Node* node) {
while (node->left) node = node->left;
return node;
}
Node* _delete(Node* node, int val) {
if (!node) return nullptr;
if (val < node->val)
node->left = _delete(node->left, val);
else if (val > node->val)
node->right = _delete(node->right, val);
else {
if (!node->left) { Node* tmp = node->right; delete node; return tmp; }
if (!node->right) { Node* tmp = node->left; delete node; return tmp; }
Node* succ = _min(node->right);
node->val = succ->val;
node->right = _delete(node->right, succ->val);
}
return node;
}
void remove(int val) { root = _delete(root, val); }
};

2.4 Balance fork tree - AVL tree

// ===== C 版 =====
typedef struct AVLNode {
int val;
struct AVLNode* left;
struct AVLNode* right;
int height;
} AVLNode;
AVLNode* avl_create(int val) {
AVLNode* node = (AVLNode*)malloc(sizeof(AVLNode));
node->val = val;
node->left = node->right = NULL;
node->height = 1;
return node;
}
int height(AVLNode* n) { return n ? n->height : 0; }
int max(int a, int b) { return a > b ? a : b; }
int balance_factor(AVLNode* n) { return n ? height(n->left) - height(n->right) : 0; }
void update_height(AVLNode* n) {
n->height = 1 + max(height(n->left), height(n->right));
}
// 右旋
AVLNode* rotate_right(AVLNode* y) {
AVLNode* x = y->left;
AVLNode* T2 = x->right;
x->right = y;
y->left = T2;
update_height(y);
update_height(x);
return x;
}
// 左旋
AVLNode* rotate_left(AVLNode* x) {
AVLNode* y = x->right;
AVLNode* T2 = y->left;
y->left = x;
x->right = T2;
update_height(x);
update_height(y);
return y;
}
AVLNode* avl_insert(AVLNode* node, int val) {
// 1. 普通 BST 插入
if (!node) return avl_create(val);
if (val < node->val)
node->left = avl_insert(node->left, val);
else if (val > node->val)
node->right = avl_insert(node->right, val);
else
return node; // 重复值不管
// 2. 更新高度
update_height(node);
// 3. 检查平衡 + 旋转
int balance = balance_factor(node);
// LL
if (balance > 1 && val < node->left->val)
return rotate_right(node);
// RR
if (balance < -1 && val > node->right->val)
return rotate_left(node);
// LR
if (balance > 1 && val > node->left->val) {
node->left = rotate_left(node->left);
return rotate_right(node);
}
// RL
if (balance < -1 && val < node->right->val) {
node->right = rotate_right(node->right);
return rotate_left(node);
}
return node;
}
// ===== C++ 版 =====
struct AVLNode {
int val;
AVLNode* left;
AVLNode* right;
int height;
AVLNode(int x) : val(x), left(nullptr), right(nullptr), height(1) {}
};
int get_height(AVLNode* n) { return n ? n->height : 0; }
int get_balance(AVLNode* n) { return n ? get_height(n->left) - get_height(n->right) : 0; }
AVLNode* rotate_right(AVLNode* y) {
AVLNode* x = y->left;
AVLNode* T2 = x->right;
x->right = y;
y->left = T2;
y->height = 1 + std::max(get_height(y->left), get_height(y->right));
x->height = 1 + std::max(get_height(x->left), get_height(x->right));
return x;
}
AVLNode* rotate_left(AVLNode* x) {
AVLNode* y = x->right;
AVLNode* T2 = y->left;
y->left = x;
x->right = T2;
x->height = 1 + std::max(get_height(x->left), get_height(x->right));
y->height = 1 + std::max(get_height(y->left), get_height(y->right));
return y;
}
AVLNode* avl_insert(AVLNode* node, int val) {
if (!node) return new AVLNode(val);
if (val < node->val)
node->left = avl_insert(node->left, val);
else if (val > node->val)
node->right = avl_insert(node->right, val);
else
return node;
node->height = 1 + std::max(get_height(node->left), get_height(node->right));
int balance = get_balance(node);
if (balance > 1 && val < node->left->val) // LL
return rotate_right(node);
if (balance < -1 && val > node->right->val) // RR
return rotate_left(node);
if (balance > 1 && val > node->left->val) { // LR
node->left = rotate_left(node->left);
return rotate_right(node);
}
if (balance < -1 && val < node->right->val) { // RL
node->right = rotate_right(node->right);
return rotate_left(node);
}
return node;
}

** Four rotation rapid memories:**

LL: y x
/ \ / \
x T4 → T1 y
/ \ / \
T1 T2 T2 T4
LR: z z x
/ \ / \ / \
y T4 → x T4 → y z
/ \ / \ / \ / \
T1 x y T3 T1 T2 T3 T4
/ \ / \
T2 T3 T1 T2
RR: x y
/ \ / \
T1 y → x T4
/ \ / \
T2 T4 T1 T2
RL: z z x
/ \ / \ / \
T1 y → T1 x → z y
/ \ / \ / \ / \
x T4 T2 y T1 T2 T3 T4
/ \ / \
T2 T3 T3 T4

2.5 Red and black trees — industry pets

** Five iron laws:**

  1. Node is either red or black.
  2. The roots are black.
  3. The leaves are black.
  4. The two children at the red node must be black.
  5. Any node to the path of all its offspring, with the same number of black nodes
// ===== C 版 =====
#include <stdio.h>
#include <stdlib.h>
#define RED 1
#define BLACK 0
typedef struct RBNode {
int val;
int color;
struct RBNode* left;
struct RBNode* right;
struct RBNode* parent;
} RBNode;
RBNode* NIL; // 哨兵节点(全局,黑色叶节点)
RBNode* rb_create(int val, int color) {
RBNode* node = (RBNode*)malloc(sizeof(RBNode));
node->val = val;
node->color = color;
node->left = NIL;
node->right = NIL;
node->parent = NULL;
return node;
}
void rb_init() {
NIL = (RBNode*)malloc(sizeof(RBNode));
NIL->color = BLACK;
NIL->left = NIL->right = NIL->parent = NULL;
}
void rb_left_rotate(RBNode** root, RBNode* x) {
RBNode* y = x->right;
x->right = y->left;
if (y->left != NIL) y->left->parent = x;
y->parent = x->parent;
if (!x->parent) *root = y;
else if (x == x->parent->left) x->parent->left = y;
else x->parent->right = y;
y->left = x;
x->parent = y;
}
void rb_right_rotate(RBNode** root, RBNode* y) {
RBNode* x = y->left;
y->left = x->right;
if (x->right != NIL) x->right->parent = y;
x->parent = y->parent;
if (!y->parent) *root = x;
else if (y == y->parent->right) y->parent->right = x;
else y->parent->left = x;
x->right = y;
y->parent = x;
}
void rb_insert_fixup(RBNode** root, RBNode* z) {
while (z->parent && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
RBNode* y = z->parent->parent->right; // 叔叔
if (y->color == RED) { // 情况1:叔叔红
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) { // 情况2
z = z->parent;
rb_left_rotate(root, z);
}
z->parent->color = BLACK; // 情况3
z->parent->parent->color = RED;
rb_right_rotate(root, z->parent->parent);
}
} else { // 对称
RBNode* y = z->parent->parent->left;
if (y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->left) {
z = z->parent;
rb_right_rotate(root, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rb_left_rotate(root, z->parent->parent);
}
}
}
(*root)->color = BLACK;
}
void rb_insert(RBNode** root, int val) {
RBNode* z = rb_create(val, RED);
RBNode* y = NULL;
RBNode* x = *root;
while (x != NIL) {
y = x;
x = (val < x->val) ? x->left : x->right;
}
z->parent = y;
if (!y) *root = z;
else if (val < y->val) y->left = z;
else y->right = z;
rb_insert_fixup(root, z);
}
// ===== C++ 版 =====
#include <iostream>
enum Color { RED, BLACK };
template<typename T>
struct RBNode {
T val;
Color color;
RBNode *left, *right, *parent;
RBNode(T x) : val(x), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
template<typename T>
class RedBlackTree {
RBNode<T>* root;
RBNode<T>* NIL; // 哨兵
void left_rotate(RBNode<T>* x) {
RBNode<T>* y = x->right;
x->right = y->left;
if (y->left != NIL) y->left->parent = x;
y->parent = x->parent;
if (!x->parent) root = y;
else if (x == x->parent->left) x->parent->left = y;
else x->parent->right = y;
y->left = x;
x->parent = y;
}
void right_rotate(RBNode<T>* y) {
RBNode<T>* x = y->left;
y->left = x->right;
if (x->right != NIL) x->right->parent = y;
x->parent = y->parent;
if (!y->parent) root = x;
else if (y == y->parent->right) y->parent->right = x;
else y->parent->left = x;
x->right = y;
y->parent = x;
}
void insert_fixup(RBNode<T>* z) {
while (z->parent && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
RBNode<T>* y = z->parent->parent->right;
if (y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
z = z->parent;
left_rotate(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
right_rotate(z->parent->parent);
}
} else {
RBNode<T>* y = z->parent->parent->left;
if (y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->left) {
z = z->parent;
right_rotate(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
left_rotate(z->parent->parent);
}
}
}
root->color = BLACK;
}
public:
RedBlackTree() {
NIL = new RBNode<T>(0);
NIL->color = BLACK;
NIL->left = NIL->right = NIL->parent = nullptr;
root = NIL;
}
void insert(T val) {
RBNode<T>* z = new RBNode<T>(val);
z->left = z->right = NIL;
RBNode<T>* y = nullptr;
RBNode<T>* x = root;
while (x != NIL) {
y = x;
x = (val < x->val) ? x->left : x->right;
}
z->parent = y;
if (!y) root = z;
else if (val < y->val) y->left = z;
else y->right = z;
insert_fixup(z);
}
};

** Why does industry use red trees instead of AVL?**

  • AVL strictly balance search speed, but insert remove more rotations
  • Red and black trees relax the balance poignantly search slightly (up to one layer) but insert deletion less (up to three)
  • C++ std::map、Java TreeMap, Linux CFS Scheduler, Poll All red and black trees

2.6 Stacks (Heap)

** The pile is a full fork tree stored in arrays. **

最小堆规则:父 ≤ 子(根最小)
数组:父 (i-1)/2,左子 2i+1,右子 2i+2
1
/ \
3 5
/ \ /
7 9 6
// ===== C 版:最小堆 =====
typedef struct {
int* data;
int size;
int capacity;
} MinHeap;
MinHeap* heap_create(int cap) {
MinHeap* h = (MinHeap*)malloc(sizeof(MinHeap));
h->data = (int*)malloc(cap * sizeof(int));
h->size = 0;
h->capacity = cap;
return h;
}
void heap_sift_up(MinHeap* h, int i) {
while (i > 0) {
int parent = (i - 1) / 2;
if (h->data[i] < h->data[parent]) {
int tmp = h->data[i];
h->data[i] = h->data[parent];
h->data[parent] = tmp;
i = parent;
} else break;
}
}
void heap_sift_down(MinHeap* h, int i) {
while (1) {
int smallest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < h->size && h->data[left] < h->data[smallest])
smallest = left;
if (right < h->size && h->data[right] < h->data[smallest])
smallest = right;
if (smallest == i) break;
int tmp = h->data[i];
h->data[i] = h->data[smallest];
h->data[smallest] = tmp;
i = smallest;
}
}
void heap_push(MinHeap* h, int val) {
if (h->size >= h->capacity) return; // 需要扩容,简化处理
h->data[h->size] = val;
heap_sift_up(h, h->size);
h->size++;
}
int heap_pop(MinHeap* h) {
if (h->size == 0) return -1;
int val = h->data[0];
h->data[0] = h->data[--h->size];
if (h->size > 0) heap_sift_down(h, 0);
return val;
}
int heap_top(MinHeap* h) { return h->size > 0 ? h->data[0] : -1; }
// O(n) 建堆:从最后一个非叶节点向前 sift_down
void heap_build(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--) {
// sift_down on arr[i]
int cur = i;
while (1) {
int smallest = cur;
int left = 2 * cur + 1;
int right = 2 * cur + 2;
if (left < n && arr[left] < arr[smallest]) smallest = left;
if (right < n && arr[right] < arr[smallest]) smallest = right;
if (smallest == cur) break;
int tmp = arr[cur];
arr[cur] = arr[smallest];
arr[smallest] = tmp;
cur = smallest;
}
}
}
// ===== C++ 版 =====
#include <queue>
#include <vector>
// STL 直接调:默认大顶堆
std::priority_queue<int> max_heap;
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;
max_heap.push(5);
int top = max_heap.top();
max_heap.pop();
// 手写
class MinHeap {
std::vector<int> data;
public:
void push(int val) {
data.push_back(val);
int i = data.size() - 1;
while (i > 0) {
int p = (i - 1) / 2;
if (data[i] < data[p]) {
std::swap(data[i], data[p]);
i = p;
} else break;
}
}
int pop() {
if (data.empty()) return -1;
int val = data[0];
data[0] = data.back();
data.pop_back();
int i = 0, n = data.size();
while (true) {
int smallest = i;
int l = 2 * i + 1, r = 2 * i + 2;
if (l < n && data[l] < data[smallest]) smallest = l;
if (r < n && data[r] < data[smallest]) smallest = r;
if (smallest == i) break;
std::swap(data[i], data[smallest]);
i = smallest;
}
return val;
}
int top() { return data.empty() ? -1 : data[0]; }
bool empty() { return data.empty(); }
};

2.7 Hafmann Tree

// C 版:哈夫曼编码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct HuffNode {
char ch;
int freq;
struct HuffNode* left;
struct HuffNode* right;
} HuffNode;
// 用最小堆来构造(简单起见,直接选最小的两个)
HuffNode* build_huffman(char chars[], int freqs[], int n) {
// 把每个字符做成节点,放到"森林"里
HuffNode** nodes = (HuffNode**)malloc(n * sizeof(HuffNode*));
for (int i = 0; i < n; i++) {
nodes[i] = (HuffNode*)malloc(sizeof(HuffNode));
nodes[i]->ch = chars[i];
nodes[i]->freq = freqs[i];
nodes[i]->left = nodes[i]->right = NULL;
}
int size = n;
while (size > 1) {
// 找最小和次小的两个
int min1 = 0, min2 = 1;
if (nodes[min1]->freq > nodes[min2]->freq) {
int tmp = min1; min1 = min2; min2 = tmp;
}
for (int i = 2; i < size; i++) {
if (nodes[i]->freq < nodes[min1]->freq) {
min2 = min1;
min1 = i;
} else if (nodes[i]->freq < nodes[min2]->freq) {
min2 = i;
}
}
// 合并
HuffNode* parent = (HuffNode*)malloc(sizeof(HuffNode));
parent->ch = '\0';
parent->freq = nodes[min1]->freq + nodes[min2]->freq;
parent->left = nodes[min1];
parent->right = nodes[min2];
// 替换掉 min1,删除 min2
nodes[min1] = parent;
nodes[min2] = nodes[size - 1];
size--;
}
HuffNode* root = nodes[0];
free(nodes);
return root;
}
void print_codes(HuffNode* root, char* code, int depth) {
if (!root->left && !root->right) {
code[depth] = '\0';
printf(" %c : %s\n", root->ch, code);
return;
}
code[depth] = '0';
print_codes(root->left, code, depth + 1);
code[depth] = '1';
print_codes(root->right, code, depth + 1);
}
// 使用示例:
// char chars[] = {'a','b','c','d','e','f'};
// int freqs[] = {45, 13, 12, 16, 9, 5};
// HuffNode* tree = build_huffman(chars, freqs, 6);
// char code[100];
// print_codes(tree, code, 0);

Figure

3.1 Basic concepts of the figure

0 --- 1
| \ |
| \ |
3 --- 2

** Three storage methods:**

// ===== 1. 邻接矩阵 — O(V²),稠密图 =====
#define MAX_V 100
int graph[MAX_V][MAX_V]; // 0=无边, 1=有边 (或存权重)
// 访问: graph[0][1] = 1 表示 0→1 有边
// ===== 2. 邻接表 — O(V+E),最常用 =====
// C 版
#define MAX_V 100
typedef struct EdgeNode {
int dest;
int weight;
struct EdgeNode* next;
} EdgeNode;
typedef struct {
EdgeNode* head;
} AdjList[MAX_V];
void add_edge(AdjList graph, int src, int dest) {
EdgeNode* node = (EdgeNode*)malloc(sizeof(EdgeNode));
node->dest = dest;
node->weight = 1;
node->next = graph[src].head;
graph[src].head = node;
}
// C++ 版
#include <vector>
#include <utility>
std::vector<std::pair<int, int>> adj[100]; // adj[u] = {(v, w), ...}
void add_edge(int u, int v, int w = 1) {
adj[u].push_back({v, w});
}
// ===== 3. 边列表 — O(E),Kruskal 用 =====
struct Edge {
int u, v, w;
};
std::vector<Edge> edges = {{0,1,4}, {0,2,1}, {1,3,1}, {2,1,2}};
// ===== C 版 =====
#include <stdbool.h>
bool visited[MAX_V];
void dfs_c(AdjList graph, int v) {
visited[v] = true;
printf("%d ", v);
for (EdgeNode* e = graph[v].head; e; e = e->next) {
if (!visited[e->dest]) {
dfs_c(graph, e->dest);
}
}
}
void dfs_all(AdjList graph, int V) {
memset(visited, 0, sizeof(visited));
for (int i = 0; i < V; i++) {
if (!visited[i]) dfs_c(graph, i);
}
}
// ===== C++ 版 =====
#include <vector>
using namespace std;
void dfs(vector<int> adj[], int v, bool visited[]) {
visited[v] = true;
cout << v << " ";
for (int neighbor : adj[v]) {
if (!visited[neighbor]) dfs(adj, neighbor, visited);
}
}
// 迭代版(栈)
void dfs_iter(vector<int> adj[], int start, int V) {
bool visited[V] = {false};
stack<int> stk;
stk.push(start);
while (!stk.empty()) {
int v = stk.top(); stk.pop();
if (!visited[v]) {
visited[v] = true;
cout << v << " ";
// 倒序压栈,顺序不变
for (auto it = adj[v].rbegin(); it != adj[v].rend(); ++it) {
if (!visited[*it]) stk.push(*it);
}
}
}
}

DFS four classic applications:

// ===== 1. 检测环(无向图)=====
bool has_cycle_util(vector<int> adj[], int v, bool visited[], int parent) {
visited[v] = true;
for (int neighbor : adj[v]) {
if (!visited[neighbor]) {
if (has_cycle_util(adj, neighbor, visited, v))
return true;
} else if (neighbor != parent) {
return true; // 访问过且不是父节点 = 有环
}
}
return false;
}
bool has_cycle(vector<int> adj[], int V) {
bool visited[V] = {false};
for (int i = 0; i < V; i++) {
if (!visited[i]) {
if (has_cycle_util(adj, i, visited, -1))
return true;
}
}
return false;
}
// ===== 2. 拓扑排序(有向无环图 DAG)=====
void topo_dfs(vector<int> adj[], int v, bool visited[], stack<int>& stk) {
visited[v] = true;
for (int neighbor : adj[v]) {
if (!visited[neighbor]) topo_dfs(adj, neighbor, visited, stk);
}
stk.push(v); // 后序
}
vector<int> topological_sort(vector<int> adj[], int V) {
bool visited[V] = {false};
stack<int> stk;
for (int i = 0; i < V; i++) {
if (!visited[i]) topo_dfs(adj, i, visited, stk);
}
vector<int> result;
while (!stk.empty()) {
result.push_back(stk.top()); stk.pop();
}
return result; // 后序反转 = 拓扑序
}
// ===== 3. 连通分量 =====
void dfs_cc(vector<int> adj[], int v, bool visited[], vector<int>& comp) {
visited[v] = true;
comp.push_back(v);
for (int neighbor : adj[v]) {
if (!visited[neighbor]) dfs_cc(adj, neighbor, visited, comp);
}
}
vector<vector<int>> connected_components(vector<int> adj[], int V) {
bool visited[V] = {false};
vector<vector<int>> components;
for (int i = 0; i < V; i++) {
if (!visited[i]) {
vector<int> comp;
dfs_cc(adj, i, visited, comp);
components.push_back(comp);
}
}
return components;
}
// ===== 4. 二分图检测 =====
bool is_bipartite_util(vector<int> adj[], int v, int color[]) {
for (int neighbor : adj[v]) {
if (color[neighbor] == -1) {
color[neighbor] = 1 - color[v];
if (!is_bipartite_util(adj, neighbor, color))
return false;
} else if (color[neighbor] == color[v]) {
return false;
}
}
return true;
}
bool is_bipartite(vector<int> adj[], int V) {
int color[V];
fill(color, color + V, -1);
for (int i = 0; i < V; i++) {
if (color[i] == -1) {
color[i] = 0;
if (!is_bipartite_util(adj, i, color))
return false;
}
}
return true;
}
// ===== C++ 版 =====
#include <queue>
#include <vector>
using namespace std;
void bfs(vector<int> adj[], int start, int V) {
bool visited[V] = {false};
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int v = q.front(); q.pop();
cout << v << " ";
for (int neighbor : adj[v]) {
if (!visited[neighbor]) {
visited[neighbor] = true;
q.push(neighbor);
}
}
}
}
// 最短路径(无权图)
vector<int> shortest_path(vector<int> adj[], int V, int start, int end) {
bool visited[V] = {false};
int parent[V];
fill(parent, parent + V, -1);
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int v = q.front(); q.pop();
if (v == end) {
// 回溯路径
vector<int> path;
for (int cur = end; cur != -1; cur = parent[cur])
path.push_back(cur);
reverse(path.begin(), path.end());
return path;
}
for (int neighbor : adj[v]) {
if (!visited[neighbor]) {
visited[neighbor] = true;
parent[neighbor] = v;
q.push(neighbor);
}
}
}
return {}; // 不可达
}
// 层序遍历
vector<vector<int>> bfs_levels(vector<int> adj[], int V, int start) {
vector<vector<int>> levels;
bool visited[V] = {false};
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int size = q.size();
vector<int> level;
for (int i = 0; i < size; i++) {
int v = q.front(); q.pop();
level.push_back(v);
for (int neighbor : adj[v]) {
if (!visited[neighbor]) {
visited[neighbor] = true;
q.push(neighbor);
}
}
}
levels.push_back(level);
}
return levels;
}

3.4 Dijkstra - Single Source Shortest Path (non-negative)

// ===== C++:邻接表 + 优先队列 =====
#include <queue>
#include <vector>
#include <climits>
using namespace std;
typedef pair<int, int> pii; // {距离, 节点}
vector<int> dijkstra(vector<pii> adj[], int V, int start) {
vector<int> dist(V, INT_MAX);
dist[start] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({0, start});
while (!pq.empty()) {
auto [d, v] = pq.top(); pq.pop();
if (d > dist[v]) continue; // 过期值跳过
for (auto [neighbor, w] : adj[v]) {
if (dist[v] + w < dist[neighbor]) {
dist[neighbor] = dist[v] + w;
pq.push({dist[neighbor], neighbor});
}
}
}
return dist;
}
// ===== C 版:邻接矩阵 + 手动实现 =====
#include <limits.h>
#include <stdbool.h>
void dijkstra_c(int graph[MAX_V][MAX_V], int V, int start, int dist[]) {
bool visited[MAX_V] = {false};
for (int i = 0; i < V; i++) dist[i] = INT_MAX;
dist[start] = 0;
for (int count = 0; count < V - 1; count++) {
// 选最小的未访问节点
int u = -1, min_dist = INT_MAX;
for (int i = 0; i < V; i++) {
if (!visited[i] && dist[i] < min_dist) {
min_dist = dist[i];
u = i;
}
}
if (u == -1) break;
visited[u] = true;
// 松弛
for (int v = 0; v < V; v++) {
if (!visited[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
}
// 时间复杂度: O((V+E) log V) — 堆优化版 | O(V²) — 朴素版

3.5 Bellman-Ford - Disposable negative rights Side

// ===== C++ 版 =====
#include <climits>
#include <vector>
using namespace std;
struct Edge { int u, v, w; };
// 返回 {距离数组, 是否有负环}
pair<vector<int>, bool> bellman_ford(int V, vector<Edge>& edges, int start) {
vector<int> dist(V, INT_MAX);
dist[start] = 0;
// 松弛 V-1 轮
for (int i = 0; i < V - 1; i++) {
bool updated = false;
for (auto& e : edges) {
if (dist[e.u] != INT_MAX && dist[e.u] + e.w < dist[e.v]) {
dist[e.v] = dist[e.u] + e.w;
updated = true;
}
}
if (!updated) break; // 提前退出
}
// 第 V 轮:检测负环
for (auto& e : edges) {
if (dist[e.u] != INT_MAX && dist[e.u] + e.w < dist[e.v]) {
return {dist, true}; // 存在负权环
}
}
return {dist, false};
}
// ===== C 版 =====
bool bellman_ford_c(int V, Edge edges[], int E, int start, int dist[]) {
for (int i = 0; i < V; i++) dist[i] = INT_MAX;
dist[start] = 0;
for (int i = 0; i < V - 1; i++) {
int updated = 0;
for (int j = 0; j < E; j++) {
int u = edges[j].u, v = edges[j].v, w = edges[j].w;
if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
updated = 1;
}
}
if (!updated) break;
}
for (int j = 0; j < E; j++) {
int u = edges[j].u, v = edges[j].v, w = edges[j].w;
if (dist[u] != INT_MAX && dist[u] + w < dist[v])
return true; // 负环
}
return false;
}
// 时间复杂度: O(V×E)

3.6 Floyd-Warshall - All points to the shortest path

// ===== C++ 版 =====
// dp[k][i][j] = 只用前k个中间节点,i→j 的最短距离
const int INF = 1e9;
void floyd_warshall(vector<vector<int>>& dist, int V) {
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][k] != INF && dist[k][j] != INF
&& dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
// ===== C 版 =====
void floyd_warshall_c(int dist[MAX_V][MAX_V], int V) {
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX
&& dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
// 时间复杂度: O(V³)

3.7 Minimal generation of trees MST

Prim - Point Priority

// ===== C++ 版 =====
#include <queue>
#include <vector>
using namespace std;
typedef pair<int, int> pii; // {权重, 节点}
int prim(vector<pii> adj[], int V) {
vector<bool> in_mst(V, false);
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({0, 0}); // {权重, 节点}
int total_weight = 0;
int edges_in_mst = 0;
while (!pq.empty() && edges_in_mst < V) {
auto [w, v] = pq.top(); pq.pop();
if (in_mst[v]) continue;
in_mst[v] = true;
total_weight += w;
edges_in_mst++;
for (auto [neighbor, weight] : adj[v]) {
if (!in_mst[neighbor])
pq.push({weight, neighbor});
}
}
return total_weight;
}
// 时间复杂度: O((V+E) log V)

Kruskal — border priority (slush)

// ===== Kruskal + 并查集 =====
// 先实现并查集
class UnionFind {
vector<int> parent, rank;
public:
UnionFind(int n) : parent(n), rank(n, 0) {
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]); // 路径压缩
return parent[x];
}
bool unite(int x, int y) {
int rx = find(x), ry = find(y);
if (rx == ry) return false;
if (rank[rx] < rank[ry]) parent[rx] = ry;
else if (rank[rx] > rank[ry]) parent[ry] = rx;
else { parent[ry] = rx; rank[rx]++; }
return true;
}
};
struct Edge { int u, v, w; };
int kruskal(int V, vector<Edge>& edges) {
sort(edges.begin(), edges.end(),
[](Edge& a, Edge& b) { return a.w < b.w; });
UnionFind uf(V);
int total = 0;
int cnt = 0; // 已加入边数
for (auto& e : edges) {
if (uf.unite(e.u, e.v)) {
total += e.w;
cnt++;
if (cnt == V - 1) break;
}
}
return total;
}
// 时间复杂度: O(E log E) = O(E log V)
// ===== C 版:并查集 =====
typedef struct {
int parent[MAX_V];
int rank[MAX_V];
} UnionFind;
void uf_init(UnionFind* uf, int n) {
for (int i = 0; i < n; i++) {
uf->parent[i] = i;
uf->rank[i] = 0;
}
}
int uf_find(UnionFind* uf, int x) {
if (uf->parent[x] != x)
uf->parent[x] = uf_find(uf, uf->parent[x]);
return uf->parent[x];
}
bool uf_unite(UnionFind* uf, int x, int y) {
int rx = uf_find(uf, x), ry = uf_find(uf, y);
if (rx == ry) return false;
if (uf->rank[rx] < uf->rank[ry])
uf->parent[rx] = ry;
else if (uf->rank[rx] > uf->rank[ry])
uf->parent[ry] = rx;
else {
uf->parent[ry] = rx;
uf->rank[rx]++;
}
return true;
}

// O(n),一个个比
int sequential_search(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
if (arr[i] == target) return i;
}
return -1;
}
// ===== 标准二分(C)=====
int binary_search(int arr[], int n, int target) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2; // 防溢出
if (arr[mid] == target)
return mid;
else if (arr[mid] < target)
lo = mid + 1;
else
hi = mid - 1;
}
return -1;
}
// ===== 变体1:左边界(第一个 ≥ target 的位置)=====
int lower_bound_c(int arr[], int n, int target) {
int lo = 0, hi = n;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] < target)
lo = mid + 1;
else
hi = mid;
}
return lo; // arr[lo] 是第一个 ≥ target 的位置
}
// ===== 变体2:右边界(最后一个 ≤ target 的位置)=====
int upper_bound_c(int arr[], int n, int target) {
int lo = 0, hi = n;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] <= target)
lo = mid + 1;
else
hi = mid;
}
return lo - 1; // arr[lo-1] 是最后一个 ≤ target 的位置
}
// C++ STL 直接调
#include <algorithm>
#include <vector>
using namespace std;
vector<int> arr = {1,2,2,2,3,5,8};
auto it = lower_bound(arr.begin(), arr.end(), 2); // → 指向第一个2
auto it = upper_bound(arr.begin(), arr.end(), 2); // → 指向3
bool found = binary_search(arr.begin(), arr.end(), 5); // → true

** Bicentenary is not used in an orderly array:**

// 找旋转排序数组的最小值
int find_min_rotated(int arr[], int n) {
int lo = 0, hi = n - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] > arr[hi])
lo = mid + 1; // 最小值在右半
else
hi = mid; // 最小值在左半(含mid)
}
return arr[lo];
}
// 找峰值
int find_peak(int arr[], int n) {
int lo = 0, hi = n - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] < arr[mid + 1])
lo = mid + 1; // 上坡,峰值在右
else
hi = mid; // 下坡,峰值在左(含mid)
}
return lo;
}
// C++ STL
#include <unordered_map>
#include <unordered_set>
using namespace std;
unordered_map<string, int> dict;
dict["hello"] = 1;
if (dict.find("hello") != dict.end()) { /* ... */ }
unordered_set<int> seen;
if (seen.count(x)) { /* 已存在 */ }
seen.insert(x);
// ===== C 版:简易哈希表(拉链法)=====
#include <stdlib.h>
#include <string.h>
#define HASH_SIZE 1021 // 素数
typedef struct HashEntry {
char* key;
int value;
struct HashEntry* next;
} HashEntry;
typedef struct {
HashEntry* buckets[HASH_SIZE];
} HashMap;
unsigned int hash_func(const char* key) {
unsigned int hash = 5381; // djb2
int c;
while ((c = *key++))
hash = ((hash << 5) + hash) + c;
return hash % HASH_SIZE;
}
void hashmap_put(HashMap* map, const char* key, int value) {
unsigned int idx = hash_func(key);
HashEntry* entry = map->buckets[idx];
while (entry) {
if (strcmp(entry->key, key) == 0) {
entry->value = value;
return;
}
entry = entry->next;
}
// 新插入(头插法)
HashEntry* new_entry = (HashEntry*)malloc(sizeof(HashEntry));
new_entry->key = strdup(key);
new_entry->value = value;
new_entry->next = map->buckets[idx];
map->buckets[idx] = new_entry;
}
int hashmap_get(HashMap* map, const char* key, int* found) {
unsigned int idx = hash_func(key);
HashEntry* entry = map->buckets[idx];
while (entry) {
if (strcmp(entry->key, key) == 0) {
if (found) *found = 1;
return entry->value;
}
entry = entry->next;
}
if (found) *found = 0;
return -1;
}

** Classic: two-digit sum**

#include <unordered_map>
#include <vector>
using namespace std;
vector<int> two_sum(vector<int>& nums, int target) {
unordered_map<int, int> seen;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (seen.count(complement))
return {seen[complement], i};
seen[nums[i]] = i;
}
return {};
}

4.4 String Matching - KMP

// ===== C++ 版 =====
#include <string>
#include <vector>
using namespace std;
// 构建 next(前缀函数)数组
vector<int> build_next(const string& pattern) {
int m = pattern.size();
vector<int> nxt(m, 0);
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && pattern[i] != pattern[j])
j = nxt[j - 1];
if (pattern[i] == pattern[j])
j++;
nxt[i] = j;
}
return nxt;
}
int kmp_search(const string& text, const string& pattern) {
if (pattern.empty()) return 0;
vector<int> nxt = build_next(pattern);
int n = text.size(), m = pattern.size();
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && text[i] != pattern[j])
j = nxt[j - 1];
if (text[i] == pattern[j])
j++;
if (j == m)
return i - m + 1; // 匹配成功,返回起始位置
}
return -1;
}
// ===== C 版 =====
void compute_lps(char* pattern, int m, int* lps) {
int len = 0;
lps[0] = 0;
int i = 1;
while (i < m) {
if (pattern[i] == pattern[len]) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0) {
len = lps[len - 1];
} else {
lps[i] = 0;
i++;
}
}
}
}
int kmp_search_c(char* text, char* pattern) {
int n = strlen(text);
int m = strlen(pattern);
if (m == 0) return 0;
int* lps = (int*)malloc(m * sizeof(int));
compute_lps(pattern, m, lps);
int i = 0, j = 0;
while (i < n) {
if (text[i] == pattern[j]) {
i++; j++;
}
if (j == m) {
free(lps);
return i - j; // 匹配到
}
if (i < n && text[i] != pattern[j]) {
if (j != 0)
j = lps[j - 1];
else
i++;
}
}
free(lps);
return -1;
}

Order

5.1 Summary of ranking algorithms

| Algorithms, average, worst, worst, space, stability, point, point. |------|------|------|------|------|------| | Flow O(n2) | O(n2) | O(1) | is | next-to-door exchange | Choose |O(n2)|O(n2)|O(1)|No |Minimum front of each round | Insert |O(n2)|O(n2)|O(1)| is | similar to playing cards | Hill O(n^1.3) | O(n2) | O(1) | No insert upgrade | | Summarizing O(n log n) | O(n log n) | O(n) | is partition, division and integration | Quick O (n log n) | O (n2) | O (log n) | Order of partitions | Pocket O(n log n) Pocket O(n log n) Pocket O(1) Pocket No Pocket + Popup Pocket | Count O(n+k) | O(n+k) | O(n+k)| is a limited range of values | Base figure |O(n+k)) |O(n+k) |O(n+k)| is | sorted in bits

5.2 Bubble Sorting

// ===== C 版 =====
void bubble_sort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int swapped = 0;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
swapped = 1;
}
}
if (!swapped) break; // 提前退出
}
}
// ===== C++ 版 =====
void bubble_sort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
swapped = true;
}
}
if (!swapped) break;
}
}

5.3 Select Sorting

void selection_sort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int min_idx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx])
min_idx = j;
}
int tmp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = tmp;
}
}

5.4 Insert Sorting

// ===== C 版 =====
void insertion_sort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
// C++ 用 STL:std::sort 对小块自动用插入排序

5.5 Hill Sorting

void shell_sort(int arr[], int n) {
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int temp = arr[i];
int j = i;
while (j >= gap && arr[j - gap] > temp) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
}

5.6 Grouping

// ===== C++ 版 =====
#include <vector>
using namespace std;
void merge(vector<int>& arr, int lo, int mid, int hi) {
vector<int> left(arr.begin() + lo, arr.begin() + mid + 1);
vector<int> right(arr.begin() + mid + 1, arr.begin() + hi + 1);
int i = 0, j = 0, k = lo;
while (i < left.size() && j < right.size()) {
if (left[i] <= right[j])
arr[k++] = left[i++];
else
arr[k++] = right[j++];
}
while (i < left.size()) arr[k++] = left[i++];
while (j < right.size()) arr[k++] = right[j++];
}
void merge_sort(vector<int>& arr, int lo, int hi) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
merge_sort(arr, lo, mid);
merge_sort(arr, mid + 1, hi);
merge(arr, lo, mid, hi);
}
// ===== C 版 =====
void merge_c(int arr[], int lo, int mid, int hi) {
int n1 = mid - lo + 1;
int n2 = hi - mid;
int* left = (int*)malloc(n1 * sizeof(int));
int* right = (int*)malloc(n2 * sizeof(int));
for (int i = 0; i < n1; i++) left[i] = arr[lo + i];
for (int i = 0; i < n2; i++) right[i] = arr[mid + 1 + i];
int i = 0, j = 0, k = lo;
while (i < n1 && j < n2) {
if (left[i] <= right[j]) arr[k++] = left[i++];
else arr[k++] = right[j++];
}
while (i < n1) arr[k++] = left[i++];
while (j < n2) arr[k++] = right[j++];
free(left);
free(right);
}
void merge_sort_c(int arr[], int lo, int hi) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
merge_sort_c(arr, lo, mid);
merge_sort_c(arr, mid + 1, hi);
merge_c(arr, lo, mid, hi);
}

Appliced by grouping: reverse logarithmic

// 统计 arr[i] > arr[j] 且 i < j 的对数
long long merge_and_count(vector<int>& arr, int lo, int mid, int hi) {
vector<int> left(arr.begin() + lo, arr.begin() + mid + 1);
vector<int> right(arr.begin() + mid + 1, arr.begin() + hi + 1);
long long inv = 0;
int i = 0, j = 0, k = lo;
while (i < left.size() && j < right.size()) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
inv += left.size() - i; // left[i:] 全部 > right[j]
}
}
while (i < left.size()) arr[k++] = left[i++];
while (j < right.size()) arr[k++] = right[j++];
return inv;
}
long long count_inversions(vector<int>& arr, int lo, int hi) {
if (lo >= hi) return 0;
int mid = lo + (hi - lo) / 2;
long long inv = count_inversions(arr, lo, mid);
inv += count_inversions(arr, mid + 1, hi);
inv += merge_and_count(arr, lo, mid, hi);
return inv;
}

5.7 Quick Sorting

// ===== C 版:Lomuto 分区 =====
int partition(int arr[], int lo, int hi) {
int pivot = arr[hi]; // 选最后一个为 pivot
int i = lo; // i 指向第一个 > pivot 的位置
for (int j = lo; j < hi; j++) {
if (arr[j] <= pivot) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
int tmp = arr[i];
arr[i] = arr[hi];
arr[hi] = tmp;
return i;
}
void quick_sort(int arr[], int lo, int hi) {
if (lo >= hi) return;
int pivot_idx = partition(arr, lo, hi);
quick_sort(arr, lo, pivot_idx - 1);
quick_sort(arr, pivot_idx + 1, hi);
}
// ===== C++ 优化版:三数取中 + Hoare 分区 =====
void quick_sort_opt(vector<int>& arr, int lo, int hi) {
if (lo >= hi) return;
// 三数取中选 pivot
int mid = lo + (hi - lo) / 2;
if (arr[mid] < arr[lo]) swap(arr[lo], arr[mid]);
if (arr[hi] < arr[lo]) swap(arr[lo], arr[hi]);
if (arr[hi] < arr[mid]) swap(arr[mid], arr[hi]);
swap(arr[mid], arr[hi - 1]); // pivot 放 hi-1
int pivot = arr[hi - 1];
// Hoare 分区
int i = lo, j = hi - 1;
while (true) {
while (arr[++i] < pivot);
while (arr[--j] > pivot);
if (i >= j) break;
swap(arr[i], arr[j]);
}
swap(arr[i], arr[hi - 1]);
quick_sort_opt(arr, lo, i - 1);
quick_sort_opt(arr, i + 1, hi);
}

5.8 Stack Sorting

// ===== C 版 =====
void heapify(int arr[], int n, int i) {
while (1) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) largest = left;
if (right < n && arr[right] > arr[largest]) largest = right;
if (largest == i) break;
int tmp = arr[i];
arr[i] = arr[largest];
arr[largest] = tmp;
i = largest;
}
}
void heap_sort(int arr[], int n) {
// 建大顶堆 O(n)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// 排序 O(n log n):堆顶和末尾交换,再下沉
for (int i = n - 1; i > 0; i--) {
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
heapify(arr, i, 0);
}
}
// ===== C++ 版:手写 =====
#include <algorithm>
#include <functional>
void heap_sort_stl(vector<int>& arr) {
make_heap(arr.begin(), arr.end()); // 大顶堆
sort_heap(arr.begin(), arr.end());
// 或者直接用 priority_queue
}

5.9 Sorting of count

void counting_sort(int arr[], int n) {
if (n <= 0) return;
// 找范围
int max_val = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > max_val) max_val = arr[i];
int* count = (int*)calloc(max_val + 1, sizeof(int));
for (int i = 0; i < n; i++)
count[arr[i]]++;
// 前缀和
for (int i = 1; i <= max_val; i++)
count[i] += count[i - 1];
// 倒序填入(保证稳定性)
int* output = (int*)malloc(n * sizeof(int));
for (int i = n - 1; i >= 0; i--) {
output[--count[arr[i]]] = arr[i];
}
for (int i = 0; i < n; i++)
arr[i] = output[i];
free(count);
free(output);
}

5.10 Sorting of base figures

void counting_sort_by_digit(int arr[], int n, int exp) {
int* output = (int*)malloc(n * sizeof(int));
int count[10] = {0};
for (int i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10;
output[--count[digit]] = arr[i];
}
for (int i = 0; i < n; i++)
arr[i] = output[i];
free(output);
}
void radix_sort(int arr[], int n) {
if (n <= 0) return;
int max_val = arr[0];
for (int i = 1; i < n; i++)
if (arr[i] > max_val) max_val = arr[i];
for (int exp = 1; max_val / exp > 0; exp *= 10)
counting_sort_by_digit(arr, n, exp);
}

5.11 C++ STL Sorting - Direct

#include <algorithm>
#include <vector>
using namespace std;
vector<int> arr = {5, 2, 8, 1, 9};
sort(arr.begin(), arr.end()); // 升序
sort(arr.begin(), arr.end(), greater<int>()); // 降序
sort(arr.begin(), arr.end(),
[](int a, int b) { return a > b; }); // 自定义
// 部分排序(前k个最小)
partial_sort(arr.begin(), arr.begin() + 5, arr.end());
// 第k大
nth_element(arr.begin(), arr.begin() + k, arr.end());
// 稳定排序
stable_sort(arr.begin(), arr.end());
// C 库
#include <stdlib.h>
int compare(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
qsort(arr, n, sizeof(int), compare);

5.12 External sorting - too big to store

/*
思路:多路归并
1. 把大文件切成 N 个能装入内存的块
2. 每块单独排序,写入临时文件
3. 用最小堆合并 N 个有序文件
*/
#include <queue>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
// 简化版(每行一个整数)
void external_sort(const string& input_file, const string& output_file,
size_t chunk_size_mb = 100) {
// 1. 分块排序
ifstream fin(input_file);
vector<string> chunk_files;
vector<int> chunk;
size_t chunk_bytes = 0;
size_t max_bytes = chunk_size_mb * 1024 * 1024;
int val;
while (fin >> val) {
chunk.push_back(val);
chunk_bytes += sizeof(val) + 1; // 估计
if (chunk_bytes >= max_bytes) {
sort(chunk.begin(), chunk.end());
string tmp = input_file + ".tmp." + to_string(chunk_files.size());
ofstream fout(tmp);
for (int x : chunk) fout << x << "\n";
chunk_files.push_back(tmp);
chunk.clear();
chunk_bytes = 0;
}
}
// 最后一块
if (!chunk.empty()) {
sort(chunk.begin(), chunk.end());
string tmp = input_file + ".tmp." + to_string(chunk_files.size());
ofstream fout(tmp);
for (int x : chunk) fout << x << "\n";
chunk_files.push_back(tmp);
}
fin.close();
// 2. 多路归并
vector<ifstream*> readers;
for (auto& f : chunk_files)
readers.push_back(new ifstream(f));
// 堆中放 pair<value, reader_index>
using pii = pair<int, int>;
priority_queue<pii, vector<pii>, greater<pii>> heap;
for (int i = 0; i < readers.size(); i++) {
int x;
if ((*readers[i]) >> x)
heap.push({x, i});
}
ofstream fout(output_file);
while (!heap.empty()) {
auto [val, idx] = heap.top(); heap.pop();
fout << val << "\n";
int next;
if ((*readers[idx]) >> next)
heap.push({next, idx});
}
// 清理
for (auto& r : readers) { r->close(); delete r; }
for (auto& f : chunk_files) remove(f.c_str());
}

6. Labeling guidance

6.1 Tree / fork tree

  • LeetCode 94, 144, 145 — three round-the-clock (over and back)
  • LeetCode 102, 103, 107 — Layers Calendar
  • LeetCode 98 — Authentication BST
  • LeetCode 104 - Maximum depth of fork tree
  • LeetCode 236 — recent public ancestors
  • LeetCode 105 — front + middle order fork tree reconstruction
  • LeetCode 297 — Two fork for Serialization and Inverse Serialization Tree

6.2 Figure

  • LeetCode 200 - Number of Islands (DFS/BFS)
  • LeetCode 207 - Course (Standing)
  • LeetCode 743 — Network Delay (Dijkstra)
  • LeetCode 787 — Best Costed Flight at Station K (Bellman-Ford)
  • LeetCode 133 — Cloning
  • LeetCode 1 — sum of two digits (Hashi Table)
  • LeetCode 33 — Search for rotational sorting arrays (two minutes)
  • LeetCode 34 - Find first and last position (diverse boundary)
  • LeetCode 153 - Rotate Sorting Numeric
  • LeetCode 4 — median of two sequenced arrays (two,hard)

6.4 Sorting

  • LeetCode 215 — K Large element (quick selection/ stacking)
  • LeetCode 912 - Sort Number Group
  • LeetCode 148 — Sort Chain Table
  • LeetCode 179 – Max
  • LeetCode 315 - Calculates the number of right-hand less than the current element

7. A few words of truth.

  1. ** Understand instincts, then code. ** Why is the sequence in BST? Think twice as important as the back code.

  2. ** Handwritten code. ** Feels like you can do it? Turn off the tutorial and open it. .c File, use gcc -g -Wall Compile, step on all the holes.

  3. **C Language pit. ** malloc Don’t forget. freeI don’t know. Keep your hands off me.NULL Check.int mid = lo + (hi - lo) / 2 Protection from spills.

  4. ** The sweet head of C++.** std::vector、std::queue、std::priority_queue、std::unordered_map This STL will save you countless times. malloc And the handwritten stack.

  5. **Intuitively complex. ** Sees a loop-set immediate reaction O(n2) and a split is O(log n).

  6. ** The stacking and identification are undervalued two sharp instruments. ** Many hard questions depend on them.

Make it run, don’t just look.