dsa-ruby 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/dsa-ruby/heap.rb CHANGED
@@ -1,145 +1,273 @@
1
- module DSA
2
- class MinHeap
3
- def initialize(elements = [])
4
- @elements = []
5
- elements.each { |e| push(e) }
6
- end
1
+ # DSA::MinHeap - A min-heap (priority queue) data structure.
2
+ #
3
+ # The smallest element is always at the root. Provides O(log n) insertion
4
+ # and extraction of the minimum element.
5
+ #
6
+ # @example
7
+ # heap = DSA::MinHeap.new([5, 3, 7, 1])
8
+ # heap.pop # => 1
9
+ # heap.peek # => 3
10
+ #
11
+ # # Or build incrementally with chained pushes:
12
+ # heap = DSA::MinHeap.new
13
+ # heap.push(5).push(3).push(7).push(1)
14
+ class DSA::MinHeap
15
+ # Initialize a new min-heap with optional initial elements.
16
+ #
17
+ # @param elements [Array<Comparable>] optional array of elements to heapify
18
+ # @return [DSA::MinHeap] a new min-heap
19
+ # @example
20
+ # DSA::MinHeap.new([3, 1, 2])
21
+ def initialize(elements = [])
22
+ @elements = []
23
+ elements.each { |e| push(e) }
24
+ end
7
25
 
8
- def push(val)
9
- @elements << val
10
- sift_up(@elements.size - 1)
11
- self
12
- end
26
+ # Inserts an element into the heap.
27
+ #
28
+ # @param val [Comparable] the value to insert
29
+ # @return [DSA::MinHeap] self for method chaining
30
+ # @example
31
+ # heap.push(5).push(3).push(1)
32
+ def push(val)
33
+ @elements << val
34
+ sift_up(@elements.size - 1)
35
+ self
36
+ end
13
37
 
14
- def pop
15
- raise IndexError, "heap is empty" if empty?
38
+ # Removes and returns the minimum element from the heap.
39
+ #
40
+ # @return [Comparable] the minimum element
41
+ # @raise [IndexError] if the heap is empty
42
+ # @example
43
+ # heap.push(5).push(1).push(3)
44
+ # heap.pop # => 1
45
+ def pop
46
+ raise IndexError, "heap is empty" if empty?
16
47
 
17
- swap(0, @elements.size - 1)
18
- min = @elements.pop
19
- sift_down(0)
20
- min
21
- end
48
+ swap(0, @elements.size - 1)
49
+ min = @elements.pop
50
+ sift_down(0)
51
+ min
52
+ end
22
53
 
23
- def peek
24
- raise IndexError, "heap is empty" if empty?
25
- @elements[0]
26
- end
54
+ # Returns the minimum element without removing it.
55
+ #
56
+ # @return [Comparable] the minimum element
57
+ # @raise [IndexError] if the heap is empty
58
+ # @example
59
+ # heap.push(5).push(1).push(3)
60
+ # heap.peek # => 1
61
+ def peek
62
+ raise IndexError, "heap is empty" if empty?
63
+ @elements[0]
64
+ end
27
65
 
28
- def size
29
- @elements.size
30
- end
66
+ # Returns the number of elements in the heap.
67
+ #
68
+ # @return [Integer] the number of elements
69
+ # @example
70
+ # heap.push(5).push(3)
71
+ # heap.size # => 2
72
+ def size
73
+ @elements.size
74
+ end
31
75
 
32
- def empty?
33
- @elements.empty?
34
- end
76
+ # Checks if the heap is empty.
77
+ #
78
+ # @return [Boolean] true if the heap contains no elements
79
+ # @example
80
+ # heap = DSA::MinHeap.new
81
+ # heap.empty? # => true
82
+ def empty?
83
+ @elements.empty?
84
+ end
35
85
 
36
- def to_a
37
- @elements.dup
38
- end
86
+ # Returns a defensive copy of the heap as an array.
87
+ #
88
+ # @return [Array<Comparable>] an array containing all elements (not in sorted order)
89
+ # @example
90
+ # heap.push(5).push(3).push(1)
91
+ # heap.to_a # => [1, 3, 5] (may vary based on internal structure)
92
+ def to_a
93
+ @elements.dup
94
+ end
39
95
 
