Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add top_k.c and refactor top_k.js #889

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions codes/c/chapter_heap/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
add_executable(my_heap my_heap.c)

add_executable(my_heap_test my_heap_test.c)
add_executable(top_k top_k.c)
40 changes: 6 additions & 34 deletions codes/c/chapter_heap/my_heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ MaxHeap *newMaxHeap(int nums[], int size) {
return h;
}

/* 析构函数 */
void freeMaxHeap(MaxHeap *h) {
// 释放内存
free(h);
}

/* 获取左子节点索引 */
int left(MaxHeap *h, int i) {
return 2 * i + 1;
Expand Down Expand Up @@ -144,37 +150,3 @@ void siftUp(MaxHeap *h, int i) {
i = p;
}
}

/* Driver Code */
int main() {
/* 初始化堆 */
// 初始化大顶堆
int nums[] = {9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2};
MaxHeap *heap = newMaxHeap(nums, sizeof(nums) / sizeof(int));
printf("输入数组并建堆后\n");
printHeap(heap->data, heap->size);

/* 获取堆顶元素 */
printf("\n堆顶元素为 %d\n", peek(heap));

/* 元素入堆 */
push(heap, 7);
printf("\n元素 7 入堆后\n");
printHeap(heap->data, heap->size);

/* 堆顶元素出堆 */
int top = pop(heap);
printf("\n堆顶元素 %d 出堆后\n", top);
printHeap(heap->data, heap->size);

/* 获取堆大小 */
printf("\n堆元素数量为 %d\n", size(heap));

/* 判断堆是否为空 */
printf("\n堆是否为空 %d\n", isEmpty(heap));

// 释放内存
free(heap);

return 0;
}
41 changes: 41 additions & 0 deletions codes/c/chapter_heap/my_heap_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* File: my_heap_test.c
* Created Time: 2023-01-15
* Author: Reanon (793584285@qq.com)
*/

#include "my_heap.c"

/* Driver Code */
int main() {
/* 初始化堆 */
// 初始化大顶堆
int nums[] = {9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2};
MaxHeap *heap = newMaxHeap(nums, sizeof(nums) / sizeof(int));
printf("输入数组并建堆后\n");
printHeap(heap->data, heap->size);

/* 获取堆顶元素 */
printf("\n堆顶元素为 %d\n", peek(heap));

/* 元素入堆 */
push(heap, 7);
printf("\n元素 7 入堆后\n");
printHeap(heap->data, heap->size);

/* 堆顶元素出堆 */
int top = pop(heap);
printf("\n堆顶元素 %d 出堆后\n", top);
printHeap(heap->data, heap->size);

/* 获取堆大小 */
printf("\n堆元素数量为 %d\n", size(heap));

/* 判断堆是否为空 */
printf("\n堆是否为空 %d\n", isEmpty(heap));

// 释放内存
freeMaxHeap(heap);

return 0;
}
73 changes: 73 additions & 0 deletions codes/c/chapter_heap/top_k.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* File: top_k.c
* Created Time: 2023-10-26
* Author: Krahets (krahets163.com)
*/

#include "my_heap.c"

/* 元素入堆 */
void pushMinHeap(MaxHeap *maxHeap, int val) {
// 元素取反
push(maxHeap, -val);
}

/* 元素出堆 */
int popMinHeap(MaxHeap *maxHeap) {
// 元素取反
return -pop(maxHeap);
}

/* 访问堆顶元素 */
int peekMinHeap(MaxHeap *maxHeap) {
// 元素取反
return -peek(maxHeap);
}

/* 取出堆中元素 */
int *getMinHeap(MaxHeap *maxHeap) {
// 将堆中所有元素取反并存入 res 数组
int *res = (int *)malloc(maxHeap->size * sizeof(int));
for (int i = 0; i < maxHeap->size; i++) {
res[i] = -maxHeap->data[i];
}
return res;
}

