mirror of
https://github.com/krahets/hello-algo.git
synced 2025-11-03 05:27:55 +08:00
Fix Repo
This commit is contained in:
@ -123,14 +123,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array.cpp"
|
||||
/* 随机返回一个数组元素 */
|
||||
int randomAccess(int* nums, int size) {
|
||||
// 在区间 [0, size) 中随机抽取一个数字
|
||||
int randomIndex = rand() % size;
|
||||
// 获取并返回随机元素
|
||||
int randomNum = nums[randomIndex];
|
||||
return randomNum;
|
||||
}
|
||||
[class]{}-[func]{randomAccess}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -238,19 +231,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array.cpp"
|
||||
/* 扩展数组长度 */
|
||||
int* extend(int* nums, int size, int enlarge) {
|
||||
// 初始化一个扩展长度后的数组
|
||||
int* res = new int[size + enlarge];
|
||||
// 将原数组中的所有元素复制到新数组
|
||||
for (int i = 0; i < size; i++) {
|
||||
res[i] = nums[i];
|
||||
}
|
||||
// 释放内存
|
||||
delete[] nums;
|
||||
// 返回扩展后的新数组
|
||||
return res;
|
||||
}
|
||||
[class]{}-[func]{extend}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -383,23 +364,9 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array.cpp"
|
||||
/* 在数组的索引 index 处插入元素 num */
|
||||
void insert(int* nums, int size, int num, int index) {
|
||||
// 把索引 index 以及之后的所有元素向后移动一位
|
||||
for (int i = size - 1; i > index; i--) {
|
||||
nums[i] = nums[i - 1];
|
||||
}
|
||||
// 将 num 赋给 index 处元素
|
||||
nums[index] = num;
|
||||
}
|
||||
|
||||
/* 删除索引 index 处元素 */
|
||||
void remove(int* nums, int size, int index) {
|
||||
// 把索引 index 之后的所有元素向前移动一位
|
||||
for (int i = index; i < size - 1; i++) {
|
||||
nums[i] = nums[i + 1];
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{insert}
|
||||
|
||||
[class]{}-[func]{remove}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -567,14 +534,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array.cpp"
|
||||
/* 遍历数组 */
|
||||
void traverse(int* nums, int size) {
|
||||
int count = 0;
|
||||
// 通过索引遍历数组
|
||||
for (int i = 0; i < size; i++) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{traverse}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -707,14 +667,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array.cpp"
|
||||
/* 在数组中查找指定元素 */
|
||||
int find(int* nums, int size, int target) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (nums[i] == target)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -511,15 +511,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linked_list.cpp"
|
||||
/* 访问链表中索引为 index 的结点 */
|
||||
ListNode* access(ListNode* head, int index) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (head == nullptr)
|
||||
return nullptr;
|
||||
head = head->next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
[class]{}-[func]{access}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -640,17 +632,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linked_list.cpp"
|
||||
/* 在链表中查找值为 target 的首个结点 */
|
||||
int find(ListNode* head, int target) {
|
||||
int index = 0;
|
||||
while (head != nullptr) {
|
||||
if (head->val == target)
|
||||
return index;
|
||||
head = head->next;
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -722,106 +722,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_list.cpp"
|
||||
/* 列表类简易实现 */
|
||||
class MyList {
|
||||
private:
|
||||
int* nums; // 数组(存储列表元素)
|
||||
int numsCapacity = 10; // 列表容量
|
||||
int numsSize = 0; // 列表长度(即当前元素数量)
|
||||
int extendRatio = 2; // 每次列表扩容的倍数
|
||||
|
||||
public:
|
||||
/* 构造函数 */
|
||||
MyList() {
|
||||
nums = new int[numsCapacity];
|
||||
}
|
||||
|
||||
/* 析构函数 */
|
||||
~MyList() {
|
||||
delete[] nums;
|
||||
}
|
||||
|
||||
/* 获取列表长度(即当前元素数量)*/
|
||||
int size() {
|
||||
return numsSize;
|
||||
}
|
||||
|
||||
/* 获取列表容量 */
|
||||
int capacity() {
|
||||
return numsCapacity;
|
||||
}
|
||||
|
||||
/* 访问元素 */
|
||||
int get(int index) {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
if (index < 0 || index >= size())
|
||||
throw out_of_range("索引越界");
|
||||
return nums[index];
|
||||
}
|
||||
|
||||
/* 更新元素 */
|
||||
void set(int index, int num) {
|
||||
if (index < 0 || index >= size())
|
||||
throw out_of_range("索引越界");
|
||||
nums[index] = num;
|
||||
}
|
||||
|
||||
/* 尾部添加元素 */
|
||||
void add(int num) {
|
||||
// 元素数量超出容量时,触发扩容机制
|
||||
if (size() == capacity())
|
||||
extendCapacity();
|
||||
nums[size()] = num;
|
||||
// 更新元素数量
|
||||
numsSize++;
|
||||
}
|
||||
|
||||
/* 中间插入元素 */
|
||||
void insert(int index, int num) {
|
||||
if (index < 0 || index >= size())
|
||||
throw out_of_range("索引越界");
|
||||
// 元素数量超出容量时,触发扩容机制
|
||||
if (size() == capacity())
|
||||
extendCapacity();
|
||||
// 索引 i 以及之后的元素都向后移动一位
|
||||
for (int j = size() - 1; j >= index; j--) {
|
||||
nums[j + 1] = nums[j];
|
||||
}
|
||||
nums[index] = num;
|
||||
// 更新元素数量
|
||||
numsSize++;
|
||||
}
|
||||
|
||||
/* 删除元素 */
|
||||
int remove(int index) {
|
||||
if (index < 0 || index >= size())
|
||||
throw out_of_range("索引越界");
|
||||
int num = nums[index];
|
||||
// 索引 i 之后的元素都向前移动一位
|
||||
for (int j = index; j < size() - 1; j++) {
|
||||
nums[j] = nums[j + 1];
|
||||
}
|
||||
// 更新元素数量
|
||||
numsSize--;
|
||||
// 返回被删除元素
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 列表扩容 */
|
||||
void extendCapacity() {
|
||||
// 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组
|
||||
int newCapacity = capacity() * extendRatio;
|
||||
int* tmp = nums;
|
||||
nums = new int[newCapacity];
|
||||
// 将原数组中的所有元素复制到新数组
|
||||
for (int i = 0; i < size(); i++) {
|
||||
nums[i] = tmp[i];
|
||||
}
|
||||
// 释放内存
|
||||
delete[] tmp;
|
||||
numsCapacity = newCapacity;
|
||||
}
|
||||
};
|
||||
[class]{MyList}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -588,22 +588,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 常数阶 */
|
||||
void constant(int n) {
|
||||
// 常量、变量、对象占用 O(1) 空间
|
||||
const int a = 0;
|
||||
int b = 0;
|
||||
vector<int> nums(10000);
|
||||
ListNode node(0);
|
||||
// 循环中的变量占用 O(1) 空间
|
||||
for (int i = 0; i < n; i++) {
|
||||
int c = 0;
|
||||
}
|
||||
// 循环中的函数占用 O(1) 空间
|
||||
for (int i = 0; i < n; i++) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{constant}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -769,21 +754,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 线性阶 */
|
||||
void linear(int n) {
|
||||
// 长度为 n 的数组占用 O(n) 空间
|
||||
vector<int> nums(n);
|
||||
// 长度为 n 的列表占用 O(n) 空间
|
||||
vector<ListNode> nodes;
|
||||
for (int i = 0; i < n; i++) {
|
||||
nodes.push_back(ListNode(i));
|
||||
}
|
||||
// 长度为 n 的哈希表占用 O(n) 空间
|
||||
unordered_map<int, string> map;
|
||||
for (int i = 0; i < n; i++) {
|
||||
map[i] = to_string(i);
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{linear}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -933,12 +904,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 线性阶(递归实现) */
|
||||
void linearRecur(int n) {
|
||||
cout << "递归 n = " << n << endl;
|
||||
if (n == 1) return;
|
||||
linearRecur(n - 1);
|
||||
}
|
||||
[class]{}-[func]{linearRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1041,18 +1007,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 平方阶 */
|
||||
void quadratic(int n) {
|
||||
// 二维列表占用 O(n^2) 空间
|
||||
vector<vector<int>> numMatrix;
|
||||
for (int i = 0; i < n; i++) {
|
||||
vector<int> tmp;
|
||||
for (int j = 0; j < n; j++) {
|
||||
tmp.push_back(0);
|
||||
}
|
||||
numMatrix.push_back(tmp);
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{quadratic}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1182,13 +1137,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 平方阶(递归实现) */
|
||||
int quadraticRecur(int n) {
|
||||
if (n <= 0) return 0;
|
||||
vector<int> nums(n);
|
||||
cout << "递归 n = " << n << " 中的 nums 长度 = " << nums.size() << endl;
|
||||
return quadraticRecur(n - 1);
|
||||
}
|
||||
[class]{}-[func]{quadraticRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1297,14 +1246,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="space_complexity.cpp"
|
||||
/* 指数阶(建立满二叉树) */
|
||||
TreeNode* buildTree(int n) {
|
||||
if (n == 0) return nullptr;
|
||||
TreeNode* root = new TreeNode(0);
|
||||
root->left = buildTree(n - 1);
|
||||
root->right = buildTree(n - 1);
|
||||
return root;
|
||||
}
|
||||
[class]{}-[func]{buildTree}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -39,20 +39,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="leetcode_two_sum.cpp"
|
||||
class SolutionBruteForce {
|
||||
public:
|
||||
vector<int> twoSum(vector<int>& nums, int target) {
|
||||
int size = nums.size();
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
for (int j = i + 1; j < size; j++) {
|
||||
if (nums[i] + nums[j] == target)
|
||||
return { i, j };
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
[class]{SolutionBruteForce}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -193,22 +180,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="leetcode_two_sum.cpp"
|
||||
class SolutionHashMap {
|
||||
public:
|
||||
vector<int> twoSum(vector<int>& nums, int target) {
|
||||
int size = nums.size();
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
unordered_map<int, int> dic;
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (dic.find(target - nums[i]) != dic.end()) {
|
||||
return { dic[target - nums[i]], i };
|
||||
}
|
||||
dic.emplace(nums[i], i);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
[class]{SolutionHashMap}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -801,14 +801,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 常数阶 */
|
||||
int constant(int n) {
|
||||
int count = 0;
|
||||
int size = 100000;
|
||||
for (int i = 0; i < size; i++)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{constant}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -927,13 +920,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 线性阶 */
|
||||
int linear(int n) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{linear}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1045,15 +1032,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 线性阶(遍历数组) */
|
||||
int arrayTraversal(vector<int>& nums) {
|
||||
int count = 0;
|
||||
// 循环次数与数组长度成正比
|
||||
for (int num : nums) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{arrayTraversal}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1175,17 +1154,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 平方阶 */
|
||||
int quadratic(int n) {
|
||||
int count = 0;
|
||||
// 循环次数与数组长度成平方关系
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{quadratic}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1330,24 +1299,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 平方阶(冒泡排序) */
|
||||
int bubbleSort(vector<int>& nums) {
|
||||
int count = 0; // 计数器
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = nums.size() - 1; i > 0; i--) {
|
||||
// 内循环:冒泡操作
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交换 nums[j] 与 nums[j + 1]
|
||||
int tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
count += 3; // 元素交换包含 3 个单元操作
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{bubbleSort}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1543,19 +1495,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 指数阶(循环实现) */
|
||||
int exponential(int n) {
|
||||
int count = 0, base = 1;
|
||||
// cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < base; j++) {
|
||||
count++;
|
||||
}
|
||||
base *= 2;
|
||||
}
|
||||
// count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{exponential}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1716,11 +1656,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 指数阶(递归实现) */
|
||||
int expRecur(int n) {
|
||||
if (n == 1) return 1;
|
||||
return expRecur(n - 1) + expRecur(n - 1) + 1;
|
||||
}
|
||||
[class]{}-[func]{expRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1822,15 +1758,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 对数阶(循环实现) */
|
||||
int logarithmic(float n) {
|
||||
int count = 0;
|
||||
while (n > 1) {
|
||||
n = n / 2;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{logarithmic}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -1958,11 +1886,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 对数阶(递归实现) */
|
||||
int logRecur(float n) {
|
||||
if (n <= 1) return 0;
|
||||
return logRecur(n / 2) + 1;
|
||||
}
|
||||
[class]{}-[func]{logRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -2062,16 +1986,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 线性对数阶 */
|
||||
int linearLogRecur(float n) {
|
||||
if (n <= 1) return 1;
|
||||
int count = linearLogRecur(n / 2) +
|
||||
linearLogRecur(n / 2);
|
||||
for (int i = 0; i < n; i++) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{linearLogRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -2213,16 +2128,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="time_complexity.cpp"
|
||||
/* 阶乘阶(递归实现) */
|
||||
int factorialRecur(int n) {
|
||||
if (n == 0) return 1;
|
||||
int count = 0;
|
||||
// 从 1 个分裂出 n 个
|
||||
for (int i = 0; i < n; i++) {
|
||||
count += factorialRecur(n - 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{factorialRecur}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -424,54 +424,9 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array_hash_map.cpp"
|
||||
/* 键值对 int->String */
|
||||
struct Entry {
|
||||
public:
|
||||
int key;
|
||||
string val;
|
||||
Entry(int key, string val) {
|
||||
this->key = key;
|
||||
this->val = val;
|
||||
}
|
||||
};
|
||||
|
||||
/* 基于数组简易实现的哈希表 */
|
||||
class ArrayHashMap {
|
||||
private:
|
||||
vector<Entry*> bucket;
|
||||
public:
|
||||
ArrayHashMap() {
|
||||
// 初始化一个长度为 100 的桶(数组)
|
||||
bucket= vector<Entry*>(100);
|
||||
}
|
||||
|
||||
/* 哈希函数 */
|
||||
int hashFunc(int key) {
|
||||
int index = key % 100;
|
||||
return index;
|
||||
}
|
||||
|
||||
/* 查询操作 */
|
||||
string get(int key) {
|
||||
int index = hashFunc(key);
|
||||
Entry* pair = bucket[index];
|
||||
return pair->val;
|
||||
}
|
||||
|
||||
/* 添加操作 */
|
||||
void put(int key, string val) {
|
||||
Entry* pair = new Entry(key, val);
|
||||
int index = hashFunc(key);
|
||||
bucket[index] = pair;
|
||||
}
|
||||
|
||||
/* 删除操作 */
|
||||
void remove(int key) {
|
||||
int index = hashFunc(key);
|
||||
// 置为 nullptr ,代表删除
|
||||
bucket[index] = nullptr;
|
||||
}
|
||||
};
|
||||
[class]{Entry}-[func]{}
|
||||
|
||||
[class]{ArrayHashMap}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -445,10 +445,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_heap.cpp"
|
||||
/* 访问堆顶元素 */
|
||||
int peek() {
|
||||
return maxHeap[0];
|
||||
}
|
||||
[class]{MaxHeap}-[func]{peek}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -548,28 +545,9 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_heap.cpp"
|
||||
/* 元素入堆 */
|
||||
void push(int val) {
|
||||
// 添加结点
|
||||
maxHeap.push_back(val);
|
||||
// 从底至顶堆化
|
||||
shifUp(size() - 1);
|
||||
}
|
||||
|
||||
/* 从结点 i 开始,从底至顶堆化 */
|
||||
void shifUp(int i) {
|
||||
while (true) {
|
||||
// 获取结点 i 的父结点
|
||||
int p = parent(i);
|
||||
// 当“越过根结点”或“结点无需修复”时,结束堆化
|
||||
if (p < 0 || maxHeap[i] <= maxHeap[p])
|
||||
break;
|
||||
// 交换两结点
|
||||
swap(maxHeap[i], maxHeap[p]);
|
||||
// 循环向上堆化
|
||||
i = p;
|
||||
}
|
||||
}
|
||||
[class]{MaxHeap}-[func]{push}
|
||||
|
||||
[class]{MaxHeap}-[func]{siftUp}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -758,39 +736,9 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_heap.cpp"
|
||||
/* 从结点 i 开始,从顶至底堆化 */
|
||||
void shifDown(int i) {
|
||||
while (true) {
|
||||
// 判断结点 i, l, r 中值最大的结点,记为 ma
|
||||
int l = left(i), r = right(i), ma = i;
|
||||
// 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
|
||||
if (l < size() && maxHeap[l] > maxHeap[ma])
|
||||
ma = l;
|
||||
if (r < size() && maxHeap[r] > maxHeap[ma])
|
||||
ma = r;
|
||||
// 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
|
||||
if (ma == i)
|
||||
break;
|
||||
swap(maxHeap[i], maxHeap[ma]);
|
||||
// 循环向下堆化
|
||||
i = ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* 元素出堆 */
|
||||
void poll() {
|
||||
// 判空处理
|
||||
if (empty()) {
|
||||
cout << "Error:堆为空" << endl;
|
||||
return;
|
||||
}
|
||||
// 交换根结点与最右叶结点(即交换首元素与尾元素)
|
||||
swap(maxHeap[0], maxHeap[size() - 1]);
|
||||
// 删除结点
|
||||
maxHeap.pop_back();
|
||||
// 从顶至底堆化
|
||||
shifDown(0);
|
||||
}
|
||||
[class]{MaxHeap}-[func]{poll}
|
||||
|
||||
[class]{MaxHeap}-[func]{siftDown}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -993,15 +941,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_heap.cpp"
|
||||
/* 构造函数,根据输入列表建堆 */
|
||||
MaxHeap(vector<int> nums) {
|
||||
// 将列表元素原封不动添加进堆
|
||||
maxHeap = nums;
|
||||
// 堆化除叶结点以外的其他所有结点
|
||||
for (int i = parent(size() - 1); i >= 0; i--) {
|
||||
shifDown(i);
|
||||
}
|
||||
}
|
||||
[class]{MaxHeap}-[func]{MaxHeap}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -60,23 +60,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_search.cpp"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(vector<int>& nums, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = nums.size() - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = (i + j) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
[class]{}-[func]{binarySearch}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -225,23 +209,7 @@ $$
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_search.cpp"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearch1(vector<int>& nums, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = nums.size();
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = (i + j) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
[class]{}-[func]{binarySearch1}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -25,14 +25,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="hashing_search.cpp"
|
||||
/* 哈希查找(数组) */
|
||||
int hashingSearchArray(unordered_map<int, int> map, int target) {
|
||||
// 哈希表的 key: 目标元素,value: 索引
|
||||
// 若哈希表中无此 key ,返回 -1
|
||||
if (map.find(target) == map.end())
|
||||
return -1;
|
||||
return map[target];
|
||||
}
|
||||
[class]{}-[func]{hashingSearchArray}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -126,14 +119,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="hashing_search.cpp"
|
||||
/* 哈希查找(链表) */
|
||||
ListNode* hashingSearchLinkedList(unordered_map<int, ListNode*> map, int target) {
|
||||
// 哈希表的 key: 目标结点值,value: 结点对象
|
||||
// 若哈希表中无此 key ,返回 nullptr
|
||||
if (map.find(target) == map.end())
|
||||
return nullptr;
|
||||
return map[target];
|
||||
}
|
||||
[class]{}-[func]{hashingSearchLinkedList}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -21,17 +21,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linear_search.cpp"
|
||||
/* 线性查找(数组) */
|
||||
int linearSearchArray(vector<int>& nums, int target) {
|
||||
// 遍历数组
|
||||
for (int i = 0; i < nums.size(); i++) {
|
||||
// 找到目标元素,返回其索引
|
||||
if (nums[i] == target)
|
||||
return i;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
[class]{}-[func]{linearSearchArray}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -151,18 +141,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linear_search.cpp"
|
||||
/* 线性查找(链表) */
|
||||
ListNode* linearSearchLinkedList(ListNode* head, int target) {
|
||||
// 遍历链表
|
||||
while (head != nullptr) {
|
||||
// 找到目标结点,返回之
|
||||
if (head->val == target)
|
||||
return head;
|
||||
head = head->next;
|
||||
}
|
||||
// 未找到目标结点,返回 nullptr
|
||||
return nullptr;
|
||||
}
|
||||
[class]{}-[func]{linearSearchLinkedList}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -56,20 +56,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="bubble_sort.cpp"
|
||||
/* 冒泡排序 */
|
||||
void bubbleSort(vector<int>& nums) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = nums.size() - 1; i > 0; i--) {
|
||||
// 内循环:冒泡操作
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交换 nums[j] 与 nums[j + 1]
|
||||
// 这里使用了 std::swap() 函数
|
||||
swap(nums[j], nums[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{bubbleSort}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -235,23 +222,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="bubble_sort.cpp"
|
||||
/* 冒泡排序(标志优化)*/
|
||||
void bubbleSortWithFlag(vector<int>& nums) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for (int i = nums.size() - 1; i > 0; i--) {
|
||||
bool flag = false; // 初始化标志位
|
||||
// 内循环:冒泡操作
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交换 nums[j] 与 nums[j + 1]
|
||||
// 这里使用了 std::swap() 函数
|
||||
swap(nums[j], nums[j + 1]);
|
||||
flag = true; // 记录交换元素
|
||||
}
|
||||
}
|
||||
if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{bubbleSortWithFlag}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -33,19 +33,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="insertion_sort.cpp"
|
||||
/* 插入排序 */
|
||||
void insertionSort(vector<int>& nums) {
|
||||
// 外循环:base = nums[1], nums[2], ..., nums[n-1]
|
||||
for (int i = 1; i < nums.size(); i++) {
|
||||
int base = nums[i], j = i - 1;
|
||||
// 内循环:将 base 插入到左边的正确位置
|
||||
while (j >= 0 && nums[j] > base) {
|
||||
nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位
|
||||
j--;
|
||||
}
|
||||
nums[j + 1] = base; // 2. 将 base 赋值到正确位置
|
||||
}
|
||||
}
|
||||
[class]{}-[func]{insertionSort}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -259,17 +259,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="quick_sort.cpp"
|
||||
/* 快速排序 */
|
||||
void quickSort(vector<int>& nums, int left, int right) {
|
||||
// 子数组长度为 1 时终止递归
|
||||
if (left >= right)
|
||||
return;
|
||||
// 哨兵划分
|
||||
int pivot = partition(nums, left, right);
|
||||
// 递归左子数组、右子数组
|
||||
quickSort(nums, left, pivot - 1);
|
||||
quickSort(nums, pivot + 1, right);
|
||||
}
|
||||
[class]{QuickSort}-[func]{quickSort}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -415,27 +405,9 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="quick_sort.cpp"
|
||||
/* 选取三个元素的中位数 */
|
||||
int medianThree(vector<int>& nums, int left, int mid, int right) {
|
||||
// 使用了异或操作来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
|
||||
return left;
|
||||
else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right]))
|
||||
return mid;
|
||||
else
|
||||
return right;
|
||||
}
|
||||
[class]{QuickSortMedian}-[func]{medianThree}
|
||||
|
||||
/* 哨兵划分(三数取中值) */
|
||||
int partition(vector<int>& nums, int left, int right) {
|
||||
// 选取三个候选元素的中位数
|
||||
int med = medianThree(nums, left, (left + right) / 2, right);
|
||||
// 将中位数交换至数组最左端
|
||||
swap(nums, left, med);
|
||||
// 以 nums[left] 作为基准数
|
||||
// 下同省略...
|
||||
}
|
||||
[class]{QuickSortMedian}-[func]{partition}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -602,22 +574,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="quick_sort.cpp"
|
||||
/* 快速排序(尾递归优化) */
|
||||
void quickSort(vector<int>& nums, int left, int right) {
|
||||
// 子数组长度为 1 时终止
|
||||
while (left < right) {
|
||||
// 哨兵划分操作
|
||||
int pivot = partition(nums, left, right);
|
||||
// 对两个子数组中较短的那个执行快排
|
||||
if (pivot - left < right - pivot) {
|
||||
quickSort(nums, left, pivot - 1); // 递归排序左子数组
|
||||
left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right]
|
||||
} else {
|
||||
quickSort(nums, pivot + 1, right); // 递归排序右子数组
|
||||
right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
[class]{QuickSortTailCall}-[func]{quickSort}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -290,63 +290,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linkedlist_queue.cpp"
|
||||
/* 基于链表实现的队列 */
|
||||
class LinkedListQueue {
|
||||
private:
|
||||
ListNode *front, *rear; // 头结点 front ,尾结点 rear
|
||||
int queSize;
|
||||
|
||||
public:
|
||||
LinkedListQueue() {
|
||||
front = nullptr;
|
||||
rear = nullptr;
|
||||
queSize = 0;
|
||||
}
|
||||
~LinkedListQueue() {
|
||||
delete front;
|
||||
delete rear;
|
||||
}
|
||||
/* 获取队列的长度 */
|
||||
int size() {
|
||||
return queSize;
|
||||
}
|
||||
/* 判断队列是否为空 */
|
||||
bool empty() {
|
||||
return queSize == 0;
|
||||
}
|
||||
/* 入队 */
|
||||
void push(int num) {
|
||||
// 尾结点后添加 num
|
||||
ListNode* node = new ListNode(num);
|
||||
// 如果队列为空,则令头、尾结点都指向该结点
|
||||
if (front == nullptr) {
|
||||
front = node;
|
||||
rear = node;
|
||||
}
|
||||
// 如果队列不为空,则将该结点添加到尾结点后
|
||||
else {
|
||||
rear->next = node;
|
||||
rear = node;
|
||||
}
|
||||
queSize++;
|
||||
}
|
||||
/* 出队 */
|
||||
void poll() {
|
||||
int num = peek();
|
||||
// 删除头结点
|
||||
ListNode *tmp = front;
|
||||
front = front->next;
|
||||
// 释放内存
|
||||
delete tmp;
|
||||
queSize--;
|
||||
}
|
||||
/* 访问队首元素 */
|
||||
int peek() {
|
||||
if (size() == 0)
|
||||
throw out_of_range("队列为空");
|
||||
return front->val;
|
||||
}
|
||||
};
|
||||
[class]{LinkedListQueue}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -669,70 +613,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array_queue.cpp"
|
||||
/* 基于环形数组实现的队列 */
|
||||
class ArrayQueue {
|
||||
private:
|
||||
int *nums; // 用于存储队列元素的数组
|
||||
int front; // 队首指针,指向队首元素
|
||||
int queSize; // 队列长度
|
||||
int queCapacity; // 队列容量
|
||||
|
||||
public:
|
||||
ArrayQueue(int capacity) {
|
||||
// 初始化数组
|
||||
nums = new int[capacity];
|
||||
queCapacity = capacity;
|
||||
front = queSize = 0;
|
||||
}
|
||||
|
||||
~ArrayQueue() {
|
||||
delete[] nums;
|
||||
}
|
||||
|
||||
/* 获取队列的容量 */
|
||||
int capacity() {
|
||||
return queCapacity;
|
||||
}
|
||||
|
||||
/* 获取队列的长度 */
|
||||
int size() {
|
||||
return queSize;
|
||||
}
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/* 入队 */
|
||||
void push(int num) {
|
||||
if (queSize == queCapacity) {
|
||||
cout << "队列已满" << endl;
|
||||
return;
|
||||
}
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
int rear = (front + queSize) % queCapacity;
|
||||
// 尾结点后添加 num
|
||||
nums[rear] = num;
|
||||
queSize++;
|
||||
}
|
||||
|
||||
/* 出队 */
|
||||
void poll() {
|
||||
int num = peek();
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
front = (front + 1) % queCapacity;
|
||||
queSize--;
|
||||
}
|
||||
|
||||
/* 访问队首元素 */
|
||||
int peek() {
|
||||
if (empty())
|
||||
throw out_of_range("队列为空");
|
||||
return nums[front];
|
||||
}
|
||||
};
|
||||
[class]{ArrayQueue}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -293,51 +293,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="linkedlist_stack.cpp"
|
||||
/* 基于链表实现的栈 */
|
||||
class LinkedListStack {
|
||||
private:
|
||||
ListNode* stackTop; // 将头结点作为栈顶
|
||||
int stkSize; // 栈的长度
|
||||
|
||||
public:
|
||||
LinkedListStack() {
|
||||
stackTop = nullptr;
|
||||
stkSize = 0;
|
||||
}
|
||||
~LinkedListStack() {
|
||||
freeMemoryLinkedList(stackTop);
|
||||
}
|
||||
/* 获取栈的长度 */
|
||||
int size() {
|
||||
return stkSize;
|
||||
}
|
||||
/* 判断栈是否为空 */
|
||||
bool empty() {
|
||||
return size() == 0;
|
||||
}
|
||||
/* 入栈 */
|
||||
void push(int num) {
|
||||
ListNode* node = new ListNode(num);
|
||||
node->next = stackTop;
|
||||
stackTop = node;
|
||||
stkSize++;
|
||||
}
|
||||
/* 出栈 */
|
||||
void pop() {
|
||||
int num = top();
|
||||
ListNode *tmp = stackTop;
|
||||
stackTop = stackTop->next;
|
||||
// 释放内存
|
||||
delete tmp;
|
||||
stkSize--;
|
||||
}
|
||||
/* 访问栈顶元素 */
|
||||
int top() {
|
||||
if (size() == 0)
|
||||
throw out_of_range("栈为空");
|
||||
return stackTop->val;
|
||||
}
|
||||
};
|
||||
[class]{LinkedListStack}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -652,36 +608,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="array_stack.cpp"
|
||||
/* 基于数组实现的栈 */
|
||||
class ArrayStack {
|
||||
private:
|
||||
vector<int> stack;
|
||||
|
||||
public:
|
||||
/* 获取栈的长度 */
|
||||
int size() {
|
||||
return stack.size();
|
||||
}
|
||||
/* 判断栈是否为空 */
|
||||
bool empty() {
|
||||
return stack.empty();
|
||||
}
|
||||
/* 入栈 */
|
||||
void push(int num) {
|
||||
stack.push_back(num);
|
||||
}
|
||||
/* 出栈 */
|
||||
void pop() {
|
||||
int oldTop = top();
|
||||
stack.pop_back();
|
||||
}
|
||||
/* 访问栈顶元素 */
|
||||
int top() {
|
||||
if(empty())
|
||||
throw out_of_range("栈为空");
|
||||
return stack.back();
|
||||
}
|
||||
};
|
||||
[class]{ArrayStack}-[func]{}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -303,13 +303,7 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit
|
||||
=== "C++"
|
||||
|
||||
```cpp title="avl_tree.cpp"
|
||||
/* 获取平衡因子 */
|
||||
int balanceFactor(TreeNode* node) {
|
||||
// 空结点平衡因子为 0
|
||||
if (node == nullptr) return 0;
|
||||
// 结点平衡因子 = 左子树高度 - 右子树高度
|
||||
return height(node->left) - height(node->right);
|
||||
}
|
||||
[class]{AVLTree}-[func]{balanceFactor}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -436,19 +430,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
=== "C++"
|
||||
|
||||
```cpp title="avl_tree.cpp"
|
||||
/* 右旋操作 */
|
||||
TreeNode* rightRotate(TreeNode* node) {
|
||||
TreeNode* child = node->left;
|
||||
TreeNode* grandChild = child->right;
|
||||
// 以 child 为原点,将 node 向右旋转
|
||||
child->right = node;
|
||||
node->left = grandChild;
|
||||
// 更新结点高度
|
||||
updateHeight(node);
|
||||
updateHeight(child);
|
||||
// 返回旋转后子树的根结点
|
||||
return child;
|
||||
}
|
||||
[class]{AVLTree}-[func]{rightRotate}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -581,19 +563,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
=== "C++"
|
||||
|
||||
```cpp title="avl_tree.cpp"
|
||||
/* 左旋操作 */
|
||||
TreeNode* leftRotate(TreeNode* node) {
|
||||
TreeNode* child = node->right;
|
||||
TreeNode* grandChild = child->left;
|
||||
// 以 child 为原点,将 node 向左旋转
|
||||
child->left = node;
|
||||
node->right = grandChild;
|
||||
// 更新结点高度
|
||||
updateHeight(node);
|
||||
updateHeight(child);
|
||||
// 返回旋转后子树的根结点
|
||||
return child;
|
||||
}
|
||||
[class]{AVLTree}-[func]{leftRotate}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -750,35 +720,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
=== "C++"
|
||||
|
||||
```cpp title="avl_tree.cpp"
|
||||
/* 执行旋转操作,使该子树重新恢复平衡 */
|
||||
TreeNode* rotate(TreeNode* node) {
|
||||
// 获取结点 node 的平衡因子
|
||||
int _balanceFactor = balanceFactor(node);
|
||||
// 左偏树
|
||||
if (_balanceFactor > 1) {
|
||||
if (balanceFactor(node->left) >= 0) {
|
||||
// 右旋
|
||||
return rightRotate(node);
|
||||
} else {
|
||||
// 先左旋后右旋
|
||||
node->left = leftRotate(node->left);
|
||||
return rightRotate(node);
|
||||
}
|
||||
}
|
||||
// 右偏树
|
||||
if (_balanceFactor < -1) {
|
||||
if (balanceFactor(node->right) <= 0) {
|
||||
// 左旋
|
||||
return leftRotate(node);
|
||||
} else {
|
||||
// 先右旋后左旋
|
||||
node->right = rightRotate(node->right);
|
||||
return leftRotate(node);
|
||||
}
|
||||
}
|
||||
// 平衡树,无需旋转,直接返回
|
||||
return node;
|
||||
}
|
||||
[class]{AVLTree}-[func]{rotate}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -44,21 +44,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_search_tree.cpp"
|
||||
/* 查找结点 */
|
||||
TreeNode* search(int num) {
|
||||
TreeNode* cur = root;
|
||||
// 循环查找,越过叶结点后跳出
|
||||
while (cur != nullptr) {
|
||||
// 目标结点在 cur 的右子树中
|
||||
if (cur->val < num) cur = cur->right;
|
||||
// 目标结点在 cur 的左子树中
|
||||
else if (cur->val > num) cur = cur->left;
|
||||
// 找到目标结点,跳出循环
|
||||
else break;
|
||||
}
|
||||
// 返回目标结点
|
||||
return cur;
|
||||
}
|
||||
[class]{BinarySearchTree}-[func]{search}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -212,27 +198,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_search_tree.cpp"
|
||||
/* 插入结点 */
|
||||
TreeNode* insert(int num) {
|
||||
// 若树为空,直接提前返回
|
||||
if (root == nullptr) return nullptr;
|
||||
TreeNode *cur = root, *pre = nullptr;
|
||||
// 循环查找,越过叶结点后跳出
|
||||
while (cur != nullptr) {
|
||||
// 找到重复结点,直接返回
|
||||
if (cur->val == num) return nullptr;
|
||||
pre = cur;
|
||||
// 插入位置在 cur 的右子树中
|
||||
if (cur->val < num) cur = cur->right;
|
||||
// 插入位置在 cur 的左子树中
|
||||
else cur = cur->left;
|
||||
}
|
||||
// 插入结点 val
|
||||
TreeNode* node = new TreeNode(num);
|
||||
if (pre->val < num) pre->right = node;
|
||||
else pre->left = node;
|
||||
return node;
|
||||
}
|
||||
[class]{BinarySearchTree}-[func]{insert}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -465,53 +431,9 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_search_tree.cpp"
|
||||
/* 删除结点 */
|
||||
TreeNode* remove(int num) {
|
||||
// 若树为空,直接提前返回
|
||||
if (root == nullptr) return nullptr;
|
||||
TreeNode *cur = root, *pre = nullptr;
|
||||
// 循环查找,越过叶结点后跳出
|
||||
while (cur != nullptr) {
|
||||
// 找到待删除结点,跳出循环
|
||||
if (cur->val == num) break;
|
||||
pre = cur;
|
||||
// 待删除结点在 cur 的右子树中
|
||||
if (cur->val < num) cur = cur->right;
|
||||
// 待删除结点在 cur 的左子树中
|
||||
else cur = cur->left;
|
||||
}
|
||||
// 若无待删除结点,则直接返回
|
||||
if (cur == nullptr) return nullptr;
|
||||
// 子结点数量 = 0 or 1
|
||||
if (cur->left == nullptr || cur->right == nullptr) {
|
||||
// 当子结点数量 = 0 / 1 时, child = nullptr / 该子结点
|
||||
TreeNode* child = cur->left != nullptr ? cur->left : cur->right;
|
||||
// 删除结点 cur
|
||||
if (pre->left == cur) pre->left = child;
|
||||
else pre->right = child;
|
||||
}
|
||||
// 子结点数量 = 2
|
||||
else {
|
||||
// 获取中序遍历中 cur 的下一个结点
|
||||
TreeNode* nex = getInOrderNext(cur->right);
|
||||
int tmp = nex->val;
|
||||
// 递归删除结点 nex
|
||||
remove(nex->val);
|
||||
// 将 nex 的值复制给 cur
|
||||
cur->val = tmp;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
[class]{BinarySearchTree}-[func]{remove}
|
||||
|
||||
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
|
||||
TreeNode* getInOrderNext(TreeNode* root) {
|
||||
if (root == nullptr) return root;
|
||||
// 循环访问左子结点,直到叶结点时为最小结点,跳出
|
||||
while (root->left != nullptr) {
|
||||
root = root->left;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
[class]{BinarySearchTree}-[func]{getInOrderNext}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -27,24 +27,7 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_tree_bfs.cpp"
|
||||
/* 层序遍历 */
|
||||
vector<int> hierOrder(TreeNode* root) {
|
||||
// 初始化队列,加入根结点
|
||||
queue<TreeNode*> queue;
|
||||
queue.push(root);
|
||||
// 初始化一个列表,用于保存遍历序列
|
||||
vector<int> vec;
|
||||
while (!queue.empty()) {
|
||||
TreeNode* node = queue.front();
|
||||
queue.pop(); // 队列出队
|
||||
vec.push_back(node->val); // 保存结点值
|
||||
if (node->left != nullptr)
|
||||
queue.push(node->left); // 左子结点入队
|
||||
if (node->right != nullptr)
|
||||
queue.push(node->right); // 右子结点入队
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
[class]{}-[func]{hierOrder}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
@ -218,32 +201,11 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="binary_tree_dfs.cpp"
|
||||
/* 前序遍历 */
|
||||
void preOrder(TreeNode* root) {
|
||||
if (root == nullptr) return;
|
||||
// 访问优先级:根结点 -> 左子树 -> 右子树
|
||||
vec.push_back(root->val);
|
||||
preOrder(root->left);
|
||||
preOrder(root->right);
|
||||
}
|
||||
|
||||
/* 中序遍历 */
|
||||
void inOrder(TreeNode* root) {
|
||||
if (root == nullptr) return;
|
||||
// 访问优先级:左子树 -> 根结点 -> 右子树
|
||||
inOrder(root->left);
|
||||
vec.push_back(root->val);
|
||||
inOrder(root->right);
|
||||
}
|
||||
|
||||
/* 后序遍历 */
|
||||
void postOrder(TreeNode* root) {
|
||||
if (root == nullptr) return;
|
||||
// 访问优先级:左子树 -> 右子树 -> 根结点
|
||||
postOrder(root->left);
|
||||
postOrder(root->right);
|
||||
vec.push_back(root->val);
|
||||
}
|
||||
[class]{}-[func]{preOrder}
|
||||
|
||||
[class]{}-[func]{inOrder}
|
||||
|
||||
[class]{}-[func]{postOrder}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
|
||||
@ -12,6 +12,7 @@ import glob
|
||||
import shutil
|
||||
from docs.utils.extract_code_python import ExtractCodeBlocksPython
|
||||
from docs.utils.extract_code_java import ExtractCodeBlocksJava
|
||||
from docs.utils.extract_code_cpp import ExtractCodeBlocksCpp
|
||||
|
||||
|
||||
def build_markdown(md_path):
|
||||
@ -22,10 +23,12 @@ def build_markdown(md_path):
|
||||
file_pattern = re.compile(r'\s*```(\w+)\s+title="(.+)"')
|
||||
src_pattern = re.compile(r'\s*\[class\]\{(.*?)\}-\[func\]\{(.*?)\}')
|
||||
|
||||
for i in range(len(lines)):
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
# Find the line target to the source codes
|
||||
src_match = src_pattern.match(lines[i])
|
||||
if src_match is None:
|
||||
i += 1
|
||||
continue
|
||||
for j in range(i - 1, -1 ,-1):
|
||||
file_match = file_pattern.match(lines[j])
|
||||
@ -70,6 +73,8 @@ def build_markdown(md_path):
|
||||
func_block = class_dict["funcs"][func_label]
|
||||
for code_line in func_block["block"][::-1]:
|
||||
lines.insert(header_line, code_line)
|
||||
|
||||
i += 1
|
||||
|
||||
with open(md_path.replace("docs/", "build/"), "w") as f:
|
||||
f.writelines(lines)
|
||||
@ -79,6 +84,7 @@ def build_markdown(md_path):
|
||||
extractor_dict = {
|
||||
"java": ExtractCodeBlocksJava(),
|
||||
"python": ExtractCodeBlocksPython(),
|
||||
"cpp": ExtractCodeBlocksCpp(),
|
||||
}
|
||||
|
||||
|
||||
|
||||
28
docs/utils/extract_code_cpp.py
Normal file
28
docs/utils/extract_code_cpp.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
File: extract_code_python.py
|
||||
Created Time: 2023-02-07
|
||||
Author: Krahets (krahets@163.com)
|
||||
"""
|
||||
|
||||
import re
|
||||
import glob
|
||||
import sys, os.path as osp
|
||||
sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__)))))
|
||||
from docs.utils.extract_code_java import ExtractCodeBlocksJava
|
||||
|
||||
|
||||
class ExtractCodeBlocksCpp(ExtractCodeBlocksJava):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
# Pattern to match function names and class names
|
||||
self.func_pattern = r'(\s*)(static|)\s*(|\S+)\s*(\w+)(\(.*\))\s+\{'
|
||||
self.class_pattern = r'(public|)\s*(class|struct)\s+(\w+)\s*\{'
|
||||
|
||||
self.func_pattern_keys = ["total", "ind", "static", "return", "label", "args"]
|
||||
self.class_pattern_keys = ["total", "scope", "type", "label"]
|
||||
|
||||
|
||||
# for code_path in glob.glob("codes/cpp/chapter_*/my_heap.cpp"):
|
||||
# ext = ExtractCodeBlocksCpp()
|
||||
# ext.extract(code_path)
|
||||
@ -5,19 +5,27 @@ Author: Krahets (krahets@163.com)
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import os.path as osp
|
||||
import glob
|
||||
import sys, os.path as osp
|
||||
sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__)))))
|
||||
|
||||
|
||||
class ExtractCodeBlocksJava:
|
||||
def __init__(self) -> None:
|
||||
self.langs = ["java"]
|
||||
self.ind = 4
|
||||
|
||||
# Pattern to match function names and class names
|
||||
self.func_pattern = r'(\s+)(public|private|)\s*(static|)\s*(\S+)\s+(\w+)(\(.*\))\s+\{'
|
||||
self.func_pattern = r'(\s*)(public|private|)\s*(static|)\s*(\S+)\s+(\w+)(\(.*\))\s+\{'
|
||||
self.class_pattern = r'(public|)\s*class\s+(\w+)\s*\{'
|
||||
|
||||
self.func_pattern_keys = ["total", "ind", "scope", "static", "return", "label", "args"]
|
||||
self.class_pattern_keys = ["total", "scope", "label"]
|
||||
|
||||
# Pattern to match the start and end of a block
|
||||
self.block_end_pattern = '^\s{ind}\}'
|
||||
self.block_start_pattern = '^\s{ind}\/\*.+\*\/'
|
||||
self.block_start_shift = 0
|
||||
self.block_end_shift = 0
|
||||
|
||||
def extract(self, file_path):
|
||||
"""
|
||||
@ -53,17 +61,17 @@ class ExtractCodeBlocksJava:
|
||||
# Search the code
|
||||
for i in range(header_line + 1, len(self.lines)):
|
||||
if re.match(block_end_pattern, self.lines[i]) is not None:
|
||||
end_line = i
|
||||
end_line = i + self.block_end_shift
|
||||
break
|
||||
# Search the header comment
|
||||
for i in range(header_line - 1, -1, -1):
|
||||
if re.search(block_start_pattern, self.lines[i]) is not None:
|
||||
start_line = i
|
||||
start_line = i + self.block_start_shift
|
||||
break
|
||||
|
||||
return start_line, end_line, self.lines[start_line:end_line + 1]
|
||||
|
||||
def extract_function_blocks(self, indentation=4, start_line=-1, end_line=-1):
|
||||
def extract_function_blocks(self, indentation=0, start_line=-1, end_line=-1):
|
||||
"""
|
||||
Extract all the functions with given indentation
|
||||
"""
|
||||
@ -82,7 +90,7 @@ class ExtractCodeBlocksJava:
|
||||
if func_match is None:
|
||||
continue
|
||||
# The function should match the input indentation
|
||||
if len(func_match.group(1)) != indentation:
|
||||
if len(func_match.group(self.func_pattern_keys.index("ind"))) != indentation:
|
||||
continue
|
||||
header_line = line_num
|
||||
|
||||
@ -90,7 +98,7 @@ class ExtractCodeBlocksJava:
|
||||
start_line, end_line, func_block = self.search_block(
|
||||
header_line, indentation)
|
||||
# Construct the funcs dict
|
||||
func_label = func_match.group(5)
|
||||
func_label = func_match.group(self.func_pattern_keys.index("label"))
|
||||
funcs[func_label] = {
|
||||
"indentation": indentation,
|
||||
"line_number": {
|
||||
@ -122,7 +130,7 @@ class ExtractCodeBlocksJava:
|
||||
start_line, end_line, class_block = self.search_block(
|
||||
header_line, 0)
|
||||
# Construct the classes dict
|
||||
class_label = class_match.group(2)
|
||||
class_label = class_match.group(self.class_pattern_keys.index("label"))
|
||||
classes[class_label] = {
|
||||
"indentation": 0,
|
||||
"line_number": {
|
||||
@ -132,7 +140,7 @@ class ExtractCodeBlocksJava:
|
||||
},
|
||||
"block": class_block,
|
||||
"funcs": self.extract_function_blocks(
|
||||
indentation=4, start_line=start_line, end_line=end_line)
|
||||
indentation=self.ind, start_line=start_line, end_line=end_line)
|
||||
}
|
||||
|
||||
return classes
|
||||
@ -144,7 +152,7 @@ class ExtractCodeBlocksJava:
|
||||
def remove_keyword(func):
|
||||
block = func["block"]
|
||||
header_line = func["line_number"]["header"] - \
|
||||
func["line_number"]["start"]
|
||||
func["line_number"]["start"]
|
||||
block[header_line] = block[header_line] \
|
||||
.replace("static ", "").replace("public ", "").replace("private ", "")
|
||||
for clas in classes.values():
|
||||
|
||||
@ -5,130 +5,28 @@ Author: Krahets (krahets@163.com)
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import os.path as osp
|
||||
import glob
|
||||
import sys, os.path as osp
|
||||
sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__)))))
|
||||
from docs.utils.extract_code_java import ExtractCodeBlocksJava
|
||||
|
||||
class ExtractCodeBlocksPython:
|
||||
|
||||
class ExtractCodeBlocksPython(ExtractCodeBlocksJava):
|
||||
def __init__(self) -> None:
|
||||
self.langs = ["python"]
|
||||
super().__init__()
|
||||
|
||||
# Pattern to match function names and class names
|
||||
self.func_pattern = r'(\s*)def\s+(\w+)\s*\('
|
||||
self.class_pattern = r'class\s+(\w+)'
|
||||
|
||||
self.func_pattern_keys = ["total", "ind", "label"]
|
||||
self.class_pattern_keys = ["total", "label"]
|
||||
|
||||
# Pattern to match the start and end of a block
|
||||
self.block_end_pattern = '^\s{0,ind}\S+.*\n'
|
||||
self.block_start_pattern = '^\s{ind}""".+'
|
||||
|
||||
def extract(self, file_path):
|
||||
"""
|
||||
Extract classes and functions from a markdown document
|
||||
"""
|
||||
self.file_path = file_path
|
||||
with open(file_path) as f:
|
||||
self.lines = f.readlines()
|
||||
self.content = "".join(self.lines)
|
||||
|
||||
# Detect and extract all the classes and fucntions
|
||||
classes = self.extract_class_blocks()
|
||||
funcs = self.extract_function_blocks()
|
||||
|
||||
self.post_process(classes, funcs)
|
||||
|
||||
return {
|
||||
"classes": classes,
|
||||
"funcs": funcs,
|
||||
}
|
||||
|
||||
def search_block(self, header_line, indentation):
|
||||
"""
|
||||
Search class/function block given the header_line and indentation
|
||||
"""
|
||||
start_line, end_line = 0, len(self.lines)
|
||||
|
||||
block_end_pattern = re.compile(self.block_end_pattern.replace("ind", str(indentation)))
|
||||
block_start_pattern = re.compile(self.block_start_pattern.replace("ind", str(indentation)))
|
||||
|
||||
# Search the code
|
||||
for i in range(header_line + 1, len(self.lines)):
|
||||
if re.match(block_end_pattern, self.lines[i]) is not None:
|
||||
end_line = i - 1
|
||||
break
|
||||
# Search the header comment
|
||||
for i in range(header_line - 1, -1, -1):
|
||||
if re.search(block_start_pattern, self.lines[i]) is not None:
|
||||
start_line = i
|
||||
break
|
||||
|
||||
return start_line, end_line, self.lines[start_line:end_line + 1]
|
||||
|
||||
|
||||
def extract_function_blocks(self, indentation=0, start_line=-1, end_line=-1):
|
||||
"""
|
||||
Extract all the functions with given indentation
|
||||
"""
|
||||
funcs = {}
|
||||
|
||||
if start_line == -1:
|
||||
start_line = 0
|
||||
if end_line == -1:
|
||||
end_line = len(self.lines) - 1
|
||||
|
||||
func_pattern = re.compile(self.func_pattern)
|
||||
|
||||
for line_num in range(start_line, end_line + 1):
|
||||
# Search the function header
|
||||
func_match = func_pattern.match(self.lines[line_num])
|
||||
if func_match is None: continue
|
||||
# The function should match the input indentation
|
||||
if len(func_match.group(1)) != indentation: continue
|
||||
header_line = line_num
|
||||
|
||||
# Search the block from the header line
|
||||
start_line, end_line, func_block = self.search_block(header_line, indentation)
|
||||
# Construct the funcs dict
|
||||
func_label = func_match.group(2)
|
||||
funcs[func_label] = {
|
||||
"indentation": indentation,
|
||||
"line_number": {
|
||||
"start": start_line,
|
||||
"end": end_line,
|
||||
"header": header_line,
|
||||
},
|
||||
"block": func_block,
|
||||
}
|
||||
|
||||
return funcs
|
||||
|
||||
def extract_class_blocks(self):
|
||||
"""
|
||||
Extract all the classes with given indentation
|
||||
"""
|
||||
classes = {}
|
||||
|
||||
class_pattern = re.compile(self.class_pattern)
|
||||
|
||||
for line_num, line in enumerate(self.lines):
|
||||
# Search the class header
|
||||
class_match = class_pattern.match(line)
|
||||
if class_match is None: continue
|
||||
header_line = line_num
|
||||
|
||||
# Search the block from the header line
|
||||
start_line, end_line, class_block = self.search_block(header_line, 0)
|
||||
# Construct the classes dict
|
||||
class_label = class_match.group(1)
|
||||
classes[class_label] = {
|
||||
"indentation": 0,
|
||||
"line_number": {
|
||||
"start": start_line,
|
||||
"end": end_line,
|
||||
"header": header_line,
|
||||
},
|
||||
"block": class_block,
|
||||
"funcs": self.extract_function_blocks(
|
||||
indentation=4, start_line=start_line, end_line=end_line)
|
||||
}
|
||||
|
||||
return classes
|
||||
self.block_start_shift = 0
|
||||
self.block_end_shift = -1
|
||||
|
||||
def post_process(self, classes, funcs):
|
||||
"""
|
||||
@ -154,4 +52,4 @@ class ExtractCodeBlocksPython:
|
||||
|
||||
|
||||
# ext = ExtractCodeBlocksPython()
|
||||
# ext.extract("codes/python/chapter_array_and_linkedlist/my_list.py")
|
||||
# ext.extract("codes/python/chapter_array_and_linkedlist/my_list.py")
|
||||
|
||||
Reference in New Issue
Block a user