40
- private
96
+ private
41
97
 
42
- def sift_up(i)
43
- while i > 0
44
- parent = (i - 1) / 2
45
- break if (@elements[parent] <=> @elements[i]) <= 0
98
+ # Moves an element up the heap to restore the heap property.
99
+ #
100
+ # @param i [Integer] the index of the element to sift up
101
+ def sift_up(i)
102
+ while i > 0
103
+ parent = (i - 1) / 2
104
+ break if (@elements[parent] <=> @elements[i]) <= 0
46
105
 
47
- swap(parent, i)
48
- i = parent
49
- end
106
+ swap(parent, i)
107
+ i = parent
50
108
  end
109
+ end
51
110
 
52
- def sift_down(i)
53
- n = @elements.size
54
- loop do
55
- smallest = i
56
- left = 2 * i + 1
57
- right = 2 * i + 2
111
+ # Moves an element down the heap to restore the heap property.
112
+ #
113
+ # @param i [Integer] the index of the element to sift down
114
+ def sift_down(i)
115
+ n = @elements.size
116
+ loop do
117
+ smallest = i
118
+ left = 2 * i + 1
119
+ right = 2 * i + 2
58
120
 
59
- smallest = left if left < n && (@elements[left] <=> @elements[smallest]) < 0
60
- smallest = right if right < n && (@elements[right] <=> @elements[smallest]) < 0
121
+ smallest = left if left < n && (@elements[left] <=> @elements[smallest]) < 0
122
+ smallest = right if right < n && (@elements[right] <=> @elements[smallest]) < 0
61
123
 
62
- break if smallest == i
124
+ break if smallest == i
63
125
 
64
- swap(i, smallest)
65
- i = smallest
66
- end
126
+ swap(i, smallest)
127
+ i = smallest
67
128
  end
129
+ end
68
130
 
69
- def swap(i, j)
70
- @elements[i], @elements[j] = @elements[j], @elements[i]
71
- end
131
+ # Swaps two elements in the heap array.
132
+ #
133
+ # @param i [Integer] index of first element
134
+ # @param j [Integer] index of second element
135
+ def swap(i, j)
136
+ @elements[i], @elements[j] = @elements[j], @elements[i]
72
137
  end
138
+ end
73
139
 
74
- class MaxHeap
75
- def initialize(elements = [])
76
- @elements = []
77
- elements.each { |e| push(e) }
78
- end
140
+ # DSA::MaxHeap - A max-heap (priority queue) data structure.
141
+ #
142
+ # The largest element is always at the root. Provides O(log n) insertion
143
+ # and extraction of the maximum element.
144
+ #
145
+ # @example
146
+ # heap = DSA::MaxHeap.new([5, 3, 7, 1])
147
+ # heap.pop # => 7
148
+ # heap.peek # => 5
149
+ class DSA::MaxHeap
150
+ # Initialize a new max-heap with optional initial elements.
151
+ #
152
+ # @param elements [Array<Comparable>] optional array of elements to heapify
153
+ # @return [DSA::MaxHeap] a new max-heap
154
+ # @example
155
+ # DSA::MaxHeap.new([3, 1, 2])
156
+ def initialize(elements = [])
157
+ @elements = []
158
+ elements.each { |e| push(e) }
159
+ end
79
160
 
80
- def push(val)
81
- @elements << val
82
- sift_up(@elements.size - 1)
83
- self
84
- end
161
+ # Inserts an element into the heap.
162
+ #
163
+ # @param val [Comparable] the value to insert
164
+ # @return [DSA::MaxHeap] self for method chaining
165
+ # @example
166
+ # heap.push(5).push(3).push(1)
167
+ def push(val)
168
+ @elements << val
169
+ sift_up(@elements.size - 1)
170
+ self
171
+ end
85
172
 
86
- def pop
87
- raise IndexError, "heap is empty" if empty?
173
+ # Removes and returns the maximum element from the heap.
174
+ #
175
+ # @return [Comparable] the maximum element
176
+ # @raise [IndexError] if the heap is empty
177
+ # @example
178
+ # heap.push(5).push(1).push(3)
179
+ # heap.pop # => 5
180
+ def pop
181
+ raise IndexError, "heap is empty" if empty?
88
182
 