// 基于堆查找数组中最大的 k 个元素的函数
int *topKHeap(int *nums, int sizeNums, int k) {
// 初始化小顶堆
// 请注意:我们将堆中所有元素取反,从而用大顶堆来模拟小顶堆
int empty[0];
MaxHeap *maxHeap = newMaxHeap(empty, 0);
// 将数组的前 k 个元素入堆
for (int i = 0; i < k; i++) {
pushMinHeap(maxHeap, nums[i]);
}
// 从第 k+1 个元素开始,保持堆的长度为 k
for (int i = k; i < sizeNums; i++) {
// 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆
if (nums[i] > peekMinHeap(maxHeap)) {
popMinHeap(maxHeap);
pushMinHeap(maxHeap, nums[i]);
}
}
int *res = getMinHeap(maxHeap);
// 释放内存
freeMaxHeap(maxHeap);
return res;
}

/* Driver Code */
int main() {
int nums[] = {1, 7, 6, 3, 2};
int k = 3;
int sizeNums = sizeof(nums) / sizeof(nums[0]);

int *res = topKHeap(nums, sizeNums, k);
printf("最大的 %d 个元素为: ", k);
printArray(res, k);

free(res);
return 0;
}
1 change: 1 addition & 0 deletions codes/cpp/chapter_heap/top_k.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* 基于堆查找数组中最大的 k 个元素 */
priority_queue<int, vector<int>, greater<int>> topKHeap(vector<int> &nums, int k) {
// 初始化小顶堆
priority_queue<int, vector<int>, greater<int>> heap;
// 将数组的前 k 个元素入堆
for (int i = 0; i < k; i++) {
Expand Down
1 change: 1 addition & 0 deletions codes/csharp/chapter_heap/top_k.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace hello_algo.chapter_heap;
public class top_k {
/* 基于堆查找数组中最大的 k 个元素 */
public static PriorityQueue<int, int> TopKHeap(int[] nums, int k) {
// 初始化小顶堆
PriorityQueue<int, int> heap = new();
// 将数组的前 k 个元素入堆
for (int i = 0; i < k; i++) {
Expand Down
2 changes: 1 addition & 1 deletion codes/dart/chapter_heap/top_k.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '../utils/print_util.dart';

/* 基于堆查找数组中最大的 k 个元素 */
MinHeap topKHeap(List<int> nums, int k) {
// 将数组的前 k 个元素入堆
// 初始化小顶堆,将数组的前 k 个元素入堆
MinHeap heap = MinHeap(nums.sublist(0, k));
// 从第 k+1 个元素开始,保持堆的长度为 k
for (int i = k; i < nums.length; i++) {
Expand Down
1 change: 1 addition & 0 deletions codes/go/chapter_heap/top_k.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (h *minHeap) Top() any {

/* 基于堆查找数组中最大的 k 个元素 */
func topKHeap(nums []int, k int) *minHeap {
// 初始化小顶堆
h := &minHeap{}
heap.Init(h)
// 将数组的前 k 个元素入堆
Expand Down
1 change: 1 addition & 0 deletions codes/java/chapter_heap/top_k.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
public class top_k {
/* 基于堆查找数组中最大的 k 个元素 */
static Queue<Integer> topKHeap(int[] nums, int k) {
// 初始化小顶堆
Queue<Integer> heap = new PriorityQueue<Integer>();
// 将数组的前 k 个元素入堆
for (int i = 0; i < k; i++) {
Expand Down
56 changes: 29 additions & 27 deletions codes/javascript/chapter_heap/my_heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,33 +123,35 @@ class MaxHeap {
}

/* Driver Code */
/* 初始化大顶堆 */
const maxHeap = new MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]);
console.log('\n输入列表并建堆后');
maxHeap.print();

/* 获取堆顶元素 */
let peek = maxHeap.peek();
console.log(`\n堆顶元素为 ${peek}`);

/* 元素入堆 */
let val = 7;
maxHeap.push(val);
console.log(`\n元素 ${val} 入堆后`);
maxHeap.print();

/* 堆顶元素出堆 */
peek = maxHeap.pop();
console.log(`\n堆顶元素 ${peek} 出堆后`);
maxHeap.print();

/* 获取堆大小 */
let size = maxHeap.size();
console.log(`\n堆元素数量为 ${size}`);

/* 判断堆是否为空 */
let isEmpty = maxHeap.isEmpty();
console.log(`\n堆是否为空 ${isEmpty}`);
if (require.main === module) {
/* 初始化大顶堆 */
const maxHeap = new MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]);
console.log('\n输入列表并建堆后');
maxHeap.print();

/* 获取堆顶元素 */
let peek = maxHeap.peek();
console.log(`\n堆顶元素为 ${peek}`);

/* 元素入堆 */
let val = 7;
maxHeap.push(val);
console.log(`\n元素 ${val} 入堆后`);
maxHeap.print();

/* 堆顶元素出堆 */
peek = maxHeap.pop();
console.log(`\n堆顶元素 ${peek} 出堆后`);
maxHeap.print();

/* 获取堆大小 */
let size = maxHeap.size();
console.log(`\n堆元素数量为 ${size}`);

/* 判断堆是否为空 */
let isEmpty = maxHeap.isEmpty();
console.log(`\n堆是否为空 ${isEmpty}`);
}

module.exports = {
MaxHeap,
Expand Down
50 changes: 37 additions & 13 deletions codes/javascript/chapter_heap/top_k.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,49 @@

const { MaxHeap } = require('./my_heap');

/* 元素入堆 */
function pushMinHeap(maxHeap, val) {
// 元素取反
maxHeap.push(-val);
}

/* 元素出堆 */
function popMinHeap(maxHeap) {
// 元素取反
return -maxHeap.pop();
}

/* 访问堆顶元素 */
function peekMinHeap(maxHeap) {
// 元素取反
return -maxHeap.peek();
}

/* 取出堆中元素 */
function getMinHeap(maxHeap) {
// 元素取反
return maxHeap.getMaxHeap().map((num) => -num);
}

/* 基于堆查找数组中最大的 k 个元素 */
function topKHeap(nums, k) {
// 使用大顶堆 MaxHeap ,对数组 nums 取相反数
const invertedNums = nums.map((num) => -num);
// 初始化小顶堆
// 请注意:我们将堆中所有元素取反,从而用大顶堆来模拟小顶堆
const maxHeap = new MaxHeap([]);
// 将数组的前 k 个元素入堆
const heap = new MaxHeap(invertedNums.slice(0, k));
for (let i = 0; i < k; i++) {
pushMinHeap(maxHeap, nums[i]);
}
// 从第 k+1 个元素开始,保持堆的长度为 k
for (let i = k; i < invertedNums.length; i++) {
// 若当前元素小于堆顶元素,则将堆顶元素出堆、当前元素入堆
if (invertedNums[i] < heap.peek()) {
heap.pop();
heap.push(invertedNums[i]);
for (let i = k; i < nums.length; i++) {
// 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆
if (nums[i] > peekMinHeap(maxHeap)) {
popMinHeap(maxHeap);
pushMinHeap(maxHeap, nums[i]);
}
}
// 取出堆中元素
const maxHeap = heap.getMaxHeap();
// 对堆中元素取相反数
const invertedMaxHeap = maxHeap.map((num) => -num);
return invertedMaxHeap;
// 返回堆中元素
return getMinHeap(maxHeap);
}

/* Driver Code */
Expand Down
1 change: 1 addition & 0 deletions codes/python/chapter_heap/top_k.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

def top_k_heap(nums: list[int], k: int) -> list[int]:
"""基于堆查找数组中最大的 k 个元素"""
# 初始化小顶堆
heap = []
# 将数组的前 k 个元素入堆
for i in range(k):
Expand Down
2 changes: 1 addition & 1 deletion codes/rust/chapter_heap/top_k.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::collections::BinaryHeap;

/* 基于堆查找数组中最大的 k 个元素 */
fn top_k_heap(nums: Vec<i32>, k: usize) -> BinaryHeap<Reverse<i32>> {
// Rust 的 BinaryHeap 是大顶堆,使用 Reverse 将元素大小反转
// BinaryHeap 是大顶堆,使用 Reverse 将元素取反,从而实现小顶堆
let mut heap = BinaryHeap::<Reverse<i32>>::new();
// 将数组的前 k 个元素入堆
for &num in nums.iter().take(k) {
Expand Down
Loading