From 5cc58c7b916cc97a61ddd4a8d6ca4d060474f0e1 Mon Sep 17 00:00:00 2001 From: Gonglja Date: Thu, 12 Jan 2023 07:08:56 +0800 Subject: [PATCH 01/13] =?UTF-8?q?fix(docs/cpp):=20fix=20=20error:=20compar?= =?UTF-8?q?ison=20of=20integer=20expressions=20of=20different=20signedness?= =?UTF-8?q?:=20=E2=80=98size=5Ft=E2=80=99=20{aka=20=E2=80=98long=20unsigne?= =?UTF-8?q?d=20int=E2=80=99}=20and=20=E2=80=98int=E2=80=99=20[-Werror=3Dsi?= =?UTF-8?q?gn-compare]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codes/cpp/chapter_array_and_linkedlist/list.cpp | 4 ++-- .../worst_best_time_complexity.cpp | 2 +- codes/cpp/chapter_searching/hashing_search.cpp | 2 +- codes/cpp/chapter_searching/linear_search.cpp | 2 +- codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codes/cpp/chapter_array_and_linkedlist/list.cpp b/codes/cpp/chapter_array_and_linkedlist/list.cpp index 44bbf88c..aadf83d4 100644 --- a/codes/cpp/chapter_array_and_linkedlist/list.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/list.cpp @@ -48,8 +48,8 @@ int main() { PrintUtil::printVector(list); /* 通过索引遍历列表 */ - int count = 0; - for (int i = 0; i < list.size(); i++) { + size_t count = 0; + for (size_t i = 0; i < list.size(); i++) { count++; } diff --git a/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp b/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp index c2916cb4..c3f35ada 100644 --- a/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp +++ b/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp @@ -22,7 +22,7 @@ vector randomNumbers(int n) { /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector& nums) { - for (int i = 0; i < nums.size(); i++) { + for (size_t i = 0; i < nums.size(); i++) { if (nums[i] == 1) return i; } diff --git a/codes/cpp/chapter_searching/hashing_search.cpp b/codes/cpp/chapter_searching/hashing_search.cpp index ebc2fb01..57c9f5d1 100644 --- a/codes/cpp/chapter_searching/hashing_search.cpp +++ b/codes/cpp/chapter_searching/hashing_search.cpp @@ -33,7 +33,7 @@ int main() { vector nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; // 初始化哈希表 unordered_map map; - for (int i = 0; i < nums.size(); i++) { + for (size_t i = 0; i < nums.size(); i++) { map[nums[i]] = i; // key: 元素,value: 索引 } int index = hashingSearch(map, target); diff --git a/codes/cpp/chapter_searching/linear_search.cpp b/codes/cpp/chapter_searching/linear_search.cpp index 7b509276..45a08ded 100644 --- a/codes/cpp/chapter_searching/linear_search.cpp +++ b/codes/cpp/chapter_searching/linear_search.cpp @@ -9,7 +9,7 @@ /* 线性查找(数组) */ int linearSearch(vector& nums, int target) { // 遍历数组 - for (int i = 0; i < nums.size(); i++) { + for (size_t i = 0; i < nums.size(); i++) { // 找到目标元素,返回其索引 if (nums[i] == target) return i; diff --git a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp index ae22740d..5694e702 100644 --- a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp @@ -68,7 +68,7 @@ public: vector toVector() { ListNode* node = front; vector res(size()); - for (int i = 0; i < res.size(); i++) { + for (size_t i = 0; i < res.size(); i++) { res[i] = node->val; node = node->next; } From 5271276f4e0e7e8efd5bdd14e761e973d89d33d5 Mon Sep 17 00:00:00 2001 From: Gonglja Date: Thu, 12 Jan 2023 11:02:39 +0800 Subject: [PATCH 02/13] feat(codes/c): add linked_list.c --- .../CMakeLists.txt | 3 +- .../linked_list.c | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 codes/c/chapter_array_and_linkedlist/linked_list.c diff --git a/codes/c/chapter_array_and_linkedlist/CMakeLists.txt b/codes/c/chapter_array_and_linkedlist/CMakeLists.txt index 24658b30..dfa3322f 100644 --- a/codes/c/chapter_array_and_linkedlist/CMakeLists.txt +++ b/codes/c/chapter_array_and_linkedlist/CMakeLists.txt @@ -1 +1,2 @@ -add_executable(array array.c) \ No newline at end of file +add_executable(array array.c) +add_executable(linked_list linked_list.c) \ No newline at end of file diff --git a/codes/c/chapter_array_and_linkedlist/linked_list.c b/codes/c/chapter_array_and_linkedlist/linked_list.c new file mode 100644 index 00000000..ed576425 --- /dev/null +++ b/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -0,0 +1,89 @@ +/** + * File: linked_list.c + * Created Time: 2022-01-12 + * Author: Zero (glj0@outlook.com) + */ + + #include "../include/include.h" + + /* 在链表的结点 n0 之后插入结点 P */ +void insertNode(ListNode* n0, ListNode* P) { + ListNode *n1; + n1 = n0 -> next; + n0 -> next = P; + P -> next = n1; +} + +/* 删除链表的结点 n0 之后的首个结点 */ +void removeNode(ListNode* n0) { + // n0 -> P -> n1 + ListNode *n1, *P; + P = n0 -> next; + n1 = P -> next; + n0 -> next = n1; + + free(P); +} + +/* 访问链表中索引为 index 的结点 */ +ListNode* accessNode(ListNode* head, int index) { + ListNode* n; + while(head && head->next && index) { + head = head->next; + index --; + } + n = head; +} + +/* 在链表中查找值为 target 的首个结点 */ +int findNode(ListNode* head, int target) { + ListNode* n; + int idx=0; + while(head) { + if(head->val == target) { + return idx; + } + head = head -> next; + idx ++; + } + return -1; +} + + +/* Driver Code */ +int main() { + /* 初始化链表 */ + // 初始化各个结点 + ListNode* n0 = newListNode(1); + ListNode* n1 = newListNode(2); + ListNode* n2 = newListNode(3); + ListNode* n3 = newListNode(4); + ListNode* n4 = newListNode(5); + // 构建引用指向 + n0->next = n1; + n1->next = n2; + n2->next = n3; + n3->next = n4; + printf("初始化的链表为\r\n"); + printLinkedList(n0); + + /* 插入结点 */ + insertNode(n0, newListNode(0)); + printf("插入结点后的链表为\r\n"); + printLinkedList(n0); + + /* 删除结点 */ + removeNode(n0); + printf("删除结点后的链表为\r\n"); + printLinkedList(n0); + + /* 访问结点 */ + ListNode* node = accessNode(n0, 3); + printf("链表中索引 3 处的结点的值 = %d\r\n", node->val); + + /* 查找结点 */ + int index = findNode(n0, 5); + printf("链表中值为 5 的结点的索引 = %d\r\n", index); + + return 0; +} From be2d109c5be6ca48d50f233ac4200858f98a881f Mon Sep 17 00:00:00 2001 From: Gonglja Date: Thu, 12 Jan 2023 15:16:57 +0800 Subject: [PATCH 03/13] style(codes/c): update comment format --- .../linked_list.c | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/codes/c/chapter_array_and_linkedlist/linked_list.c b/codes/c/chapter_array_and_linkedlist/linked_list.c index ed576425..5ce7cf4c 100644 --- a/codes/c/chapter_array_and_linkedlist/linked_list.c +++ b/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -4,47 +4,44 @@ * Author: Zero (glj0@outlook.com) */ - #include "../include/include.h" +#include "../include/include.h" /* 在链表的结点 n0 之后插入结点 P */ void insertNode(ListNode* n0, ListNode* P) { - ListNode *n1; - n1 = n0 -> next; - n0 -> next = P; - P -> next = n1; + ListNode *n1 = n0->next; + n0->next = P; + P->next = n1; } /* 删除链表的结点 n0 之后的首个结点 */ void removeNode(ListNode* n0) { + if (!n0->next) + return; // n0 -> P -> n1 - ListNode *n1, *P; - P = n0 -> next; - n1 = P -> next; - n0 -> next = n1; - + ListNode *P = n0->next; + ListNode *n1 = P->next; + n0->next = n1; + // 释放内存 free(P); } /* 访问链表中索引为 index 的结点 */ ListNode* accessNode(ListNode* head, int index) { - ListNode* n; - while(head && head->next && index) { + while (head && head->next && index) { head = head->next; - index --; + index--; } - n = head; + return head; } /* 在链表中查找值为 target 的首个结点 */ int findNode(ListNode* head, int target) { - ListNode* n; - int idx=0; - while(head) { - if(head->val == target) { - return idx; - } - head = head -> next; - idx ++; + int index = 0; + while (head) { + if (head->val == target) + return index; + head = head->next; + index++; } return -1; } @@ -55,10 +52,10 @@ int main() { /* 初始化链表 */ // 初始化各个结点 ListNode* n0 = newListNode(1); - ListNode* n1 = newListNode(2); - ListNode* n2 = newListNode(3); - ListNode* n3 = newListNode(4); - ListNode* n4 = newListNode(5); + ListNode* n1 = newListNode(3); + ListNode* n2 = newListNode(2); + ListNode* n3 = newListNode(5); + ListNode* n4 = newListNode(4); // 构建引用指向 n0->next = n1; n1->next = n2; @@ -82,8 +79,8 @@ int main() { printf("链表中索引 3 处的结点的值 = %d\r\n", node->val); /* 查找结点 */ - int index = findNode(n0, 5); - printf("链表中值为 5 的结点的索引 = %d\r\n", index); + int index = findNode(n0, 2); + printf("链表中值为 2 的结点的索引 = %d\r\n", index); return 0; } From 78d7d07bd9cfc4308b50cc756b0743c9e0d0367c Mon Sep 17 00:00:00 2001 From: Gonglja Date: Fri, 13 Jan 2023 06:01:21 +0800 Subject: [PATCH 04/13] style(codes/c): update comment format --- codes/c/chapter_array_and_linkedlist/linked_list.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/codes/c/chapter_array_and_linkedlist/linked_list.c b/codes/c/chapter_array_and_linkedlist/linked_list.c index 5ce7cf4c..8228c48c 100644 --- a/codes/c/chapter_array_and_linkedlist/linked_list.c +++ b/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -7,13 +7,15 @@ #include "../include/include.h" /* 在链表的结点 n0 之后插入结点 P */ -void insertNode(ListNode* n0, ListNode* P) { +void insert(ListNode* n0, ListNode* P) { ListNode *n1 = n0->next; n0->next = P; P->next = n1; } /* 删除链表的结点 n0 之后的首个结点 */ +/* Keep Sample, 受 c 语言特性限制,removeNode 无法更改为 remove, + 详见 https://github.com/krahets/hello-algo/pull/244#discussion_r1067863888 */ void removeNode(ListNode* n0) { if (!n0->next) return; @@ -26,7 +28,7 @@ void removeNode(ListNode* n0) { } /* 访问链表中索引为 index 的结点 */ -ListNode* accessNode(ListNode* head, int index) { +ListNode* access(ListNode* head, int index) { while (head && head->next && index) { head = head->next; index--; @@ -35,7 +37,7 @@ ListNode* accessNode(ListNode* head, int index) { } /* 在链表中查找值为 target 的首个结点 */ -int findNode(ListNode* head, int target) { +int find(ListNode* head, int target) { int index = 0; while (head) { if (head->val == target) @@ -65,7 +67,7 @@ int main() { printLinkedList(n0); /* 插入结点 */ - insertNode(n0, newListNode(0)); + insert(n0, newListNode(0)); printf("插入结点后的链表为\r\n"); printLinkedList(n0); @@ -75,11 +77,11 @@ int main() { printLinkedList(n0); /* 访问结点 */ - ListNode* node = accessNode(n0, 3); + ListNode* node = access(n0, 3); printf("链表中索引 3 处的结点的值 = %d\r\n", node->val); /* 查找结点 */ - int index = findNode(n0, 2); + int index = find(n0, 2); printf("链表中值为 2 的结点的索引 = %d\r\n", index); return 0; From 845e70366d6cbb114b47f79a5ce6832e5e0fda7d Mon Sep 17 00:00:00 2001 From: Gonglja Date: Fri, 13 Jan 2023 15:07:12 +0800 Subject: [PATCH 05/13] feat(codes/cpp): revert the changes `size_t` back to `int` --- codes/cpp/chapter_array_and_linkedlist/list.cpp | 4 ++-- .../worst_best_time_complexity.cpp | 2 +- codes/cpp/chapter_searching/hashing_search.cpp | 2 +- codes/cpp/chapter_searching/linear_search.cpp | 2 +- codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codes/cpp/chapter_array_and_linkedlist/list.cpp b/codes/cpp/chapter_array_and_linkedlist/list.cpp index aadf83d4..44bbf88c 100644 --- a/codes/cpp/chapter_array_and_linkedlist/list.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/list.cpp @@ -48,8 +48,8 @@ int main() { PrintUtil::printVector(list); /* 通过索引遍历列表 */ - size_t count = 0; - for (size_t i = 0; i < list.size(); i++) { + int count = 0; + for (int i = 0; i < list.size(); i++) { count++; } diff --git a/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp b/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp index c3f35ada..c2916cb4 100644 --- a/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp +++ b/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp @@ -22,7 +22,7 @@ vector randomNumbers(int n) { /* 查找数组 nums 中数字 1 所在索引 */ int findOne(vector& nums) { - for (size_t i = 0; i < nums.size(); i++) { + for (int i = 0; i < nums.size(); i++) { if (nums[i] == 1) return i; } diff --git a/codes/cpp/chapter_searching/hashing_search.cpp b/codes/cpp/chapter_searching/hashing_search.cpp index 57c9f5d1..ebc2fb01 100644 --- a/codes/cpp/chapter_searching/hashing_search.cpp +++ b/codes/cpp/chapter_searching/hashing_search.cpp @@ -33,7 +33,7 @@ int main() { vector nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; // 初始化哈希表 unordered_map map; - for (size_t i = 0; i < nums.size(); i++) { + for (int i = 0; i < nums.size(); i++) { map[nums[i]] = i; // key: 元素,value: 索引 } int index = hashingSearch(map, target); diff --git a/codes/cpp/chapter_searching/linear_search.cpp b/codes/cpp/chapter_searching/linear_search.cpp index 45a08ded..7b509276 100644 --- a/codes/cpp/chapter_searching/linear_search.cpp +++ b/codes/cpp/chapter_searching/linear_search.cpp @@ -9,7 +9,7 @@ /* 线性查找(数组) */ int linearSearch(vector& nums, int target) { // 遍历数组 - for (size_t i = 0; i < nums.size(); i++) { + for (int i = 0; i < nums.size(); i++) { // 找到目标元素,返回其索引 if (nums[i] == target) return i; diff --git a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp index 5694e702..ae22740d 100644 --- a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp @@ -68,7 +68,7 @@ public: vector toVector() { ListNode* node = front; vector res(size()); - for (size_t i = 0; i < res.size(); i++) { + for (int i = 0; i < res.size(); i++) { res[i] = node->val; node = node->next; } From 750d4f502d6cc71a539d35c13ec45898d45383fe Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Fri, 13 Jan 2023 16:18:05 +0800 Subject: [PATCH 06/13] Update linked_list.c --- codes/c/chapter_array_and_linkedlist/linked_list.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/c/chapter_array_and_linkedlist/linked_list.c b/codes/c/chapter_array_and_linkedlist/linked_list.c index 8228c48c..ea61c84c 100644 --- a/codes/c/chapter_array_and_linkedlist/linked_list.c +++ b/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -14,8 +14,8 @@ void insert(ListNode* n0, ListNode* P) { } /* 删除链表的结点 n0 之后的首个结点 */ -/* Keep Sample, 受 c 语言特性限制,removeNode 无法更改为 remove, - 详见 https://github.com/krahets/hello-algo/pull/244#discussion_r1067863888 */ +// 由于引入了 stdio.h ,此处无法使用 remove 关键词 +// 详见 https://github.com/krahets/hello-algo/pull/244#discussion_r1067863888 void removeNode(ListNode* n0) { if (!n0->next) return; From 7ab9fd68c89f4f2949deb5c85714ed34d64c1d40 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Fri, 13 Jan 2023 16:19:04 +0800 Subject: [PATCH 07/13] Update linked_list.c --- codes/c/chapter_array_and_linkedlist/linked_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codes/c/chapter_array_and_linkedlist/linked_list.c b/codes/c/chapter_array_and_linkedlist/linked_list.c index ea61c84c..a8de0873 100644 --- a/codes/c/chapter_array_and_linkedlist/linked_list.c +++ b/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -6,7 +6,7 @@ #include "../include/include.h" - /* 在链表的结点 n0 之后插入结点 P */ +/* 在链表的结点 n0 之后插入结点 P */ void insert(ListNode* n0, ListNode* P) { ListNode *n1 = n0->next; n0->next = P; From 32962fb7a14d143d36fece4bdc315af2eb50e4b2 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Thu, 12 Jan 2023 20:32:06 +0800 Subject: [PATCH 08/13] feat(heap): add go codes --- codes/go/chapter_heap/heap.go | 46 ++++++++++ codes/go/chapter_heap/heap_test.go | 90 +++++++++++++++++++ codes/go/chapter_heap/my_heap.go | 139 +++++++++++++++++++++++++++++ codes/go/pkg/print_utils.go | 23 +++-- 4 files changed, 291 insertions(+), 7 deletions(-) create mode 100644 codes/go/chapter_heap/heap.go create mode 100644 codes/go/chapter_heap/heap_test.go create mode 100644 codes/go/chapter_heap/my_heap.go diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go new file mode 100644 index 00000000..d28d2ba7 --- /dev/null +++ b/codes/go/chapter_heap/heap.go @@ -0,0 +1,46 @@ +// File: intHeap.go +// Created Time: 2023-01-12 +// Author: Reanon (793584285@qq.com) + +package chapter_heap + +// intHeap 是一个由整数组成的最大堆 +// 通过实现 heap.Interface 来构建堆 +type intHeap []any + +// Len sort.Interface 的方法 +func (h *intHeap) Len() int { + return len(*h) +} + +// Less sort.Interface 的方法 +func (h *intHeap) Less(i, j int) bool { + // 如果实现小顶堆,则需要调整为小于号 + return (*h)[i].(int) > (*h)[j].(int) +} + +// Swap sort.Interface 的方法 +func (h *intHeap) Swap(i, j int) { + (*h)[i], (*h)[j] = (*h)[j], (*h)[i] +} + +// Push heap.Interface 的方法 + +func (h *intHeap) Push(x any) { + // Push 和 Pop 使用 pointer receiver 作为参数 + // 因为它们不仅会对切片的内容进行调整,还会修改切片的长度。 + *h = append(*h, x.(int)) +} + +// Top 获取堆顶元素 +func (h *intHeap) Top() int { + return (*h)[0].(int) +} + +// Pop heap.Interface 的方法,实现弹出堆顶元素 +func (h *intHeap) Pop() any { + // 待出堆元素存放在最后 + last := (*h)[len(*h)-1] + *h = (*h)[:len(*h)-1] + return last +} diff --git a/codes/go/chapter_heap/heap_test.go b/codes/go/chapter_heap/heap_test.go new file mode 100644 index 00000000..db3844ef --- /dev/null +++ b/codes/go/chapter_heap/heap_test.go @@ -0,0 +1,90 @@ +// File: heap_test.go +// Created Time: 2023-01-12 +// Author: Reanon (793584285@qq.com) + +package chapter_heap + +import ( + "container/heap" + "fmt" + "testing" + + . "github.com/krahets/hello-algo/pkg" +) + +func testPush(h *intHeap, val int) { + // 调用 heap.Interface 的方法,来添加元素 + heap.Push(h, val) + fmt.Printf("\n元素 %d 入堆后 \n", val) + PrintHeap(*h) +} + +func testPop(h *intHeap) { + // 调用 heap.Interface 的方法,来移除元素 + val := heap.Pop(h) + fmt.Printf("\n堆顶元素 %d 出堆后 \n", val) + PrintHeap(*h) +} + +func TestHeap(t *testing.T) { + /* 初始化堆 */ + // 初始化大顶堆 + maxHeap := &intHeap{} + heap.Init(maxHeap) + /* 元素入堆 */ + testPush(maxHeap, 1) + testPush(maxHeap, 3) + testPush(maxHeap, 2) + testPush(maxHeap, 5) + testPush(maxHeap, 4) + + /* 获取堆顶元素 */ + top := maxHeap.Top() + fmt.Printf("堆顶元素为 %d\n", top) + + /* 堆顶元素出堆 */ + testPop(maxHeap) + testPop(maxHeap) + testPop(maxHeap) + testPop(maxHeap) + testPop(maxHeap) + + /* 获取堆大小 */ + size := len(*maxHeap) + fmt.Printf("堆元素数量为 %d\n", size) + + /* 判断堆是否为空 */ + isEmpty := len(*maxHeap) == 0 + fmt.Printf("堆是否为空 %t\n", isEmpty) +} + +func TestMyHeap(t *testing.T) { + /* 初始化堆 */ + // 初始化大顶堆 + maxHeap := newMaxHeap([]any{9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}) + fmt.Printf("输入数组并建堆后\n") + maxHeap.print() + + /* 获取堆顶元素 */ + peek := maxHeap.peek() + fmt.Printf("\n堆顶元素为 %d\n", peek) + + /* 元素入堆 */ + val := 7 + maxHeap.push(val) + fmt.Printf("\n元素 %d 入堆后\n", val) + maxHeap.print() + + /* 堆顶元素出堆 */ + peek = maxHeap.poll() + fmt.Printf("\n堆顶元素 %d 出堆后\n", peek) + maxHeap.print() + + /* 获取堆大小 */ + size := maxHeap.size() + fmt.Printf("\n堆元素数量为 %d\n", size) + + /* 判断堆是否为空 */ + isEmpty := maxHeap.isEmpty() + fmt.Printf("\n堆是否为空 %t\n", isEmpty) +} diff --git a/codes/go/chapter_heap/my_heap.go b/codes/go/chapter_heap/my_heap.go new file mode 100644 index 00000000..53e96121 --- /dev/null +++ b/codes/go/chapter_heap/my_heap.go @@ -0,0 +1,139 @@ +// File: my_heap.go +// Created Time: 2023-01-12 +// Author: Reanon (793584285@qq.com) + +package chapter_heap + +import ( + "fmt" + + . "github.com/krahets/hello-algo/pkg" +) + +type maxHeap struct { + // 使用切片而非数组,这样无需考虑扩容问题 + data []any +} + +/* 构造函数,建立空堆 */ +func newHeap() *maxHeap { + return &maxHeap{ + data: make([]any, 0), + } +} + +/* 构造函数,根据切片建堆 */ +func newMaxHeap(nums []any) *maxHeap { + // 所有元素入堆 + h := &maxHeap{data: nums} + for i := len(h.data) - 1; i >= 0; i-- { + // 堆化除叶结点以外的其他所有结点 + h.siftDown(i) + } + return h +} + +/* 获取左子结点索引 */ +func (h *maxHeap) left(i int) int { + return 2*i + 1 +} + +/* 获取右子结点索引 */ +func (h *maxHeap) right(i int) int { + return 2*i + 2 +} + +/* 获取父结点索引 */ +func (h *maxHeap) parent(i int) int { + // 向下整除 + return (i - 1) / 2 +} + +/* 交换元素 */ +func (h *maxHeap) swap(i, j int) { + h.data[i], h.data[j] = h.data[j], h.data[i] +} + +/* 获取堆大小 */ +func (h *maxHeap) size() int { + return len(h.data) +} + +/* 判断堆是否为空 */ +func (h *maxHeap) isEmpty() bool { + return len(h.data) == 0 +} + +/* 访问堆顶元素 */ +func (h *maxHeap) peek() any { + return h.data[0] +} + +/* 元素入堆 */ +func (h *maxHeap) push(val any) { + // 添加结点 + h.data = append(h.data, val) + // 从底至顶堆化 + h.siftUp(len(h.data) - 1) +} + +/* 元素出堆 */ +func (h *maxHeap) poll() any { + // 判空处理 + if h.isEmpty() { + fmt.Println("error") + } + // 交换根结点与最右叶结点(即交换首元素与尾元素) + h.swap(0, h.size()-1) + // 删除结点 + val := h.data[len(h.data)-1] + h.data = h.data[:len(h.data)-1] + // 从顶至底堆化 + h.siftDown(0) + + // 返回堆顶元素 + return val +} + +/* 从结点 i 开始,从顶至底堆化 */ +func (h *maxHeap) siftDown(i int) { + for true { + // 判断结点 i, l, r 中值最大的结点,记为 max + l, r, max := h.left(i), h.right(i), i + if l < h.size() && h.data[l].(int) > h.data[max].(int) { + max = l + } + if r < h.size() && h.data[r].(int) > h.data[max].(int) { + max = r + } + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if max == i { + break + } + // 交换两结点 + h.swap(i, max) + // 循环向下堆化 + i = max + } +} + +/* 从结点 i 开始,从底至顶堆化 */ +func (h *maxHeap) siftUp(i int) { + for true { + // 获取结点 i 的父结点 + p := h.parent(i) + // 当“越过根结点”或“结点无需修复”时,结束堆化 + if p < 0 || h.data[i].(int) <= h.data[p].(int) { + break + } + // 交换两结点 + h.swap(i, p) + // 循环向上堆化 + i = p + } +} + +/* 打印堆(二叉树) */ +func (h *maxHeap) print() { + PrintHeap(h.data) +} diff --git a/codes/go/pkg/print_utils.go b/codes/go/pkg/print_utils.go index 575ab6b9..d65ebba1 100644 --- a/codes/go/pkg/print_utils.go +++ b/codes/go/pkg/print_utils.go @@ -29,6 +29,22 @@ func PrintList(list *list.List) { fmt.Print(e.Value, "]\n") } +// PrintMap Print a hash map +func PrintMap[K comparable, V any](m map[K]V) { + for key, value := range m { + fmt.Println(key, "->", value) + } +} + +// PrintHeap Print a heap +func PrintHeap(h []any) { + fmt.Printf("堆的数组表示:") + fmt.Printf("%v", h) + fmt.Printf("\n堆的树状表示:\n") + root := ArrToTree(h) + PrintTree(root) +} + // PrintLinkedList Print a linked list func PrintLinkedList(node *ListNode) { if node == nil { @@ -97,10 +113,3 @@ func showTrunk(t *trunk) { showTrunk(t.prev) fmt.Print(t.str) } - -// PrintMap Print a hash map -func PrintMap[K comparable, V any](m map[K]V) { - for key, value := range m { - fmt.Println(key, "->", value) - } -} From 79d51e36913eac600ace5afc0b4b6fe9e52c49ef Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Thu, 12 Jan 2023 20:47:11 +0800 Subject: [PATCH 09/13] fix(heap): fix go code --- codes/go/chapter_heap/heap.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go index d28d2ba7..a2c2eefe 100644 --- a/codes/go/chapter_heap/heap.go +++ b/codes/go/chapter_heap/heap.go @@ -4,9 +4,9 @@ package chapter_heap -// intHeap 是一个由整数组成的最大堆 +// intHeap 是一个由整数组成的堆 // 通过实现 heap.Interface 来构建堆 -type intHeap []any +type intHeap []int // Len sort.Interface 的方法 func (h *intHeap) Len() int { @@ -16,7 +16,7 @@ func (h *intHeap) Len() int { // Less sort.Interface 的方法 func (h *intHeap) Less(i, j int) bool { // 如果实现小顶堆,则需要调整为小于号 - return (*h)[i].(int) > (*h)[j].(int) + return (*h)[i] > (*h)[j] } // Swap sort.Interface 的方法 @@ -34,11 +34,11 @@ func (h *intHeap) Push(x any) { // Top 获取堆顶元素 func (h *intHeap) Top() int { - return (*h)[0].(int) + return (*h)[0] } // Pop heap.Interface 的方法,实现弹出堆顶元素 -func (h *intHeap) Pop() any { +func (h *intHeap) Pop() int { // 待出堆元素存放在最后 last := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] From 8117a1d47d0e130003126959fe5c17b395a36427 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Thu, 12 Jan 2023 20:58:39 +0800 Subject: [PATCH 10/13] fix(heap): fix go code --- codes/go/chapter_heap/heap.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go index a2c2eefe..4a5b0c43 100644 --- a/codes/go/chapter_heap/heap.go +++ b/codes/go/chapter_heap/heap.go @@ -6,7 +6,7 @@ package chapter_heap // intHeap 是一个由整数组成的堆 // 通过实现 heap.Interface 来构建堆 -type intHeap []int +type intHeap []any // Len sort.Interface 的方法 func (h *intHeap) Len() int { @@ -16,7 +16,7 @@ func (h *intHeap) Len() int { // Less sort.Interface 的方法 func (h *intHeap) Less(i, j int) bool { // 如果实现小顶堆,则需要调整为小于号 - return (*h)[i] > (*h)[j] + return (*h)[i].(int) > (*h)[j].(int) } // Swap sort.Interface 的方法 @@ -33,12 +33,12 @@ func (h *intHeap) Push(x any) { } // Top 获取堆顶元素 -func (h *intHeap) Top() int { +func (h *intHeap) Top() any { return (*h)[0] } // Pop heap.Interface 的方法,实现弹出堆顶元素 -func (h *intHeap) Pop() int { +func (h *intHeap) Pop() any { // 待出堆元素存放在最后 last := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] From 264a2ab6bca636b299d045d61be5d75f626c7517 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Fri, 13 Jan 2023 10:25:25 +0800 Subject: [PATCH 11/13] docs(heap): add go codes --- codes/go/chapter_heap/heap.go | 35 ++++---- codes/go/chapter_heap/my_heap.go | 32 +++---- docs/chapter_heap/heap.md | 139 ++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 35 deletions(-) diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go index 4a5b0c43..5f846ced 100644 --- a/codes/go/chapter_heap/heap.go +++ b/codes/go/chapter_heap/heap.go @@ -4,10 +4,25 @@ package chapter_heap -// intHeap 是一个由整数组成的堆 -// 通过实现 heap.Interface 来构建堆 +// Go 语言中可以通过实现 heap.Interface 来构建整数大顶堆 +// 实现 heap.Interface 需要同时实现 sort.Interface type intHeap []any +// Push heap.Interface 的方法,实现推入元素到堆 +func (h *intHeap) Push(x any) { + // Push 和 Pop 使用 pointer receiver 作为参数 + // 因为它们不仅会对切片的内容进行调整,还会修改切片的长度。 + *h = append(*h, x.(int)) +} + +// Pop heap.Interface 的方法,实现弹出堆顶元素 +func (h *intHeap) Pop() any { + // 待出堆元素存放在最后 + last := (*h)[len(*h)-1] + *h = (*h)[:len(*h)-1] + return last +} + // Len sort.Interface 的方法 func (h *intHeap) Len() int { return len(*h) @@ -24,23 +39,7 @@ func (h *intHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } -// Push heap.Interface 的方法 - -func (h *intHeap) Push(x any) { - // Push 和 Pop 使用 pointer receiver 作为参数 - // 因为它们不仅会对切片的内容进行调整,还会修改切片的长度。 - *h = append(*h, x.(int)) -} - // Top 获取堆顶元素 func (h *intHeap) Top() any { return (*h)[0] } - -// Pop heap.Interface 的方法,实现弹出堆顶元素 -func (h *intHeap) Pop() any { - // 待出堆元素存放在最后 - last := (*h)[len(*h)-1] - *h = (*h)[:len(*h)-1] - return last -} diff --git a/codes/go/chapter_heap/my_heap.go b/codes/go/chapter_heap/my_heap.go index 53e96121..0b3d0a3b 100644 --- a/codes/go/chapter_heap/my_heap.go +++ b/codes/go/chapter_heap/my_heap.go @@ -77,6 +77,22 @@ func (h *maxHeap) push(val any) { h.siftUp(len(h.data) - 1) } +/* 从结点 i 开始,从底至顶堆化 */ +func (h *maxHeap) siftUp(i int) { + for true { + // 获取结点 i 的父结点 + p := h.parent(i) + // 当“越过根结点”或“结点无需修复”时,结束堆化 + if p < 0 || h.data[i].(int) <= h.data[p].(int) { + break + } + // 交换两结点 + h.swap(i, p) + // 循环向上堆化 + i = p + } +} + /* 元素出堆 */ func (h *maxHeap) poll() any { // 判空处理 @@ -117,22 +133,6 @@ func (h *maxHeap) siftDown(i int) { } } -/* 从结点 i 开始,从底至顶堆化 */ -func (h *maxHeap) siftUp(i int) { - for true { - // 获取结点 i 的父结点 - p := h.parent(i) - // 当“越过根结点”或“结点无需修复”时,结束堆化 - if p < 0 || h.data[i].(int) <= h.data[p].(int) { - break - } - // 交换两结点 - h.swap(i, p) - // 循环向上堆化 - i = p - } -} - /* 打印堆(二叉树) */ func (h *maxHeap) print() { PrintHeap(h.data) diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 73f425ff..91f7670b 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -97,7 +97,45 @@ comments: true === "Go" ```go title="heap.go" + // Go 语言中可以通过实现 heap.Interface 来构建整数大顶堆 + // 实现 heap.Interface 需要同时实现 sort.Interface + type intHeap []any + // Push heap.Interface 的方法,实现推入元素到堆 + func (h *intHeap) Push(x any) { + // Push 和 Pop 使用 pointer receiver 作为参数 + // 因为它们不仅会对切片的内容进行调整,还会修改切片的长度。 + *h = append(*h, x.(int)) + } + + // Pop heap.Interface 的方法,实现弹出堆顶元素 + func (h *intHeap) Pop() any { + // 待出堆元素存放在最后 + last := (*h)[len(*h)-1] + *h = (*h)[:len(*h)-1] + return last + } + + // Len sort.Interface 的方法 + func (h *intHeap) Len() int { + return len(*h) + } + + // Less sort.Interface 的方法 + func (h *intHeap) Less(i, j int) bool { + // 如果实现小顶堆,则需要调整为小于号 + return (*h)[i].(int) > (*h)[j].(int) + } + + // Swap sort.Interface 的方法 + func (h *intHeap) Swap(i, j int) { + (*h)[i], (*h)[j] = (*h)[j], (*h)[i] + } + + // Top 获取堆顶元素 + func (h *intHeap) Top() any { + return (*h)[0] + } ``` === "JavaScript" @@ -188,7 +226,33 @@ comments: true === "Go" ```go title="my_heap.go" + type maxHeap struct { + // 使用切片而非数组,这样无需考虑扩容问题 + data []any + } + /* 构造函数,建立空堆 */ + func newHeap() *maxHeap { + return &maxHeap{ + data: make([]any, 0), + } + } + + /* 获取左子结点索引 */ + func (h *maxHeap) left(i int) int { + return 2*i + 1 + } + + /* 获取右子结点索引 */ + func (h *maxHeap) right(i int) int { + return 2*i + 2 + } + + /* 获取父结点索引 */ + func (h *maxHeap) parent(i int) int { + // 向下整除 + return (i - 1) / 2 + } ``` === "JavaScript" @@ -249,6 +313,10 @@ comments: true === "Go" ```go title="my_heap.go" + /* 访问堆顶元素 */ + func (h *maxHeap) peek() any { + return h.data[0] + } ``` @@ -350,7 +418,29 @@ comments: true === "Go" ```go title="my_heap.go" + /* 元素入堆 */ + func (h *maxHeap) push(val any) { + // 添加结点 + h.data = append(h.data, val) + // 从底至顶堆化 + h.siftUp(len(h.data) - 1) + } + /* 从结点 i 开始,从底至顶堆化 */ + func (h *maxHeap) siftUp(i int) { + for true { + // 获取结点 i 的父结点 + p := h.parent(i) + // 当“越过根结点”或“结点无需修复”时,结束堆化 + if p < 0 || h.data[i].(int) <= h.data[p].(int) { + break + } + // 交换两结点 + h.swap(i, p) + // 循环向上堆化 + i = p + } + } ``` === "JavaScript" @@ -477,7 +567,45 @@ comments: true === "Go" ```go title="my_heap.go" + /* 元素出堆 */ + func (h *maxHeap) poll() any { + // 判空处理 + if h.isEmpty() { + fmt.Println("error") + } + // 交换根结点与最右叶结点(即交换首元素与尾元素) + h.swap(0, h.size()-1) + // 删除结点 + val := h.data[len(h.data)-1] + h.data = h.data[:len(h.data)-1] + // 从顶至底堆化 + h.siftDown(0) + // 返回堆顶元素 + return val + } + + /* 从结点 i 开始,从顶至底堆化 */ + func (h *maxHeap) siftDown(i int) { + for true { + // 判断结点 i, l, r 中值最大的结点,记为 max + l, r, max := h.left(i), h.right(i), i + if l < h.size() && h.data[l].(int) > h.data[max].(int) { + max = l + } + if r < h.size() && h.data[r].(int) > h.data[max].(int) { + max = r + } + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if max == i { + break + } + // 交换两结点 + h.swap(i, max) + // 循环向下堆化 + i = max + } + } ``` === "JavaScript" @@ -545,7 +673,16 @@ comments: true === "Go" ```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 + } ``` === "JavaScript" From 3dcdd1c72dafdae44ab5e7bfdbc06918a3adff93 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Fri, 13 Jan 2023 17:37:24 +0800 Subject: [PATCH 12/13] fix(heap): add go codes --- codes/go/chapter_heap/heap.go | 40 +++++++++++++++++++++++++++++++++++ docs/chapter_heap/heap.md | 36 ++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go index 5f846ced..886ec20e 100644 --- a/codes/go/chapter_heap/heap.go +++ b/codes/go/chapter_heap/heap.go @@ -4,6 +4,11 @@ package chapter_heap +import ( + "container/heap" + "fmt" +) + // Go 语言中可以通过实现 heap.Interface 来构建整数大顶堆 // 实现 heap.Interface 需要同时实现 sort.Interface type intHeap []any @@ -43,3 +48,38 @@ func (h *intHeap) Swap(i, j int) { func (h *intHeap) Top() any { return (*h)[0] } + +/* Driver Code */ +func main() { + /* 初始化堆 */ + // 初始化大顶堆 + maxHeap := &intHeap{} + heap.Init(maxHeap) + /* 元素入堆 */ + // 调用 heap.Interface 的方法,来添加元素 + heap.Push(maxHeap, 1) + heap.Push(maxHeap, 3) + heap.Push(maxHeap, 2) + heap.Push(maxHeap, 4) + heap.Push(maxHeap, 5) + + /* 获取堆顶元素 */ + top := maxHeap.Top() + fmt.Printf("堆顶元素为 %d\n", top) + + /* 堆顶元素出堆 */ + // 调用 heap.Interface 的方法,来移除元素 + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + + /* 获取堆大小 */ + size := len(*maxHeap) + fmt.Printf("堆元素数量为 %d\n", size) + + /* 判断堆是否为空 */ + isEmpty := len(*maxHeap) == 0 + fmt.Printf("堆是否为空 %t\n", isEmpty) +} diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 91f7670b..92499325 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -136,6 +136,41 @@ comments: true func (h *intHeap) Top() any { return (*h)[0] } + + /* Driver Code */ + func TestHeap(t *testing.T) { + /* 初始化堆 */ + // 初始化大顶堆 + maxHeap := &intHeap{} + heap.Init(maxHeap) + /* 元素入堆 */ + // 调用 heap.Interface 的方法,来添加元素 + heap.Push(maxHeap, 1) + heap.Push(maxHeap, 3) + heap.Push(maxHeap, 2) + heap.Push(maxHeap, 4) + heap.Push(maxHeap, 5) + + /* 获取堆顶元素 */ + top := maxHeap.Top() + fmt.Printf("堆顶元素为 %d\n", top) + + /* 堆顶元素出堆 */ + // 调用 heap.Interface 的方法,来移除元素 + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + heap.Pop(maxHeap) + + /* 获取堆大小 */ + size := len(*maxHeap) + fmt.Printf("堆元素数量为 %d\n", size) + + /* 判断堆是否为空 */ + isEmpty := len(*maxHeap) == 0 + fmt.Printf("堆是否为空 %t\n", isEmpty) + } ``` === "JavaScript" @@ -317,7 +352,6 @@ comments: true func (h *maxHeap) peek() any { return h.data[0] } - ``` === "JavaScript" From ec28b4ce7a3d4580422c58275329b3cd192b4bb1 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Fri, 13 Jan 2023 17:40:20 +0800 Subject: [PATCH 13/13] fix(heap): add go codes --- codes/go/chapter_heap/heap.go | 40 ----------------------------------- docs/chapter_heap/heap.md | 2 +- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/codes/go/chapter_heap/heap.go b/codes/go/chapter_heap/heap.go index 886ec20e..5f846ced 100644 --- a/codes/go/chapter_heap/heap.go +++ b/codes/go/chapter_heap/heap.go @@ -4,11 +4,6 @@ package chapter_heap -import ( - "container/heap" - "fmt" -) - // Go 语言中可以通过实现 heap.Interface 来构建整数大顶堆 // 实现 heap.Interface 需要同时实现 sort.Interface type intHeap []any @@ -48,38 +43,3 @@ func (h *intHeap) Swap(i, j int) { func (h *intHeap) Top() any { return (*h)[0] } - -/* Driver Code */ -func main() { - /* 初始化堆 */ - // 初始化大顶堆 - maxHeap := &intHeap{} - heap.Init(maxHeap) - /* 元素入堆 */ - // 调用 heap.Interface 的方法,来添加元素 - heap.Push(maxHeap, 1) - heap.Push(maxHeap, 3) - heap.Push(maxHeap, 2) - heap.Push(maxHeap, 4) - heap.Push(maxHeap, 5) - - /* 获取堆顶元素 */ - top := maxHeap.Top() - fmt.Printf("堆顶元素为 %d\n", top) - - /* 堆顶元素出堆 */ - // 调用 heap.Interface 的方法,来移除元素 - heap.Pop(maxHeap) - heap.Pop(maxHeap) - heap.Pop(maxHeap) - heap.Pop(maxHeap) - heap.Pop(maxHeap) - - /* 获取堆大小 */ - size := len(*maxHeap) - fmt.Printf("堆元素数量为 %d\n", size) - - /* 判断堆是否为空 */ - isEmpty := len(*maxHeap) == 0 - fmt.Printf("堆是否为空 %t\n", isEmpty) -} diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 92499325..15d22e78 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -262,7 +262,7 @@ comments: true ```go title="my_heap.go" type maxHeap struct { - // 使用切片而非数组,这样无需考虑扩容问题 + // 使用切片而非数组,这样无需考虑扩容问题 data []any }