mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-24 09:46:29 +08:00
Several enhancements and fixes
This commit is contained in:
parent
a9d70e9e4b
commit
d190dbf3c1
18 changed files with 84 additions and 70 deletions
|
@ -78,7 +78,7 @@ class MaxHeap {
|
|||
}
|
||||
|
||||
/* 判断堆是否为空 */
|
||||
bool empty() {
|
||||
bool isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ class MaxHeap {
|
|||
/* 元素出堆 */
|
||||
void pop() {
|
||||
// 判空处理
|
||||
if (empty()) {
|
||||
if (isEmpty()) {
|
||||
throw out_of_range("堆为空");
|
||||
}
|
||||
// 交换根节点与最右叶节点(即交换首元素与尾元素)
|
||||
|
@ -149,7 +149,7 @@ int main() {
|
|||
cout << "\n堆元素数量为 " << size << endl;
|
||||
|
||||
/* 判断堆是否为空 */
|
||||
bool isEmpty = maxHeap.empty();
|
||||
bool isEmpty = maxHeap.isEmpty();
|
||||
cout << "\n堆是否为空 " << isEmpty << endl;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -37,7 +37,7 @@ class ArrayQueue {
|
|||
}
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty() {
|
||||
bool isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ class ArrayQueue {
|
|||
|
||||
/* 访问队首元素 */
|
||||
int peek() {
|
||||
if (empty())
|
||||
if (isEmpty())
|
||||
throw out_of_range("队列为空");
|
||||
return nums[front];
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ int main() {
|
|||
cout << "队列长度 size = " << size << endl;
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty = queue->empty();
|
||||
bool empty = queue->isEmpty();
|
||||
cout << "队列是否为空 = " << empty << endl;
|
||||
|
||||
/* 测试环形数组 */
|
||||
|
|
|
@ -18,8 +18,8 @@ class ArrayStack {
|
|||
}
|
||||
|
||||
/* 判断栈是否为空 */
|
||||
bool empty() {
|
||||
return stack.empty();
|
||||
bool isEmpty() {
|
||||
return stack.size() == 0;
|
||||
}
|
||||
|
||||
/* 入栈 */
|
||||
|
@ -35,7 +35,7 @@ class ArrayStack {
|
|||
|
||||
/* 访问栈顶元素 */
|
||||
int top() {
|
||||
if (empty())
|
||||
if (isEmpty())
|
||||
throw out_of_range("栈为空");
|
||||
return stack.back();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ int main() {
|
|||
cout << "栈的长度 size = " << size << endl;
|
||||
|
||||
/* 判断是否为空 */
|
||||
bool empty = stack->empty();
|
||||
bool empty = stack->isEmpty();
|
||||
cout << "栈是否为空 = " << empty << endl;
|
||||
|
||||
// 释放内存
|
||||
|
|
|
@ -81,9 +81,8 @@ class LinkedListDeque {
|
|||
|
||||
/* 出队操作 */
|
||||
int pop(bool isFront) {
|
||||
// 若队列为空,直接返回 -1
|
||||
if (isEmpty())
|
||||
return -1;
|
||||
throw out_of_range("队列为空");
|
||||
int val;
|
||||
// 队首出队操作
|
||||
if (isFront) {
|
||||
|
@ -124,12 +123,16 @@ class LinkedListDeque {
|
|||
|
||||
/* 访问队首元素 */
|
||||
int peekFirst() {
|
||||
return isEmpty() ? -1 : front->val;
|
||||
if (isEmpty())
|
||||
throw out_of_range("双向队列为空");
|
||||
return front->val;
|
||||
}
|
||||
|
||||
/* 访问队尾元素 */
|
||||
int peekLast() {
|
||||
return isEmpty() ? -1 : rear->val;
|
||||
if (isEmpty())
|
||||
throw out_of_range("双向队列为空");
|
||||
return rear->val;
|
||||
}
|
||||
|
||||
/* 返回数组用于打印 */
|
||||
|
|
|
@ -30,7 +30,7 @@ class LinkedListQueue {
|
|||
}
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty() {
|
||||
bool isEmpty() {
|
||||
return queSize == 0;
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ int main() {
|
|||
cout << "队列长度 size = " << size << endl;
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty = queue->empty();
|
||||
bool empty = queue->isEmpty();
|
||||
cout << "队列是否为空 = " << empty << endl;
|
||||
|
||||
// 释放内存
|
||||
|
|
|
@ -29,7 +29,7 @@ class LinkedListStack {
|
|||
}
|
||||
|
||||
/* 判断栈是否为空 */
|
||||
bool empty() {
|
||||
bool isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ class LinkedListStack {
|
|||
|
||||
/* 访问栈顶元素 */
|
||||
int top() {
|
||||
if (size() == 0)
|
||||
if (isEmpty())
|
||||
throw out_of_range("栈为空");
|
||||
return stackTop->val;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ int main() {
|
|||
cout << "栈的长度 size = " << size << endl;
|
||||
|
||||
/* 判断是否为空 */
|
||||
bool empty = stack->empty();
|
||||
bool empty = stack->isEmpty();
|
||||
cout << "栈是否为空 = " << empty << endl;
|
||||
|
||||
// 释放内存
|
||||
|
|
|
@ -77,34 +77,29 @@ public class LinkedListDeque {
|
|||
|
||||
/* 出队操作 */
|
||||
private int? pop(bool isFront) {
|
||||
// 若队列为空,直接返回 null
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isEmpty())
|
||||
throw new Exception();
|
||||
int val;
|
||||
// 队首出队操作
|
||||
if (isFront) {
|
||||
val = front.val; // 暂存头节点值
|
||||
// 删除头节点
|
||||
// 删除头节点
|
||||
ListNode fNext = front.next;
|
||||
if (fNext != null) {
|
||||
fNext.prev = null;
|
||||
front.next = null;
|
||||
}
|
||||
|
||||
front = fNext; // 更新头节点
|
||||
}
|
||||
// 队尾出队操作
|
||||
else {
|
||||
val = rear.val; // 暂存尾节点值
|
||||
// 删除尾节点
|
||||
// 删除尾节点
|
||||
ListNode rPrev = rear.prev;
|
||||
if (rPrev != null) {
|
||||
rPrev.next = null;
|
||||
rear.prev = null;
|
||||
}
|
||||
|
||||
rear = rPrev; // 更新尾节点
|
||||
}
|
||||
|
||||
|
@ -124,12 +119,16 @@ public class LinkedListDeque {
|
|||
|
||||
/* 访问队首元素 */
|
||||
public int? peekFirst() {
|
||||
return isEmpty() ? null : front.val;
|
||||
if (isEmpty())
|
||||
throw new Exception();
|
||||
return front.val;
|
||||
}
|
||||
|
||||
/* 访问队尾元素 */
|
||||
public int? peekLast() {
|
||||
return isEmpty() ? null : rear.val;
|
||||
if (isEmpty())
|
||||
throw new Exception();
|
||||
return rear.val;
|
||||
}
|
||||
|
||||
/* 返回数组用于打印 */
|
||||
|
|
|
@ -53,7 +53,7 @@ class LinkedListQueue {
|
|||
|
||||
/* 访问队首元素 */
|
||||
public int peek() {
|
||||
if (size() == 0 || front == null)
|
||||
if (isEmpty())
|
||||
throw new Exception();
|
||||
return front.val;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,6 @@ class LinkedListStack {
|
|||
|
||||
/* 出栈 */
|
||||
public int pop() {
|
||||
if (stackPeek == null)
|
||||
throw new Exception();
|
||||
|
||||
int num = peek();
|
||||
stackPeek = stackPeek.next;
|
||||
stkSize--;
|
||||
|
@ -46,7 +43,7 @@ class LinkedListStack {
|
|||
|
||||
/* 访问栈顶元素 */
|
||||
public int peek() {
|
||||
if (size() == 0 || stackPeek == null)
|
||||
if (isEmpty())
|
||||
throw new Exception();
|
||||
return stackPeek.val;
|
||||
}
|
||||
|
|
|
@ -72,10 +72,9 @@ class LinkedListDeque {
|
|||
}
|
||||
|
||||
/* 出队操作 */
|
||||
private Integer pop(boolean isFront) {
|
||||
// 若队列为空,直接返回 null
|
||||
private int pop(boolean isFront) {
|
||||
if (isEmpty())
|
||||
return null;
|
||||
throw new IndexOutOfBoundsException();
|
||||
int val;
|
||||
// 队首出队操作
|
||||
if (isFront) {
|
||||
|
@ -103,23 +102,27 @@ class LinkedListDeque {
|
|||
}
|
||||
|
||||
/* 队首出队 */
|
||||
public Integer popFirst() {
|
||||
public int popFirst() {
|
||||
return pop(true);
|
||||
}
|
||||
|
||||
/* 队尾出队 */
|
||||
public Integer popLast() {
|
||||
public int popLast() {
|
||||
return pop(false);
|
||||
}
|
||||
|
||||
/* 访问队首元素 */
|
||||
public Integer peekFirst() {
|
||||
return isEmpty() ? null : front.val;
|
||||
public int peekFirst() {
|
||||
if (isEmpty())
|
||||
throw new IndexOutOfBoundsException();
|
||||
return front.val;
|
||||
}
|
||||
|
||||
/* 访问队尾元素 */
|
||||
public Integer peekLast() {
|
||||
return isEmpty() ? null : rear.val;
|
||||
public int peekLast() {
|
||||
if (isEmpty())
|
||||
throw new IndexOutOfBoundsException();
|
||||
return rear.val;
|
||||
}
|
||||
|
||||
/* 返回数组用于打印 */
|
||||
|
|
|
@ -55,7 +55,7 @@ class LinkedListQueue {
|
|||
|
||||
/* 访问队首元素 */
|
||||
public int peek() {
|
||||
if (size() == 0)
|
||||
if (isEmpty())
|
||||
throw new IndexOutOfBoundsException();
|
||||
return front.val;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class LinkedListStack {
|
|||
|
||||
/* 访问栈顶元素 */
|
||||
public int peek() {
|
||||
if (size() == 0)
|
||||
if (isEmpty())
|
||||
throw new IndexOutOfBoundsException();
|
||||
return stackPeek.val;
|
||||
}
|
||||
|
|
|
@ -62,9 +62,8 @@ class LinkedListDeque:
|
|||
|
||||
def pop(self, is_front: bool) -> int:
|
||||
"""出队操作"""
|
||||
# 若队列为空,直接返回 None
|
||||
if self.is_empty():
|
||||
return None
|
||||
raise IndexError("双向队列为空")
|
||||
# 队首出队操作
|
||||
if is_front:
|
||||
val: int = self.front.val # 暂存头节点值
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
!!! question "数组存储在栈上和存储在堆上,对时间效率和空间效率是否有影响?"
|
||||
|
||||
栈内存分配由编译器自动完成,而堆内存由程序员在代码中分配(注意,这里的栈和堆和数据结构中的栈和堆不是同一概念)。
|
||||
存储在栈上和堆上的数组都被存储在连续内存空间内,数据操作效率是基本一致的。然而,栈和堆具有各自的特点,从而导致以下不同点。
|
||||
|
||||
1. 栈不灵活,分配的内存大小不可更改;堆相对灵活,可以动态分配内存。
|
||||
2. 栈是一块比较小的内存,容易出现内存不足;堆内存很大,但是由于是动态分配,容易碎片化,管理堆内存的难度更大、成本更高。
|
||||
3. 访问栈比访问堆更快,因为栈内存较小、对缓存友好,堆帧分散在很大的空间内,会出现更多的缓存未命中。
|
||||
1. 分配和释放效率:栈是一块较小的内存,分配由编译器自动完成;而堆内存相对更大,可以在代码中动态分配,更容易碎片化。因此,堆上的分配和释放操作通常比栈上的慢。
|
||||
2. 大小限制:栈内存相对较小,堆的大小一般受限于可用内存。因此堆更加适合存储大型数组。
|
||||
3. 灵活性:栈上的数组的大小需要在编译时确定,而堆上的数组的大小可以在运行时动态确定。
|
||||
|
||||
!!! question "为什么数组要求相同类型的元素,而在链表中却没有强调同类型呢?"
|
||||
|
||||
|
|
|
@ -2,25 +2,26 @@
|
|||
|
||||
在某些情况下,我们希望使用一个列表的所有元素来构建一个堆,这个过程被称为“建堆操作”。
|
||||
|
||||
## 自上而下构建
|
||||
## 借助入堆操作实现
|
||||
|
||||
我们首先创建一个空堆,然后遍历列表,依次对每个元素执行“入堆操作”,即先将元素添加至堆的尾部,再对该元素执行“从底至顶”堆化。
|
||||
|
||||
每当一个元素入堆,堆的长度就加一,因此堆是“自上而下”地构建的。
|
||||
每当一个元素入堆,堆的长度就加一。由于节点是从顶到底依次被添加进二叉树的,因此堆是“自上而下”地构建的。
|
||||
|
||||
设元素数量为 $n$ ,每个元素的入堆操作使用 $O(\log{n})$ 时间,因此该建堆方法的时间复杂度为 $O(n \log n)$ 。
|
||||
|
||||
## 自下而上构建
|
||||
## 通过遍历堆化实现
|
||||
|
||||
实际上,我们可以实现一种更为高效的建堆方法,共分为两步。
|
||||
|
||||
1. 将列表所有元素原封不动添加到堆中。
|
||||
1. 将列表所有元素原封不动添加到堆中,此时堆的性质尚未得到满足。
|
||||
2. 倒序遍历堆(即层序遍历的倒序),依次对每个非叶节点执行“从顶至底堆化”。
|
||||
|
||||
在倒序遍历中,堆是“自下而上”地构建的,需要重点理解以下两点。
|
||||
**每当堆化一个节点后,以该节点为根节点的子树就形成一个合法的子堆**。而由于是倒序遍历,因此堆是“自下而上”地被构建的。
|
||||
|
||||
- 由于叶节点没有子节点,因此无需对它们执行堆化。最后一个节点的父节点是最后一个非叶节点。
|
||||
- 在倒序遍历中,我们能够保证当前节点之下的子树已经完成堆化(已经是合法的堆),而这是堆化当前节点的前置条件。
|
||||
之所以选择倒序遍历,是因为这样能够保证当前节点之下的子树已经是合法的子堆,这样堆化当前节点才是有效的。
|
||||
|
||||
值得说明的是,**叶节点没有子节点,天然就是合法的子堆,因此无需堆化**。如以下代码所示,最后一个非叶节点是最后一个节点的父节点,我们从它开始倒序遍历并执行堆化。
|
||||
|
||||
=== "Python"
|
||||
|
||||
|
|
|
@ -21,3 +21,11 @@
|
|||
!!! question "双向队列像是两个栈拼接在了一起,它的用途是什么?"
|
||||
|
||||
双向队列就像是栈和队列的组合,或者是两个栈拼在了一起。它表现的是栈 + 队列的逻辑,因此可以实现栈与队列的所有应用,并且更加灵活。
|
||||
|
||||
!!! question "撤销(undo)和反撤销(redo)具体是如何实现的?"
|
||||
|
||||
使用两个堆栈,栈 `A` 用于撤销,栈 `B` 用于反撤销。
|
||||
|
||||
1. 每当用户执行一个操作,将这个操作压入栈 `A` ,并清空栈 `B` 。
|
||||
2. 当用户执行“撤销”时,从栈 `A` 中弹出最近的操作,并将其压入栈 `B` 。
|
||||
3. 当用户执行“反撤销”时,从栈 `B` 中弹出最近的操作,并将其压入栈 `A` 。
|
||||
|
|
|
@ -106,19 +106,20 @@ hide:
|
|||
</a>
|
||||
</p>
|
||||
|
||||
本书的代码审阅工作由 Gonglja, gvenusleo, justin‐tse, krahets, nuomi1, Reanon, sjinzh 完成(按照首字母顺序排列)。感谢他们付出的时间与精力,正是他们确保了各语言代码的规范与统一。
|
||||
本书的代码审阅工作由 Gonglja, gvenusleo, justin‐tse, krahets, night-cruise, nuomi1, Reanon, sjinzh 完成(按照首字母顺序排列)。感谢他们付出的时间与精力,正是他们确保了各语言代码的规范与统一。
|
||||
|
||||
<div class="center-table">
|
||||
<table>
|
||||
<tbody>
|
||||
<td align="center"><a href="https://github.com/Gonglja"><img src="https://avatars.githubusercontent.com/u/39959756?v=4" width="50px;" alt="Gonglja"/><br /><sub><b>Gonglja</b></sub></a><br /><sub>C / C++</sub></td>
|
||||
<td align="center"><a href="https://github.com/gvenusleo"><img src="https://avatars.githubusercontent.com/u/79075347?v=4" width="50px;" alt="gvenusleo"/><br /><sub><b>gvenusleo</b></sub></a><br /><sub>Dart</sub></td>
|
||||
<td align="center"><a href="https://github.com/hpstory"><img src="https://avatars.githubusercontent.com/u/33348162?v=4" width="50px;" alt="hpstory"/><br /><sub><b>hpstory</b></sub></a><br /><sub>C#</sub></td>
|
||||
<td align="center"><a href="https://github.com/justin-tse"><img src="https://avatars.githubusercontent.com/u/24556310?v=4" width="50px;" alt="justin-tse"/><br /><sub><b>justin-tse</b></sub></a><br /><sub>JS / TS</sub></td>
|
||||
<td align="center"><a href="https://github.com/krahets"><img src="https://avatars.githubusercontent.com/u/26993056?v=4" width="50px;" alt="krahets"/><br /><sub><b>krahets</b></sub></a><br /><sub>Java / Python</sub></td>
|
||||
<td align="center"><a href="https://github.com/nuomi1"><img src="https://avatars.githubusercontent.com/u/3739017?v=4" width="50px;" alt="nuomi1"/><br /><sub><b>nuomi1</b></sub></a><br /><sub>Swift</sub></td>
|
||||
<td align="center"><a href="https://github.com/Reanon"><img src="https://avatars.githubusercontent.com/u/22005836?v=4" width="50px;" alt="Reanon"/><br /><sub><b>Reanon</b></sub></a><br /><sub>Go / C</sub></td>
|
||||
<td align="center"><a href="https://github.com/sjinzh"><img src="https://avatars.githubusercontent.com/u/99076655?v=4" width="50px;" alt="sjinzh"/><br /><sub><b>sjinzh</b></sub></a><br /><sub>Rust / Zig</sub></td>
|
||||
<td align="center"><a href="https://github.com/Gonglja"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/39959756?v=4" width="50px;" alt="Gonglja"/><br /><sub><b>Gonglja</b></sub></a><br /><sub>C, C++</sub></td>
|
||||
<td align="center"><a href="https://github.com/gvenusleo"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/79075347?v=4" width="50px;" alt="gvenusleo"/><br /><sub><b>gvenusleo</b></sub></a><br /><sub>Dart</sub></td>
|
||||
<td align="center"><a href="https://github.com/hpstory"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/33348162?v=4" width="50px;" alt="hpstory"/><br /><sub><b>hpstory</b></sub></a><br /><sub>C#</sub></td>
|
||||
<td align="center"><a href="https://github.com/justin-tse"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/24556310?v=4" width="50px;" alt="justin-tse"/><br /><sub><b>justin-tse</b></sub></a><br /><sub>JS, TS</sub></td>
|
||||
<td align="center"><a href="https://github.com/krahets"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/26993056?v=4" width="50px;" alt="krahets"/><br /><sub><b>krahets</b></sub></a><br /><sub>Java, Python</sub></td>
|
||||
<td align="center"><a href="https://github.com/night-cruise"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/77157236?v=4" width="50px;" alt="night-cruise"/><br /><sub><b>night-cruise</b></sub></a><br /><sub>Rust</sub></td>
|
||||
<td align="center"><a href="https://github.com/nuomi1"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/3739017?v=4" width="50px;" alt="nuomi1"/><br /><sub><b>nuomi1</b></sub></a><br /><sub>Swift</sub></td>
|
||||
<td align="center"><a href="https://github.com/Reanon"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/22005836?v=4" width="50px;" alt="Reanon"/><br /><sub><b>Reanon</b></sub></a><br /><sub>Go, C</sub></td>
|
||||
<td align="center"><a href="https://github.com/sjinzh"><img style="border-radius: 50%;" src="https://avatars.githubusercontent.com/u/99076655?v=4" width="50px;" alt="sjinzh"/><br /><sub><b>sjinzh</b></sub></a><br /><sub>Rust, Zig</sub></td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
--md-default-fg-color: #1d1d20;
|
||||
--md-default-bg-color: #ffffff;
|
||||
|
||||
--md-code-fg-color: #1d1d20;
|
||||
|
||||
--md-accent-fg-color: #999;
|
||||
|
||||
--md-admonition-fg-color: #1d1d20;
|
||||
|
@ -23,9 +25,10 @@
|
|||
--md-default-fg-color: #adbac7;
|
||||
--md-default-bg-color: #22272e;
|
||||
|
||||
--md-code-bg-color: #1c2329;
|
||||
--md-code-bg-color: #2D333B;
|
||||
--md-code-fg-color: #adbac7;
|
||||
|
||||
--md-accent-fg-color: #999;
|
||||
--md-accent-fg-color: #aaa;
|
||||
|
||||
--md-admonition-fg-color: #adbac7;
|
||||
|
||||
|
|
Loading…
Reference in a new issue