89
- swap(0, @elements.size - 1)
90
- max = @elements.pop
91
- sift_down(0)
92
- max
93
- end
183
+ swap(0, @elements.size - 1)
184
+ max = @elements.pop
185
+ sift_down(0)
186
+ max
187
+ end
94
188
 
95
- def peek
96
- raise IndexError, "heap is empty" if empty?
97
- @elements[0]
98
- end
189
+ # Returns the maximum element without removing it.
190
+ #
191
+ # @return [Comparable] the maximum element
192
+ # @raise [IndexError] if the heap is empty
193
+ # @example
194
+ # heap.push(5).push(1).push(3)
195
+ # heap.peek # => 5
196
+ def peek
197
+ raise IndexError, "heap is empty" if empty?
198
+ @elements[0]
199
+ end
99
200
 
100
- def size
101
- @elements.size
102
- end
201
+ # Returns the number of elements in the heap.
202
+ #
203
+ # @return [Integer] the number of elements
204
+ # @example
205
+ # heap.push(5).push(3)
206
+ # heap.size # => 2
207
+ def size
208
+ @elements.size
209
+ end
103
210
 
104
- def empty?
105
- @elements.empty?
106
- end
211
+ # Checks if the heap is empty.
212
+ #
213
+ # @return [Boolean] true if the heap contains no elements
214
+ # @example
215
+ # heap = DSA::MaxHeap.new
216
+ # heap.empty? # => true
217
+ def empty?
218
+ @elements.empty?
219
+ end
107
220
 
108
- def to_a
109
- @elements.dup
110
- end
221
+ # Returns a defensive copy of the heap as an array.
222
+ #
223
+ # @return [Array<Comparable>] an array containing all elements (not in sorted order)
224
+ # @example
225
+ # heap.push(5).push(3).push(1)
226
+ # heap.to_a # => [5, 3, 1] (may vary based on internal structure)
227
+ def to_a
228
+ @elements.dup
229
+ end
111
230
 
112
- private
231
+ private
113
232
 
114
- def sift_up(i)
115
- while i > 0
116
- parent = (i - 1) / 2
117
- break if (@elements[parent] <=> @elements[i]) >= 0
233
+ # Moves an element up the heap to restore the heap property.
234
+ #
235
+ # @param i [Integer] the index of the element to sift up
236
+ def sift_up(i)
237
+ while i > 0
238
+ parent = (i - 1) / 2
239
+ break if (@elements[parent] <=> @elements[i]) >= 0
118
240
 
119
- swap(parent, i)
120
- i = parent
121
- end
241
+ swap(parent, i)
242
+ i = parent
122
243
  end
244
+ end
123
245
 
124
- def sift_down(i)
125
- n = @elements.size
126
- loop do
127
- largest = i
128
- left = 2 * i + 1
129
- right = 2 * i + 2
246
+ # Moves an element down the heap to restore the heap property.
247
+ #
248
+ # @param i [Integer] the index of the element to sift down
249
+ def sift_down(i)
250
+ n = @elements.size
251
+ loop do
252
+ largest = i
253
+ left = 2 * i + 1
254
+ right = 2 * i + 2
130
255
 
131
- largest = left if left < n && (@elements[left] <=> @elements[largest]) > 0
132
- largest = right if right < n && (@elements[right] <=> @elements[largest]) > 0
256
+ largest = left if left < n && (@elements[left] <=> @elements[largest]) > 0
257
+ largest = right if right < n && (@elements[right] <=> @elements[largest]) > 0
133
258
 
134
- break if largest == i
259
+ break if largest == i
135
260
 
136
- swap(i, largest)
137
- i = largest
138
- end
261
+ swap(i, largest)
262
+ i = largest
139
263
  end
264
+ end
140
265
 
141
- def swap(i, j)
142
- @elements[i], @elements[j] = @elements[j], @elements[i]
143
- end
266
+ # Swaps two elements in the heap array.
267
+ #
268
+ # @param i [Integer] index of first element
269
+ # @param j [Integer] index of second element
270
+ def swap(i, j)
271
+ @elements[i], @elements[j] = @elements[j], @elements[i]
144
272
  end
145
273
  end