Merge branch 'krahets:master' into master

This commit is contained in:
zhuoqinyue
2023-01-16 21:08:49 +08:00
committed by GitHub
66 changed files with 931 additions and 172 deletions

View File

@@ -245,6 +245,8 @@ elementAddr = firtstElementAddr + elementLength * elementIndex
for (int i = 0; i < size; i++) {
res[i] = nums[i];
}
// 释放内存
delete[] nums;
// 返回扩展后的新数组
return res;
}

View File

@@ -748,6 +748,11 @@ comments: true
nums = new int[numsCapacity];
}
/* 析构函数 */
~MyList() {
delete[] nums;
}
/* 获取列表长度(即当前元素数量)*/
int size() {
return numsSize;
@@ -818,14 +823,14 @@ comments: true
void extendCapacity() {
// 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组
int newCapacity = capacity() * extendRatio;
int* extend = new int[newCapacity];
int* tmp = nums;
nums = new int[newCapacity];
// 将原数组中的所有元素复制到新数组
for (int i = 0; i < size(); i++) {
extend[i] = nums[i];
nums[i] = tmp[i];
}
int* temp = nums;
nums = extend;
delete[] temp;
// 释放内存
delete[] tmp;
numsCapacity = newCapacity;
}
};

View File

@@ -507,7 +507,7 @@ $$
const int a = 0;
int b = 0;
vector<int> nums(10000);
ListNode* node = new ListNode(0);
ListNode node(0);
// 循环中的变量占用 O(1) 空间
for (int i = 0; i < n; i++) {
int c = 0;
@@ -654,9 +654,9 @@ $$
// 长度为 n 的数组占用 O(n) 空间
vector<int> nums(n);
// 长度为 n 的列表占用 O(n) 空间
vector<ListNode*> nodes;
vector<ListNode> nodes;
for (int i = 0; i < n; i++) {
nodes.push_back(new ListNode(i));
nodes.push_back(ListNode(i));
}
// 长度为 n 的哈希表占用 O(n) 空间
unordered_map<int, string> map;

View File

@@ -606,6 +606,7 @@ comments: true
// 判空处理
if h.isEmpty() {
fmt.Println("error")
return nil
}
// 交换根结点与最右叶结点(即交换首元素与尾元素)
h.swap(0, h.size()-1)
@@ -709,10 +710,10 @@ comments: true
```go title="my_heap.go"
/* 构造函数,根据切片建堆 */
func newMaxHeap(nums []any) *maxHeap {
// 所有元素入
// 将列表元素原封不动添加进
h := &maxHeap{data: nums}
// 堆化除叶结点以外的其他所有结点
for i := len(h.data) - 1; i >= 0; i-- {
// 堆化除叶结点以外的其他所有结点
h.siftDown(i)
}
return h

View File

@@ -228,7 +228,7 @@ comments: true
**稳定排序**:不交换相等元素。
**自适排序**:引入 `flag` 优化后(见下文),最佳时间复杂度为 $O(N)$ 。
**自适排序**:引入 `flag` 优化后(见下文),最佳时间复杂度为 $O(N)$ 。
## 效率优化

View File

@@ -16,20 +16,28 @@ comments: true
=== "Step 1"
![pivot_division_step1](quick_sort.assets/pivot_division_step1.png)
=== "Step 2"
![pivot_division_step2](quick_sort.assets/pivot_division_step2.png)
=== "Step 3"
![pivot_division_step3](quick_sort.assets/pivot_division_step3.png)
=== "Step 4"
![pivot_division_step4](quick_sort.assets/pivot_division_step4.png)
=== "Step 5"
![pivot_division_step5](quick_sort.assets/pivot_division_step5.png)
=== "Step 6"
![pivot_division_step6](quick_sort.assets/pivot_division_step6.png)
=== "Step 7"
![pivot_division_step7](quick_sort.assets/pivot_division_step7.png)
=== "Step 8"
![pivot_division_step8](quick_sort.assets/pivot_division_step8.png)
=== "Step 9"
![pivot_division_step9](quick_sort.assets/pivot_division_step9.png)
@@ -134,27 +142,27 @@ comments: true
``` js title="quick_sort.js"
/* 元素交换 */
function swap(nums, i, j) {
let tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
let tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
/* 哨兵划分 */
function partition(nums, left, right){
function partition(nums, left, right) {
// 以 nums[left] 作为基准数
let i = left, j = right
while(i < j){
while(i < j && nums[j] >= nums[left]){
j -= 1 // 从右向左找首个小于基准数的元素
let i = left, j = right;
while (i < j) {
while (i < j && nums[j] >= nums[left]) {
j -= 1; // 从右向左找首个小于基准数的元素
}
while(i < j && nums[i] <= nums[left]){
i += 1 // 从左向右找首个大于基准数的元素
while (i < j && nums[i] <= nums[left]) {
i += 1; // 从左向右找首个大于基准数的元素
}
// 元素交换
swap(nums, i, j) // 交换这两个元素
swap(nums, i, j); // 交换这两个元素
}
swap(nums, i, left) // 将基准数交换至两子数组的分界线
return i // 返回基准数的索引
swap(nums, i, left); // 将基准数交换至两子数组的分界线
return i; // 返回基准数的索引
}
```
@@ -220,7 +228,6 @@ comments: true
swap(nums, i, left); // 将基准数交换至两子数组的分界线
return i; // 返回基准数的索引
}
```
=== "Swift"
@@ -313,14 +320,14 @@ comments: true
```js title="quick_sort.js"
/* 快速排序 */
function quickSort(nums, left, right){
function quickSort(nums, left, right) {
// 子数组长度为 1 时终止递归
if(left >= right) return
if (left >= right) return;
// 哨兵划分
const pivot = partition(nums, left, right)
const pivot = partition(nums, left, right);
// 递归左子数组、右子数组
quick_sort(nums, left, pivot - 1)
quick_sort(nums, pivot + 1, right)
quickSort(nums, left, pivot - 1);
quickSort(nums, pivot + 1, right);
}
```
@@ -408,7 +415,7 @@ comments: true
int medianThree(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]))
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
return left;
else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right]))
return mid;
@@ -434,7 +441,7 @@ comments: true
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]))
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
return left;
else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right]))
return mid;
@@ -460,7 +467,7 @@ comments: true
def median_three(self, nums, left, mid, right):
# 使用了异或操作来简化代码
# 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
if (nums[left] > nums[mid]) ^ (nums[left] > nums[right]):
if (nums[left] < nums[mid]) ^ (nums[left] < nums[right]):
return left
elif (nums[mid] < nums[left]) ^ (nums[mid] > nums[right]):
return mid
@@ -481,9 +488,9 @@ comments: true
```go title="quick_sort.go"
/* 选取三个元素的中位数 */
func medianThree(nums []int, left, mid, right int) int {
if (nums[left] > nums[mid]) != (nums[left] > nums[right]) {
if (nums[left] < nums[mid]) != (nums[left] < nums[right]) {
return left
} else if (nums[mid] < nums[left]) != (nums[mid] > nums[right]) {
} else if (nums[mid] > nums[left]) != (nums[mid] > nums[right]) {
return mid
}
return right
@@ -507,7 +514,7 @@ comments: true
function medianThree(nums, left, mid, right) {
// 使用了异或操作来简化代码
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right]))
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
return left;
else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right]))
return mid;
@@ -533,7 +540,7 @@ comments: true
function medianThree(nums: number[], left: number, mid: number, right: number): number {
// 使用了异或操作来简化代码
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
if (Number(nums[left] > nums[mid]) ^ Number(nums[left] > nums[right])) {
if (Number(nums[left] < nums[mid]) ^ Number(nums[left] < nums[right])) {
return left;
} else if (Number(nums[mid] < nums[left]) ^ Number(nums[mid] < nums[right])) {
return mid;
@@ -566,7 +573,7 @@ comments: true
{
// 使用了异或操作来简化代码
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right]))
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
return left;
else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right]))
return mid;

View File

@@ -196,5 +196,29 @@ comments: true
=== "Swift"
```swift title="deque.swift"
/* 初始化双向队列 */
// Swift 没有内置的双向队列类,可以把 Array 当作双向队列来使用
var deque: [Int] = []
/* 元素入队 */
deque.append(2) // 添加至队尾
deque.append(5)
deque.append(4)
deque.insert(3, at: 0) // 添加至队首
deque.insert(1, at: 0)
/* 访问元素 */
let peekFirst = deque.first! // 队首元素
let peekLast = deque.last! // 队尾元素
/* 元素出队 */
// 使用 Array 模拟时 pollFirst 的复杂度为 O(n)
let pollFirst = deque.removeFirst() // 队首元素出队
let pollLast = deque.removeLast() // 队尾元素出队
/* 获取双向队列的长度 */
let size = deque.count
/* 判断双向队列是否为空 */
let isEmpty = deque.isEmpty
```

View File

@@ -246,6 +246,7 @@ comments: true
let peek = queue.first!
/* 元素出队 */
// 使用 Array 模拟时 poll 的复杂度为 O(n)
let pool = queue.removeFirst()
/* 获取队列的长度 */
@@ -330,6 +331,10 @@ comments: true
rear = nullptr;
queSize = 0;
}
~LinkedListQueue() {
delete front;
delete rear;
}
/* 获取队列的长度 */
int size() {
return queSize;
@@ -784,6 +789,9 @@ comments: true
cap = capacity;
nums = new int[capacity];
}
~ArrayQueue() {
delete[] nums;
}
/* 获取队列的容量 */
int capacity() {
return cap;

View File

@@ -324,6 +324,9 @@ comments: true
stackTop = nullptr;
stkSize = 0;
}
~LinkedListStack() {
freeMemoryLinkedList(stackTop);
}
/* 获取栈的长度 */
int size() {
return stkSize;

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -22,19 +22,15 @@ comments: true
-`cur.val = num` ,说明找到目标结点,跳出循环并返回该结点即可;
=== "Step 1"
![bst_search_1](binary_search_tree.assets/bst_search_1.png)
=== "Step 2"
![bst_search_2](binary_search_tree.assets/bst_search_2.png)
=== "Step 3"
![bst_search_3](binary_search_tree.assets/bst_search_3.png)
=== "Step 4"
![bst_search_4](binary_search_tree.assets/bst_search_4.png)
二叉搜索树的查找操作和二分查找算法如出一辙,也是在每轮排除一半情况。循环次数最多为二叉树的高度,当二叉树平衡时,使用 $O(\log n)$ 时间。
@@ -483,9 +479,9 @@ comments: true
// 找到待删除结点,跳出循环
if (cur.val == num) break;
pre = cur;
// 待删除结点在 root 的右子树中
// 待删除结点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除结点在 root 的左子树中
// 待删除结点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除结点,则直接返回
@@ -527,9 +523,9 @@ comments: true
// 找到待删除结点,跳出循环
if (cur->val == num) break;
pre = cur;
// 待删除结点在 root 的右子树中
// 待删除结点在 cur 的右子树中
if (cur->val < num) cur = cur->right;
// 待删除结点在 root 的左子树中
// 待删除结点在 cur 的左子树中
else cur = cur->left;
}
// 若无待删除结点,则直接返回
@@ -575,9 +571,9 @@ comments: true
if cur.val == num:
break
pre = cur
if cur.val < num: # 待删除结点在 root 的右子树中
if cur.val < num: # 待删除结点在 cur 的右子树中
cur = cur.right
else: # 待删除结点在 root 的左子树中
else: # 待删除结点在 cur 的左子树中
cur = cur.left
# 若无待删除结点,则直接返回
@@ -677,9 +673,9 @@ comments: true
// 找到待删除结点,跳出循环
if (cur.val === num) break;
pre = cur;
// 待删除结点在 root 的右子树中
// 待删除结点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除结点在 root 的左子树中
// 待删除结点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除结点,则直接返回
@@ -725,9 +721,9 @@ comments: true
}
pre = cur;
if (cur.val < num) {
cur = cur.right as TreeNode; // 待删除结点在 root 的右子树中
cur = cur.right as TreeNode; // 待删除结点在 cur 的右子树中
} else {
cur = cur.left as TreeNode; // 待删除结点在 root 的左子树中
cur = cur.left as TreeNode; // 待删除结点在 cur 的左子树中
}
}
// 若无待删除结点,则直接返回
@@ -780,9 +776,9 @@ comments: true
// 找到待删除结点,跳出循环
if (cur.val == num) break;
pre = cur;
// 待删除结点在 root 的右子树中
// 待删除结点在 cur 的右子树中
if (cur.val < num) cur = cur.right;
// 待删除结点在 root 的左子树中
// 待删除结点在 cur 的左子树中
else cur = cur.left;
}
// 若无待删除结点,则直接返回

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 177 KiB