mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-10 11:00:59 +00:00
Revisit the English version (#1835)
* Review the English version using Claude-4.5. * Update mkdocs.yml * Align the section titles. * Bug fixes
This commit is contained in:
@@ -1,27 +1,27 @@
|
||||
# Heap construction operation
|
||||
|
||||
In some cases, we want to build a heap using all elements of a list, and this process is known as "heap construction operation."
|
||||
In some cases, we want to build a heap using all elements of a list, and this process is called "heap construction operation."
|
||||
|
||||
## Implementing with heap insertion operation
|
||||
## Implementing with element insertion
|
||||
|
||||
First, we create an empty heap and then iterate through the list, performing the "heap insertion operation" on each element in turn. This means adding the element to the end of the heap and then "heapifying" it from bottom to top.
|
||||
We first create an empty heap, then iterate through the list, performing the "element insertion operation" on each element in sequence. This means adding the element to the bottom of the heap and then performing "bottom-to-top" heapify on that element.
|
||||
|
||||
Each time an element is added to the heap, the length of the heap increases by one. Since nodes are added to the binary tree from top to bottom, the heap is constructed "from top to bottom."
|
||||
Each time an element is inserted into the heap, the heap's length increases by one. Since nodes are added to the binary tree sequentially from top to bottom, the heap is constructed "from top to bottom."
|
||||
|
||||
Let the number of elements be $n$, and each element's insertion operation takes $O(\log{n})$ time, thus the time complexity of this heap construction method is $O(n \log n)$.
|
||||
Given $n$ elements, each element's insertion operation takes $O(\log{n})$ time, so the time complexity of this heap construction method is $O(n \log n)$.
|
||||
|
||||
## Implementing by heapifying through traversal
|
||||
## Implementing through heapify traversal
|
||||
|
||||
In fact, we can implement a more efficient method of heap construction in two steps.
|
||||
In fact, we can implement a more efficient heap construction method in two steps.
|
||||
|
||||
1. Add all elements of the list as they are into the heap, at this point the properties of the heap are not yet satisfied.
|
||||
2. Traverse the heap in reverse order (reverse of level-order traversal), and perform "top to bottom heapify" on each non-leaf node.
|
||||
1. Add all elements of the list as-is to the heap, at which point the heap property is not yet satisfied.
|
||||
2. Traverse the heap in reverse order (reverse of level-order traversal), performing "top-to-bottom heapify" on each non-leaf node in sequence.
|
||||
|
||||
**After heapifying a node, the subtree with that node as the root becomes a valid sub-heap**. Since the traversal is in reverse order, the heap is built "from bottom to top."
|
||||
**After heapifying a node, the subtree rooted at that node becomes a valid sub-heap**. Since we traverse in reverse order, the heap is constructed "from bottom to top."
|
||||
|
||||
The reason for choosing reverse traversal is that it ensures the subtree below the current node is already a valid sub-heap, making the heapification of the current node effective.
|
||||
The reason for choosing reverse order traversal is that it ensures the subtree below the current node is already a valid sub-heap, making the heapification of the current node effective.
|
||||
|
||||
It's worth mentioning that **since leaf nodes have no children, they naturally form valid sub-heaps and do not need to be heapified**. As shown in the following code, the last non-leaf node is the parent of the last node; we start from it and traverse in reverse order to perform heapification:
|
||||
It's worth noting that **since leaf nodes have no children, they are naturally valid sub-heaps and do not require heapification**. As shown in the code below, the last non-leaf node is the parent of the last node; we start from it and traverse in reverse order to perform heapification:
|
||||
|
||||
```src
|
||||
[file]{my_heap}-[class]{max_heap}-[func]{__init__}
|
||||
@@ -29,39 +29,39 @@ It's worth mentioning that **since leaf nodes have no children, they naturally f
|
||||
|
||||
## Complexity analysis
|
||||
|
||||
Next, let's attempt to calculate the time complexity of this second method of heap construction.
|
||||
Next, let's attempt to derive the time complexity of this second heap construction method.
|
||||
|
||||
- Assuming the number of nodes in the complete binary tree is $n$, then the number of leaf nodes is $(n + 1) / 2$, where $/$ is integer division. Therefore, the number of nodes that need to be heapified is $(n - 1) / 2$.
|
||||
- In the process of "top to bottom heapification," each node is heapified to the leaf nodes at most, so the maximum number of iterations is the height of the binary tree $\log n$.
|
||||
- Assuming the complete binary tree has $n$ nodes, then the number of leaf nodes is $(n + 1) / 2$, where $/$ is floor division. Therefore, the number of nodes that need heapification is $(n - 1) / 2$.
|
||||
- In the top-to-bottom heapify process, each node is heapified at most to the leaf nodes, so the maximum number of iterations is the binary tree height $\log n$.
|
||||
|
||||
Multiplying the two, we get the time complexity of the heap construction process as $O(n \log n)$. **But this estimate is not accurate, because it does not take into account the nature of the binary tree having far more nodes at the lower levels than at the top.**
|
||||
Multiplying these two together, we get a time complexity of $O(n \log n)$ for the heap construction process. **However, this estimate is not accurate because it doesn't account for the property that binary trees have far more nodes at lower levels than at upper levels**.
|
||||
|
||||
Let's perform a more accurate calculation. To simplify the calculation, assume a "perfect binary tree" with $n$ nodes and height $h$; this assumption does not affect the correctness of the result.
|
||||
Let's perform a more accurate calculation. To reduce calculation difficulty, assume a "perfect binary tree" with $n$ nodes and height $h$; this assumption does not affect the correctness of the result.
|
||||
|
||||

|
||||

|
||||
|
||||
As shown in the figure above, the maximum number of iterations for a node "to be heapified from top to bottom" is equal to the distance from that node to the leaf nodes, which is precisely "node height." Therefore, we can sum the "number of nodes $\times$ node height" at each level, **to get the total number of heapification iterations for all nodes**.
|
||||
As shown in the figure above, the maximum number of iterations for a node's "top-to-bottom heapify" equals the distance from that node to the leaf nodes, which is precisely the "node height." Therefore, we can sum the "number of nodes $\times$ node height" at each level to **obtain the total number of heapify iterations for all nodes**.
|
||||
|
||||
$$
|
||||
T(h) = 2^0h + 2^1(h-1) + 2^2(h-2) + \dots + 2^{(h-1)}\times1
|
||||
$$
|
||||
|
||||
To simplify the above equation, we need to use knowledge of sequences from high school, first multiply $T(h)$ by $2$, to get:
|
||||
To simplify the above expression, we need to use sequence knowledge from high school. First, multiply $T(h)$ by $2$ to get:
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
T(h) & = 2^0h + 2^1(h-1) + 2^2(h-2) + \dots + 2^{h-1}\times1 \newline
|
||||
2T(h) & = 2^1h + 2^2(h-1) + 2^3(h-2) + \dots + 2^h\times1 \newline
|
||||
2 T(h) & = 2^1h + 2^2(h-1) + 2^3(h-2) + \dots + 2^{h}\times1 \newline
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
By subtracting $T(h)$ from $2T(h)$ using the method of displacement, we get:
|
||||
Using the method of differences, subtract the first equation $T(h)$ from the second equation $2 T(h)$ to get:
|
||||
|
||||
$$
|
||||
2T(h) - T(h) = T(h) = -2^0h + 2^1 + 2^2 + \dots + 2^{h-1} + 2^h
|
||||
$$
|
||||
|
||||
Observing the equation, $T(h)$ is an geometric series, which can be directly calculated using the sum formula, resulting in a time complexity of:
|
||||
Observing the above expression, we find that $T(h)$ is a geometric series, which can be calculated directly using the sum formula, yielding a time complexity of:
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
@@ -71,4 +71,4 @@ T(h) & = 2 \frac{1 - 2^h}{1 - 2} - h \newline
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||
Further, a perfect binary tree with height $h$ has $n = 2^{h+1} - 1$ nodes, thus the complexity is $O(2^h) = O(n)$. This calculation shows that **the time complexity of inputting a list and constructing a heap is $O(n)$, which is very efficient**.
|
||||
Furthermore, a perfect binary tree with height $h$ has $n = 2^{h+1} - 1$ nodes, so the complexity is $O(2^h) = O(n)$. This derivation shows that **the time complexity of building a heap from an input list is $O(n)$, which is highly efficient**.
|
||||
|
||||
+109
-109
@@ -7,33 +7,33 @@ A <u>heap</u> is a complete binary tree that satisfies specific conditions and c
|
||||
|
||||

|
||||
|
||||
As a special case of a complete binary tree, a heap has the following characteristics:
|
||||
As a special case of a complete binary tree, heaps have the following characteristics.
|
||||
|
||||
- The bottom layer nodes are filled from left to right, and nodes in other layers are fully filled.
|
||||
- The root node of the binary tree is called the "top" of the heap, and the bottom-rightmost node is called the "bottom" of the heap.
|
||||
- For max heaps (min heaps), the value of the top element (root) is the largest (smallest) among all elements.
|
||||
- We call the root node of the binary tree the "heap top" and the bottom-rightmost node the "heap bottom."
|
||||
- For max heaps (min heaps), the value of the heap top element (root node) is the largest (smallest).
|
||||
|
||||
## Common heap operations
|
||||
|
||||
It should be noted that many programming languages provide a <u>priority queue</u>, which is an abstract data structure defined as a queue with priority sorting.
|
||||
|
||||
In practice, **heaps are often used to implement priority queues. A max heap corresponds to a priority queue where elements are dequeued in descending order**. From a usage perspective, we can consider "priority queue" and "heap" as equivalent data structures. Therefore, this book does not make a special distinction between the two, uniformly referring to them as "heap."
|
||||
In fact, **heaps are typically used to implement priority queues, with max heaps corresponding to priority queues where elements are dequeued in descending order**. From a usage perspective, we can regard "priority queue" and "heap" as equivalent data structures. Therefore, this book does not make a special distinction between the two and uniformly refers to them as "heap."
|
||||
|
||||
Common operations on heaps are shown in the table below, and the method names may vary based on the programming language.
|
||||
Common heap operations are shown in the table below, and method names need to be determined based on the programming language.
|
||||
|
||||
<p align="center"> Table <id> Efficiency of Heap Operations </p>
|
||||
|
||||
| Method name | Description | Time complexity |
|
||||
| ----------- | ------------------------------------------------------------ | --------------- |
|
||||
| `push()` | Add an element to the heap | $O(\log n)$ |
|
||||
| `pop()` | Remove the top element from the heap | $O(\log n)$ |
|
||||
| `peek()` | Access the top element (for max/min heap, the max/min value) | $O(1)$ |
|
||||
| `size()` | Get the number of elements in the heap | $O(1)$ |
|
||||
| `isEmpty()` | Check if the heap is empty | $O(1)$ |
|
||||
| Method name | Description | Time complexity |
|
||||
| ----------- | ----------------------------------------------------------------- | --------------- |
|
||||
| `push()` | Insert an element into the heap | $O(\log n)$ |
|
||||
| `pop()` | Remove the heap top element | $O(\log n)$ |
|
||||
| `peek()` | Access the heap top element (max/min value for max/min heap) | $O(1)$ |
|
||||
| `size()` | Get the number of elements in the heap | $O(1)$ |
|
||||
| `isEmpty()` | Check if the heap is empty | $O(1)$ |
|
||||
|
||||
In practice, we can directly use the heap class (or priority queue class) provided by programming languages.
|
||||
In practical applications, we can directly use the heap class (or priority queue class) provided by programming languages.
|
||||
|
||||
Similar to sorting algorithms where we have "ascending order" and "descending order", we can switch between "min heap" and "max heap" by setting a `flag` or modifying the `Comparator`. The code is as follows:
|
||||
Similar to "ascending order" and "descending order" in sorting algorithms, we can implement conversion between "min heap" and "max heap" by setting a `flag` or modifying the `Comparator`. The code is as follows:
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -44,8 +44,8 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
max_heap, flag = [], -1
|
||||
|
||||
# Python's heapq module implements a min heap by default
|
||||
# By negating the elements before pushing them to the heap, we invert the order and thus implement a max heap
|
||||
# In this example, flag = 1 corresponds to a min heap, while flag = -1 corresponds to a max heap
|
||||
# Consider negating elements before pushing them to the heap, which inverts the size relationship and thus implements a max heap
|
||||
# In this example, flag = 1 corresponds to a min heap, flag = -1 corresponds to a max heap
|
||||
|
||||
# Push elements into the heap
|
||||
heapq.heappush(max_heap, flag * 1)
|
||||
@@ -54,24 +54,24 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
heapq.heappush(max_heap, flag * 5)
|
||||
heapq.heappush(max_heap, flag * 4)
|
||||
|
||||
# Retrieve the top element of the heap
|
||||
# Get the heap top element
|
||||
peek: int = flag * max_heap[0] # 5
|
||||
|
||||
# Pop the top element of the heap
|
||||
# The popped elements will form a sequence in descending order
|
||||
# Remove the heap top element
|
||||
# The removed elements will form a descending sequence
|
||||
val = flag * heapq.heappop(max_heap) # 5
|
||||
val = flag * heapq.heappop(max_heap) # 4
|
||||
val = flag * heapq.heappop(max_heap) # 3
|
||||
val = flag * heapq.heappop(max_heap) # 2
|
||||
val = flag * heapq.heappop(max_heap) # 1
|
||||
|
||||
# Get the size of the heap
|
||||
# Get the heap size
|
||||
size: int = len(max_heap)
|
||||
|
||||
# Check if the heap is empty
|
||||
is_empty: bool = not max_heap
|
||||
|
||||
# Create a heap from a list
|
||||
# Build a heap from an input list
|
||||
min_heap: list[int] = [1, 3, 2, 5, 4]
|
||||
heapq.heapify(min_heap)
|
||||
```
|
||||
@@ -92,24 +92,24 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
maxHeap.push(5);
|
||||
maxHeap.push(4);
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
/* Get the heap top element */
|
||||
int peek = maxHeap.top(); // 5
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// The popped elements will form a sequence in descending order
|
||||
/* Remove the heap top element */
|
||||
// The removed elements will form a descending sequence
|
||||
maxHeap.pop(); // 5
|
||||
maxHeap.pop(); // 4
|
||||
maxHeap.pop(); // 3
|
||||
maxHeap.pop(); // 2
|
||||
maxHeap.pop(); // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
/* Get the heap size */
|
||||
int size = maxHeap.size();
|
||||
|
||||
/* Check if the heap is empty */
|
||||
bool isEmpty = maxHeap.empty();
|
||||
|
||||
/* Create a heap from a list */
|
||||
/* Build a heap from an input list */
|
||||
vector<int> input{1, 3, 2, 5, 4};
|
||||
priority_queue<int, vector<int>, greater<int>> minHeap(input.begin(), input.end());
|
||||
```
|
||||
@@ -120,34 +120,34 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
/* Initialize a heap */
|
||||
// Initialize a min heap
|
||||
Queue<Integer> minHeap = new PriorityQueue<>();
|
||||
// Initialize a max heap (Simply modify the Comparator using a lambda expression)
|
||||
// Initialize a max heap (use lambda expression to modify Comparator)
|
||||
Queue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
|
||||
|
||||
|
||||
/* Push elements into the heap */
|
||||
maxHeap.offer(1);
|
||||
maxHeap.offer(3);
|
||||
maxHeap.offer(2);
|
||||
maxHeap.offer(5);
|
||||
maxHeap.offer(4);
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
|
||||
/* Get the heap top element */
|
||||
int peek = maxHeap.peek(); // 5
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// The popped elements will form a sequence in descending order
|
||||
|
||||
/* Remove the heap top element */
|
||||
// The removed elements will form a descending sequence
|
||||
peek = maxHeap.poll(); // 5
|
||||
peek = maxHeap.poll(); // 4
|
||||
peek = maxHeap.poll(); // 3
|
||||
peek = maxHeap.poll(); // 2
|
||||
peek = maxHeap.poll(); // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
|
||||
/* Get the heap size */
|
||||
int size = maxHeap.size();
|
||||
|
||||
|
||||
/* Check if the heap is empty */
|
||||
boolean isEmpty = maxHeap.isEmpty();
|
||||
|
||||
/* Create a heap from a list */
|
||||
|
||||
/* Build a heap from an input list */
|
||||
minHeap = new PriorityQueue<>(Arrays.asList(1, 3, 2, 5, 4));
|
||||
```
|
||||
|
||||
@@ -157,8 +157,8 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
/* Initialize a heap */
|
||||
// Initialize a min heap
|
||||
PriorityQueue<int, int> minHeap = new();
|
||||
// Initialize a max heap (Simply modify the Comparator using a lambda expression)
|
||||
PriorityQueue<int, int> maxHeap = new(Comparer<int>.Create((x, y) => y - x));
|
||||
// Initialize a max heap (use lambda expression to modify Comparer)
|
||||
PriorityQueue<int, int> maxHeap = new(Comparer<int>.Create((x, y) => y.CompareTo(x)));
|
||||
|
||||
/* Push elements into the heap */
|
||||
maxHeap.Enqueue(1, 1);
|
||||
@@ -167,24 +167,24 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
maxHeap.Enqueue(5, 5);
|
||||
maxHeap.Enqueue(4, 4);
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
/* Get the heap top element */
|
||||
int peek = maxHeap.Peek();//5
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// The popped elements will form a sequence in descending order
|
||||
/* Remove the heap top element */
|
||||
// The removed elements will form a descending sequence
|
||||
peek = maxHeap.Dequeue(); // 5
|
||||
peek = maxHeap.Dequeue(); // 4
|
||||
peek = maxHeap.Dequeue(); // 3
|
||||
peek = maxHeap.Dequeue(); // 2
|
||||
peek = maxHeap.Dequeue(); // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
/* Get the heap size */
|
||||
int size = maxHeap.Count;
|
||||
|
||||
/* Check if the heap is empty */
|
||||
bool isEmpty = maxHeap.Count == 0;
|
||||
|
||||
/* Create a heap from a list */
|
||||
/* Build a heap from an input list */
|
||||
minHeap = new PriorityQueue<int, int>([(1, 1), (3, 3), (2, 2), (5, 5), (4, 4)]);
|
||||
```
|
||||
|
||||
@@ -192,41 +192,41 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
|
||||
```go title="heap.go"
|
||||
// In Go, we can construct a max heap of integers by implementing heap.Interface
|
||||
// Note that implementing heap.Interface requires also implementing sort.Interface
|
||||
// Implementing heap.Interface also requires implementing sort.Interface
|
||||
type intHeap []any
|
||||
|
||||
// Push method of heap.Interface, which pushes an element into the heap
|
||||
// Push implements the heap.Interface method for pushing an element into the heap
|
||||
func (h *intHeap) Push(x any) {
|
||||
// Both Push and Pop use a pointer receiver
|
||||
// because they not only adjust the elements of the slice but also change its length
|
||||
// Push and Pop use pointer receiver as parameters
|
||||
// because they not only adjust the slice contents but also modify the slice length
|
||||
*h = append(*h, x.(int))
|
||||
}
|
||||
|
||||
// Pop method of heap.Interface, which removes the top element of the heap
|
||||
// Pop implements the heap.Interface method for popping the heap top element
|
||||
func (h *intHeap) Pop() any {
|
||||
// The element to pop from the heap is stored at the end
|
||||
// The element to be removed is stored at the end
|
||||
last := (*h)[len(*h)-1]
|
||||
*h = (*h)[:len(*h)-1]
|
||||
return last
|
||||
}
|
||||
|
||||
// Len method of sort.Interface
|
||||
// Len is a sort.Interface method
|
||||
func (h *intHeap) Len() int {
|
||||
return len(*h)
|
||||
}
|
||||
|
||||
// Less method of sort.Interface
|
||||
// Less is a sort.Interface method
|
||||
func (h *intHeap) Less(i, j int) bool {
|
||||
// If you want to implement a min heap, you would change this to a less-than comparison
|
||||
// To implement a min heap, change this to a less-than sign
|
||||
return (*h)[i].(int) > (*h)[j].(int)
|
||||
}
|
||||
|
||||
// Swap method of sort.Interface
|
||||
// Swap is a sort.Interface method
|
||||
func (h *intHeap) Swap(i, j int) {
|
||||
(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
|
||||
}
|
||||
|
||||
// Top Retrieve the top element of the heap
|
||||
// Top gets the heap top element
|
||||
func (h *intHeap) Top() any {
|
||||
return (*h)[0]
|
||||
}
|
||||
@@ -238,28 +238,28 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
maxHeap := &intHeap{}
|
||||
heap.Init(maxHeap)
|
||||
/* Push elements into the heap */
|
||||
// Call the methods of heap.Interface to add elements
|
||||
// Call heap.Interface methods to add elements
|
||||
heap.Push(maxHeap, 1)
|
||||
heap.Push(maxHeap, 3)
|
||||
heap.Push(maxHeap, 2)
|
||||
heap.Push(maxHeap, 4)
|
||||
heap.Push(maxHeap, 5)
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
/* Get the heap top element */
|
||||
top := maxHeap.Top()
|
||||
fmt.Printf("The top element of the heap is %d\n", top)
|
||||
fmt.Printf("Heap top element is %d\n", top)
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// Call the methods of heap.Interface to remove elements
|
||||
/* Remove the heap top element */
|
||||
// Call heap.Interface methods to remove elements
|
||||
heap.Pop(maxHeap) // 5
|
||||
heap.Pop(maxHeap) // 4
|
||||
heap.Pop(maxHeap) // 3
|
||||
heap.Pop(maxHeap) // 2
|
||||
heap.Pop(maxHeap) // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
/* Get the heap size */
|
||||
size := len(*maxHeap)
|
||||
fmt.Printf("The number of elements in the heap is %d\n", size)
|
||||
fmt.Printf("Number of heap elements is %d\n", size)
|
||||
|
||||
/* Check if the heap is empty */
|
||||
isEmpty := len(*maxHeap) == 0
|
||||
@@ -271,7 +271,7 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
|
||||
```swift title="heap.swift"
|
||||
/* Initialize a heap */
|
||||
// Swift’s Heap type supports both max heaps and min heaps, and need the swift-collections library
|
||||
// Swift's Heap type supports both max heaps and min heaps, and requires importing swift-collections
|
||||
var heap = Heap<Int>()
|
||||
|
||||
/* Push elements into the heap */
|
||||
@@ -281,23 +281,23 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
heap.insert(5)
|
||||
heap.insert(4)
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
/* Get the heap top element */
|
||||
var peek = heap.max()!
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
/* Remove the heap top element */
|
||||
peek = heap.removeMax() // 5
|
||||
peek = heap.removeMax() // 4
|
||||
peek = heap.removeMax() // 3
|
||||
peek = heap.removeMax() // 2
|
||||
peek = heap.removeMax() // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
/* Get the heap size */
|
||||
let size = heap.count
|
||||
|
||||
/* Check if the heap is empty */
|
||||
let isEmpty = heap.isEmpty
|
||||
|
||||
/* Create a heap from a list */
|
||||
/* Build a heap from an input list */
|
||||
let heap2 = Heap([1, 3, 2, 5, 4])
|
||||
```
|
||||
|
||||
@@ -337,25 +337,25 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
max_heap.push(2);
|
||||
max_heap.push(5);
|
||||
max_heap.push(4);
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
|
||||
/* Get the heap top element */
|
||||
let peek = max_heap.peek().unwrap(); // 5
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// The popped elements will form a sequence in descending order
|
||||
/* Remove the heap top element */
|
||||
// The removed elements will form a descending sequence
|
||||
let peek = max_heap.pop().unwrap(); // 5
|
||||
let peek = max_heap.pop().unwrap(); // 4
|
||||
let peek = max_heap.pop().unwrap(); // 3
|
||||
let peek = max_heap.pop().unwrap(); // 2
|
||||
let peek = max_heap.pop().unwrap(); // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
/* Get the heap size */
|
||||
let size = max_heap.len();
|
||||
|
||||
/* Check if the heap is empty */
|
||||
let is_empty = max_heap.is_empty();
|
||||
|
||||
/* Create a heap from a list */
|
||||
/* Build a heap from an input list */
|
||||
let min_heap = BinaryHeap::from(vec![Reverse(1), Reverse(3), Reverse(2), Reverse(5), Reverse(4)]);
|
||||
```
|
||||
|
||||
@@ -371,41 +371,41 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
/* Initialize a heap */
|
||||
// Initialize a min heap
|
||||
var minHeap = PriorityQueue<Int>()
|
||||
// Initialize a max heap (Simply modify the Comparator using a lambda expression)
|
||||
// Initialize a max heap (use lambda expression to modify Comparator)
|
||||
val maxHeap = PriorityQueue { a: Int, b: Int -> b - a }
|
||||
|
||||
|
||||
/* Push elements into the heap */
|
||||
maxHeap.offer(1)
|
||||
maxHeap.offer(3)
|
||||
maxHeap.offer(2)
|
||||
maxHeap.offer(5)
|
||||
maxHeap.offer(4)
|
||||
|
||||
/* Retrieve the top element of the heap */
|
||||
|
||||
/* Get the heap top element */
|
||||
var peek = maxHeap.peek() // 5
|
||||
|
||||
/* Pop the top element of the heap */
|
||||
// The popped elements will form a sequence in descending order
|
||||
|
||||
/* Remove the heap top element */
|
||||
// The removed elements will form a descending sequence
|
||||
peek = maxHeap.poll() // 5
|
||||
peek = maxHeap.poll() // 4
|
||||
peek = maxHeap.poll() // 3
|
||||
peek = maxHeap.poll() // 2
|
||||
peek = maxHeap.poll() // 1
|
||||
|
||||
/* Get the size of the heap */
|
||||
|
||||
/* Get the heap size */
|
||||
val size = maxHeap.size
|
||||
|
||||
|
||||
/* Check if the heap is empty */
|
||||
val isEmpty = maxHeap.isEmpty()
|
||||
|
||||
/* Create a heap from a list */
|
||||
|
||||
/* Build a heap from an input list */
|
||||
minHeap = PriorityQueue(mutableListOf(1, 3, 2, 5, 4))
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="heap.rb"
|
||||
|
||||
# Ruby does not provide a built-in Heap class
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@@ -414,33 +414,33 @@ Similar to sorting algorithms where we have "ascending order" and "descending or
|
||||
|
||||
```
|
||||
|
||||
??? pythontutor "Code visualization"
|
||||
??? pythontutor "Code Visualization"
|
||||
|
||||
https://pythontutor.com/render.html#code=import%20heapq%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B0%8F%E9%A1%B6%E5%A0%86%0A%20%20%20%20min_heap,%20flag%20%3D%20%5B%5D,%201%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20max_heap,%20flag%20%3D%20%5B%5D,%20-1%0A%20%20%20%20%0A%20%20%20%20%23%20Python%20%E7%9A%84%20heapq%20%E6%A8%A1%E5%9D%97%E9%BB%98%E8%AE%A4%E5%AE%9E%E7%8E%B0%E5%B0%8F%E9%A1%B6%E5%A0%86%0A%20%20%20%20%23%20%E8%80%83%E8%99%91%E5%B0%86%E2%80%9C%E5%85%83%E7%B4%A0%E5%8F%96%E8%B4%9F%E2%80%9D%E5%90%8E%E5%86%8D%E5%85%A5%E5%A0%86%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%A4%A7%E5%B0%8F%E5%85%B3%E7%B3%BB%E9%A2%A0%E5%80%92%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%AE%9E%E7%8E%B0%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20%23%20%E5%9C%A8%E6%9C%AC%E7%A4%BA%E4%BE%8B%E4%B8%AD%EF%BC%8Cflag%20%3D%201%20%E6%97%B6%E5%AF%B9%E5%BA%94%E5%B0%8F%E9%A1%B6%E5%A0%86%EF%BC%8Cflag%20%3D%20-1%20%E6%97%B6%E5%AF%B9%E5%BA%94%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E5%A0%86%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%201%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%203%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%202%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%205%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%204%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%A0%86%E9%A1%B6%E5%85%83%E7%B4%A0%0A%20%20%20%20peek%20%3D%20flag%20*%20max_heap%5B0%5D%20%23%205%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%A0%86%E9%A1%B6%E5%85%83%E7%B4%A0%E5%87%BA%E5%A0%86%0A%20%20%20%20%23%20%E5%87%BA%E5%A0%86%E5%85%83%E7%B4%A0%E4%BC%9A%E5%BD%A2%E6%88%90%E4%B8%80%E4%B8%AA%E4%BB%8E%E5%A4%A7%E5%88%B0%E5%B0%8F%E7%9A%84%E5%BA%8F%E5%88%97%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%205%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%204%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%203%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%202%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%201%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%A0%86%E5%A4%A7%E5%B0%8F%0A%20%20%20%20size%20%3D%20len%28max_heap%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%A0%86%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20not%20max_heap%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%BE%93%E5%85%A5%E5%88%97%E8%A1%A8%E5%B9%B6%E5%BB%BA%E5%A0%86%0A%20%20%20%20min_heap%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20heapq.heapify%28min_heap%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false
|
||||
|
||||
## Implementation of the heap
|
||||
|
||||
The following implementation is of a max heap. To convert it into a min heap, simply invert all size logic comparisons (for example, replace $\geq$ with $\leq$). Interested readers are encouraged to implement it on their own.
|
||||
The following implementation is of a max heap. To convert it to a min heap, simply invert all size logic comparisons (for example, replace $\geq$ with $\leq$). Interested readers are encouraged to implement this on their own.
|
||||
|
||||
### Heap storage and representation
|
||||
|
||||
As mentioned in the "Binary Trees" section, complete binary trees are highly suitable for array representation. Since heaps are a type of complete binary tree, **we will use arrays to store heaps**.
|
||||
As mentioned in the "Binary Tree" chapter, complete binary trees are well-suited for array representation. Since heaps are a type of complete binary tree, **we will use arrays to store heaps**.
|
||||
|
||||
When using an array to represent a binary tree, elements represent node values, and indexes represent node positions in the binary tree. **Node pointers are implemented through an index mapping formula**.
|
||||
When representing a binary tree with an array, elements represent node values, and indexes represent node positions in the binary tree. **Node pointers are implemented through index mapping formulas**.
|
||||
|
||||
As shown in the figure below, given an index $i$, the index of its left child is $2i + 1$, the index of its right child is $2i + 2$, and the index of its parent is $(i - 1) / 2$ (floor division). When the index is out of bounds, it signifies a null node or the node does not exist.
|
||||
As shown in the figure below, given an index $i$, the index of its left child is $2i + 1$, the index of its right child is $2i + 2$, and the index of its parent is $(i - 1) / 2$ (floor division). When an index is out of bounds, it indicates a null node or that the node does not exist.
|
||||
|
||||

|
||||
|
||||
We can encapsulate the index mapping formula into functions for convenient later use:
|
||||
We can encapsulate the index mapping formula into functions for convenient subsequent use:
|
||||
|
||||
```src
|
||||
[file]{my_heap}-[class]{max_heap}-[func]{parent}
|
||||
```
|
||||
|
||||
### Accessing the top element of the heap
|
||||
### Accessing the heap top element
|
||||
|
||||
The top element of the heap is the root node of the binary tree, which is also the first element of the list:
|
||||
The heap top element is the root node of the binary tree, which is also the first element of the list:
|
||||
|
||||
```src
|
||||
[file]{my_heap}-[class]{max_heap}-[func]{peek}
|
||||
@@ -448,12 +448,12 @@ The top element of the heap is the root node of the binary tree, which is also t
|
||||
|
||||
### Inserting an element into the heap
|
||||
|
||||
Given an element `val`, we first add it to the bottom of the heap. After addition, since `val` may be larger than other elements in the heap, the heap's integrity might be compromised, **thus it's necessary to repair the path from the inserted node to the root node**. This operation is called <u>heapify</u>.
|
||||
Given an element `val`, we first add it to the bottom of the heap. After addition, since `val` may be larger than other elements in the heap, the heap's property may be violated. **Therefore, it's necessary to repair the path from the inserted node to the root node**. This operation is called <u>heapify</u>.
|
||||
|
||||
Considering starting from the node inserted, **perform heapify from bottom to top**. As shown in the figure below, we compare the value of the inserted node with its parent node, and if the inserted node is larger, we swap them. Then continue this operation, repairing each node in the heap from bottom to top until reaching the root or a node that does not need swapping.
|
||||
Starting from the inserted node, **perform heapify from bottom to top**. As shown in the figure below, we compare the inserted node with its parent node, and if the inserted node is larger, swap them. Then continue this operation, repairing nodes in the heap from bottom to top until we pass the root node or encounter a node that does not need swapping.
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -479,24 +479,24 @@ Considering starting from the node inserted, **perform heapify from bottom to to
|
||||
=== "<9>"
|
||||

|
||||
|
||||
Given a total of $n$ nodes, the height of the tree is $O(\log n)$. Hence, the loop iterations for the heapify operation are at most $O(\log n)$, **making the time complexity of the element insertion operation $O(\log n)$**. The code is as shown:
|
||||
Given a total of $n$ nodes, the tree height is $O(\log n)$. Thus, the number of loop iterations in the heapify operation is at most $O(\log n)$, **making the time complexity of the element insertion operation $O(\log n)$**. The code is as follows:
|
||||
|
||||
```src
|
||||
[file]{my_heap}-[class]{max_heap}-[func]{sift_up}
|
||||
```
|
||||
|
||||
### Removing the top element from the heap
|
||||
### Removing the heap top element
|
||||
|
||||
The top element of the heap is the root node of the binary tree, that is, the first element of the list. If we directly remove the first element from the list, all node indexes in the binary tree will change, making it difficult to use heapify for subsequent repairs. To minimize changes in element indexes, we use the following steps.
|
||||
The heap top element is the root node of the binary tree, which is the first element of the list. If we directly remove the first element from the list, all node indexes in the binary tree would change, making subsequent repair with heapify difficult. To minimize changes in element indexes, we use the following steps.
|
||||
|
||||
1. Swap the top element with the bottom element of the heap (swap the root node with the rightmost leaf node).
|
||||
2. After swapping, remove the bottom of the heap from the list (note that since it has been swapped, the original top element is actually being removed).
|
||||
1. Swap the heap top element with the heap bottom element (swap the root node with the rightmost leaf node).
|
||||
2. After swapping, remove the heap bottom from the list (note that since we've swapped, we're actually removing the original heap top element).
|
||||
3. Starting from the root node, **perform heapify from top to bottom**.
|
||||
|
||||
As shown in the figure below, **the direction of "heapify from top to bottom" is opposite to "heapify from bottom to top"**. We compare the value of the root node with its two children and swap it with the largest child. Then, repeat this operation until reaching the leaf node or encountering a node that does not need swapping.
|
||||
As shown in the figure below, **the direction of "top-to-bottom heapify" is opposite to "bottom-to-top heapify"**. We compare the root node's value with its two children and swap it with the largest child. Then loop this operation until we pass a leaf node or encounter a node that doesn't need swapping.
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -525,7 +525,7 @@ As shown in the figure below, **the direction of "heapify from top to bottom" is
|
||||
=== "<10>"
|
||||

|
||||
|
||||
Similar to the element insertion operation, the time complexity of the top element removal operation is also $O(\log n)$. The code is as follows:
|
||||
Similar to the element insertion operation, the time complexity of the heap top element removal operation is also $O(\log n)$. The code is as follows:
|
||||
|
||||
```src
|
||||
[file]{my_heap}-[class]{max_heap}-[func]{sift_down}
|
||||
@@ -533,6 +533,6 @@ Similar to the element insertion operation, the time complexity of the top eleme
|
||||
|
||||
## Common applications of heaps
|
||||
|
||||
- **Priority Queue**: Heaps are often the preferred data structure for implementing priority queues, with both enqueue and dequeue operations having a time complexity of $O(\log n)$, and building a queue having a time complexity of $O(n)$, all of which are very efficient.
|
||||
- **Heap Sort**: Given a set of data, we can create a heap from them and then continually perform element removal operations to obtain ordered data. However, there is a more elegant way to implement heap sort, as explained in the "Heap Sort" chapter.
|
||||
- **Finding the Largest $k$ Elements**: This is a classic algorithm problem and also a common use case, such as selecting the top 10 hot news for Weibo hot search, picking the top 10 selling products, etc.
|
||||
- **Priority queue**: Heaps are typically the preferred data structure for implementing priority queues, with both enqueue and dequeue operations having a time complexity of $O(\log n)$, and the heap construction operation having $O(n)$, all of which are highly efficient.
|
||||
- **Heap sort**: Given a set of data, we can build a heap with them and then continuously perform element removal operations to obtain sorted data. However, we usually use a more elegant approach to implement heap sort, as detailed in the "Heap Sort" chapter.
|
||||
- **Getting the largest $k$ elements**: This is a classic algorithm problem and also a typical application, such as selecting the top 10 trending news for Weibo hot search, selecting the top 10 best-selling products, etc.
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
!!! abstract
|
||||
|
||||
Heaps resemble mountains and their jagged peaks, layered and undulating, each with its unique form.
|
||||
Heaps are like mountain peaks, layered and undulating, each with its unique form.
|
||||
|
||||
Each mountain peak rises and falls in scattered heights, yet the tallest always captures attention first.
|
||||
The peaks rise and fall at varying heights, yet the tallest peak always catches the eye first.
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
### Key review
|
||||
|
||||
- A heap is a complete binary tree that can be categorized as either a max heap or a min heap based on its building property, where the top element of a max heap is the largest and the top element of a min heap is the smallest.
|
||||
- A priority queue is defined as a queue with dequeue priority, usually implemented using a heap.
|
||||
- Common operations of a heap and their corresponding time complexities include: element insertion into the heap $O(\log n)$, removing the top element from the heap $O(\log n)$, and accessing the top element of the heap $O(1)$.
|
||||
- A complete binary tree is well-suited to be represented by an array, thus heaps are commonly stored using arrays.
|
||||
- Heapify operations are used to maintain the properties of the heap and are used in both heap insertion and removal operations.
|
||||
- The time complexity of building a heap given an input of $n$ elements can be optimized to $O(n)$, which is highly efficient.
|
||||
- A heap is a complete binary tree that can be categorized as a max heap or min heap based on its property. The heap top element of a max heap (min heap) is the largest (smallest).
|
||||
- A priority queue is defined as a queue with priority sorting, typically implemented using heaps.
|
||||
- Common heap operations and their corresponding time complexities include: element insertion $O(\log n)$, heap top element removal $O(\log n)$, and accessing the heap top element $O(1)$.
|
||||
- Complete binary trees are well-suited for array representation, so we typically use arrays to store heaps.
|
||||
- Heapify operations are used to maintain the heap property and are employed in both element insertion and removal operations.
|
||||
- The time complexity of building a heap with $n$ input elements can be optimized to $O(n)$, which is highly efficient.
|
||||
- Top-k is a classic algorithm problem that can be efficiently solved using the heap data structure, with a time complexity of $O(n \log k)$.
|
||||
|
||||
### Q & A
|
||||
|
||||
**Q**: Is the "heap" in data structures the same concept as the "heap" in memory management?
|
||||
**Q**: Are the "heap" in data structures and the "heap" in memory management the same concept?
|
||||
|
||||
The two are not the same concept, even though they are both referred to as "heap". The heap in computer system memory is part of dynamic memory allocation, where the program can use it to store data during execution. The program can request a certain amount of heap memory to store complex structures like objects and arrays. When the allocated data is no longer needed, the program needs to release this memory to prevent memory leaks. Compared to stack memory, the management and usage of heap memory demands more caution, as improper use may lead to memory leaks and dangling pointers.
|
||||
The two are not the same concept; they just happen to share the name "heap." The heap in computer system memory is part of dynamic memory allocation, where programs can use it to store data during runtime. Programs can request a certain amount of heap memory to store complex structures such as objects and arrays. When this data is no longer needed, the program needs to release this memory to prevent memory leaks. Compared to stack memory, heap memory management and usage require more caution, as improper use can lead to issues such as memory leaks and dangling pointers.
|
||||
|
||||
@@ -4,39 +4,39 @@
|
||||
|
||||
Given an unordered array `nums` of length $n$, return the largest $k$ elements in the array.
|
||||
|
||||
For this problem, we will first introduce two straightforward solutions, then explain a more efficient heap-based method.
|
||||
For this problem, we'll first introduce two solutions with relatively straightforward approaches, then introduce a more efficient heap-based solution.
|
||||
|
||||
## Method 1: Iterative selection
|
||||
|
||||
We can perform $k$ rounds of iterations as shown in the figure below, extracting the $1^{st}$, $2^{nd}$, $\dots$, $k^{th}$ largest elements in each round, with a time complexity of $O(nk)$.
|
||||
We can perform $k$ rounds of traversal as shown in the figure below, extracting the $1^{st}$, $2^{nd}$, $\dots$, $k^{th}$ largest elements in each round, with a time complexity of $O(nk)$.
|
||||
|
||||
This method is only suitable when $k \ll n$, as the time complexity approaches $O(n^2)$ when $k$ is close to $n$, which is very time-consuming.
|
||||
This method is only suitable when $k \ll n$, because when $k$ is close to $n$, the time complexity approaches $O(n^2)$, which is very time-consuming.
|
||||
|
||||

|
||||

|
||||
|
||||
!!! tip
|
||||
|
||||
When $k = n$, we can obtain a complete ordered sequence, which is equivalent to the "selection sort" algorithm.
|
||||
When $k = n$, we can obtain a complete sorted sequence, which is equivalent to the "selection sort" algorithm.
|
||||
|
||||
## Method 2: Sorting
|
||||
|
||||
As shown in the figure below, we can first sort the array `nums` and then return the last $k$ elements, with a time complexity of $O(n \log n)$.
|
||||
As shown in the figure below, we can first sort the array `nums`, then return the rightmost $k$ elements, with a time complexity of $O(n \log n)$.
|
||||
|
||||
Clearly, this method "overachieves" the task, as we only need to find the largest $k$ elements, without the need to sort the other elements.
|
||||
Clearly, this method "overachieves" the task, as we only need to find the largest $k$ elements, without needing to sort the other elements.
|
||||
|
||||

|
||||
|
||||
## Method 3: Heap
|
||||
|
||||
We can solve the Top-k problem more efficiently based on heaps, as shown in the following process.
|
||||
We can solve the Top-k problem more efficiently using heaps, with the process shown in the figure below.
|
||||
|
||||
1. Initialize a min heap, where the top element is the smallest.
|
||||
2. First, insert the first $k$ elements of the array into the heap.
|
||||
3. Starting from the $k + 1^{th}$ element, if the current element is greater than the top element of the heap, remove the top element of the heap and insert the current element into the heap.
|
||||
4. After completing the traversal, the heap contains the largest $k$ elements.
|
||||
1. Initialize a min heap, where the heap top element is the smallest.
|
||||
2. First, insert the first $k$ elements of the array into the heap in sequence.
|
||||
3. Starting from the $(k + 1)^{th}$ element, if the current element is greater than the heap top element, remove the heap top element and insert the current element into the heap.
|
||||
4. After traversal is complete, the heap contains the largest $k$ elements.
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -68,6 +68,6 @@ Example code is as follows:
|
||||
[file]{top_k}-[class]{}-[func]{top_k_heap}
|
||||
```
|
||||
|
||||
A total of $n$ rounds of heap insertions and deletions are performed, with the maximum heap size being $k$, hence the time complexity is $O(n \log k)$. This method is very efficient; when $k$ is small, the time complexity tends towards $O(n)$; when $k$ is large, the time complexity will not exceed $O(n \log n)$.
|
||||
A total of $n$ rounds of heap insertions and removals are performed, with the heap's maximum length being $k$, so the time complexity is $O(n \log k)$. This method is very efficient; when $k$ is small, the time complexity approaches $O(n)$; when $k$ is large, the time complexity does not exceed $O(n \log n)$.
|
||||
|
||||
Additionally, this method is suitable for scenarios with dynamic data streams. By continuously adding data, we can maintain the elements within the heap, thereby achieving dynamic updates of the largest $k$ elements.
|
||||
Additionally, this method is suitable for dynamic data stream scenarios. By continuously adding data, we can maintain the elements in the heap, thus achieving dynamic updates of the largest $k$ elements.
|
||||
|
||||
Reference in New Issue
Block a user