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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d48c162c54e6f3b5a72e0ec6c5bfb01ea194db9aa01edd8b3acf22ec8e65d2a
4
- data.tar.gz: 90dec8d0903d522bd53c1928f1b4bfe4e3183c51ac0cd6c6c2089864eeaf31ed
3
+ metadata.gz: 263fc0d28c00fb0c51f2728871cc4f13e5f8d5d8c2011cd42523d440003bcd3e
4
+ data.tar.gz: 72d323d5c5b3527ee5ad9c4ec85b2949ff1ec90a6258928e83ced26358bc7466
5
5
  SHA512:
6
- metadata.gz: ffc6d6ee8215956588a61c477fbf92c8a441d43ded58525f758086c07433389616c9f538bac40d2de30f113d184beec0cfb155d236cc7ddb08da815b9d1aa75f
7
- data.tar.gz: 700cbc183e14b7fe0884c52b43a49c686530e6276deea50a3eaf6b7df9e65dfd23b51ccc21c38d5af38bed62496f59e1314c43c59a20d0587344d495606406c3
6
+ metadata.gz: 8d0dced01fb73b0a2e76d32795bbf57ffb84ffeaee0d790089d63e5e33365a7113247ede84e080b6e4fdcf4b30ad0459e42f81ed42bc6c18e7d49b29ad3cbcb6
7
+ data.tar.gz: 6855c1c3e893b55ae698e966094117d5f3105f39c4724bcd09fb478570ebd4ade85d6817f24b19172cd3a3787b0b625360ef49cdb1a5b100cc263a1cdd067d8c
data/README.md CHANGED
@@ -24,8 +24,7 @@ require "dsa-ruby"
24
24
  ### MinHeap / MaxHeap
25
25
 
26
26
  ```ruby
27
- heap = DSA::MinHeap.new
28
- heap.push(5, 3, 7, 1)
27
+ heap = DSA::MinHeap.new([5, 3, 7, 1])
29
28
  heap.pop # => 1
30
29
  heap.peek # => 3
31
30
 
@@ -33,6 +32,13 @@ max_heap = DSA::MaxHeap.new([5, 3, 7, 1])
33
32
  max_heap.pop # => 7
34
33
  ```
35
34
 
35
+ Or build incrementally with chained pushes:
36
+
37
+ ```ruby
38
+ heap = DSA::MinHeap.new
39
+ heap.push(5).push(3).push(7).push(1)
40
+ ```
41
+
36
42
  ### PriorityQueue
37
43
 
38
44
  ```ruby
@@ -58,7 +64,7 @@ dq.pop_front # => 1
58
64
  dq.pop_back # => 2
59
65
 
60
66
  # Enumerable support
61
- dq.push_back(1, 2, 3)
67
+ dq.push_back(1).push_back(2).push_back(3)
62
68
  dq.map { |x| x * 2 } # => [2, 4, 6]
63
69
  ```
64
70
 
@@ -1,154 +1,289 @@
1
- module DSA
2
- class BinarySearchTree
3
- Node = Struct.new(:val, :left, :right, keyword_init: true)
1
+ # DSA::BinarySearchTree - A binary search tree data structure.
2
+ #
3
+ # Supports insertion, deletion, search, and tree traversals.
4
+ # Duplicate values are not inserted.
5
+ #
6
+ # @example
7
+ # bst = DSA::BinarySearchTree.new
8
+ # bst.insert(5).insert(3).insert(7).insert(1).insert(4)
9
+ # bst.search(3) # => true
10
+ # bst.min # => 1
11
+ # bst.max # => 7
12
+ # bst.inorder # => [1, 3, 4, 5, 7]
13
+ # bst.preorder # => [5, 3, 1, 4, 7]
14
+ # bst.postorder # => [1, 4, 3, 7, 5]
15
+ # bst.delete(3)
16
+ class DSA::BinarySearchTree
17
+ # Internal node structure for the binary search tree.
18
+ #
19
+ # @!attribute [rw] val
20
+ # @return [Comparable] the value stored in the node
21
+ # @!attribute [rw] left
22
+ # @return [Node, nil] the left child node
23
+ # @!attribute [rw] right
24
+ # @return [Node, nil] the right child node
25
+ Node = Struct.new(:val, :left, :right, keyword_init: true)
4
26
 
5
- def initialize
6
- @root = nil
7
- @size = 0
8
- end
9
-
10
- def insert(val)
11
- @root, added = insert_recursive(@root, val)
12
- @size += 1 if added
13
- self
14
- end
15
-
16
- def search(val)
17
- !!find_node(@root, val)
18
- end
27
+ # Initialize a new empty binary search tree.
28
+ #
29
+ # @return [DSA::BinarySearchTree] a new empty tree
30
+ def initialize
31
+ @root = nil
32
+ @size = 0
33
+ end
19
34
 
20
- def delete(val)
21
- @root, deleted = delete_recursive(@root, val)
22
- @size -= 1 if deleted
23
- deleted
24
- end
35
+ # Inserts a value into the tree. Duplicates are ignored.
36
+ #
37
+ # @param val [Comparable] the value to insert
38
+ # @return [DSA::BinarySearchTree] self for method chaining
39
+ # @example
40
+ # bst.insert(5).insert(3).insert(7)
41
+ def insert(val)
42
+ @root, added = insert_recursive(@root, val)
43
+ @size += 1 if added
44
+ self
45
+ end
25
46
 
26
- def min
27
- raise IndexError, "tree is empty" if empty?
28
- find_min(@root).val
29
- end
47
+ # Searches for a value in the tree.
48
+ #
49
+ # @param val [Comparable] the value to search for
50
+ # @return [Boolean] true if the value exists in the tree
51
+ # @example
52
+ # bst.insert(5)
53
+ # bst.search(5) # => true
54
+ # bst.search(3) # => false
55
+ def search(val)
56
+ !!find_node(@root, val)
57
+ end
30
58
 
31
- def max
32
- raise IndexError, "tree is empty" if empty?
33
- find_max(@root).val
34
- end
59
+ # Deletes a value from the tree if it exists.
60
+ #
61
+ # @param val [Comparable] the value to delete
62
+ # @return [Boolean] true if the value was deleted, false if not found
63
+ # @example
64
+ # bst.insert(5).insert(3)
65
+ # bst.delete(3) # => true
66
+ # bst.delete(8) # => false
67
+ def delete(val)
68
+ @root, deleted = delete_recursive(@root, val)
69
+ @size -= 1 if deleted
70
+ deleted
71
+ end
35
72
 
36
- def inorder
37
- return [] if empty?
38
- result = []
39
- traverse_inorder(@root, result)
40
- result
41
- end
73
+ # Returns the minimum value in the tree.
74
+ #
75
+ # @return [Comparable] the minimum value
76
+ # @raise [IndexError] if the tree is empty
77
+ # @example
78
+ # bst.insert(5).insert(3).insert(1)
79
+ # bst.min # => 1
80
+ def min
81
+ raise IndexError, "tree is empty" if empty?
82
+ find_min(@root).val
83
+ end
42
84
 
43
- def preorder
44
- return [] if empty?
45
- result = []
46
- traverse_preorder(@root, result)
47
- result
48
- end
85
+ # Returns the maximum value in the tree.
86
+ #
87
+ # @return [Comparable] the maximum value
88
+ # @raise [IndexError] if the tree is empty
89
+ # @example
90
+ # bst.insert(5).insert(3).insert(7)
91
+ # bst.max # => 7
92
+ def max
93
+ raise IndexError, "tree is empty" if empty?
94
+ find_max(@root).val
95
+ end
49
96
 
50
- def postorder
51
- return [] if empty?
52
- result = []
53
- traverse_postorder(@root, result)
54
- result
55
- end
97
+ # Returns an array of values in inorder traversal (left, root, right).
98
+ #
99
+ # @return [Array<Comparable>] values in inorder sequence (sorted order)
100
+ # @example
101
+ # bst.insert(5).insert(3).insert(7)
102
+ # bst.inorder # => [3, 5, 7]
103
+ def inorder
104
+ return [] if empty?
105
+ result = []
106
+ traverse_inorder(@root, result)
107
+ result
108
+ end
56
109
 
57
- def size
58
- @size
59
- end
110
+ # Returns an array of values in preorder traversal (root, left, right).
111
+ #
112
+ # @return [Array<Comparable>] values in preorder sequence
113
+ # @example
114
+ # bst.insert(5).insert(3).insert(7)
115
+ # bst.preorder # => [5, 3, 7]
116
+ def preorder
117
+ return [] if empty?
118
+ result = []
119
+ traverse_preorder(@root, result)
120
+ result
121
+ end
60
122
 
61
- def empty?
62
- @size == 0
63
- end
123
+ # Returns an array of values in postorder traversal (left, right, root).
124
+ #
125
+ # @return [Array<Comparable>] values in postorder sequence
126
+ # @example
127
+ # bst.insert(5).insert(3).insert(7)
128
+ # bst.postorder # => [3, 7, 5]
129
+ def postorder
130
+ return [] if empty?
131
+ result = []
132
+ traverse_postorder(@root, result)
133
+ result
134
+ end
64
135
 
65
- def to_a
66
- inorder
67
- end
136
+ # Returns the number of elements in the tree.
137
+ #
138
+ # @return [Integer] the number of elements
139
+ # @example
140
+ # bst.insert(5).insert(3)
141
+ # bst.size # => 2
142
+ def size
143
+ @size
144
+ end
68
145
 
69
- private
146
+ # Checks if the tree is empty.
147
+ #
148
+ # @return [Boolean] true if the tree contains no elements
149
+ # @example
150
+ # bst = DSA::BinarySearchTree.new
151
+ # bst.empty? # => true
152
+ def empty?
153
+ @size == 0
154
+ end
70
155
 
71
- def insert_recursive(node, val)
72
- if node.nil?
73
- return [Node.new(val: val, left: nil, right: nil), true]
74
- end
156
+ # Returns a defensive copy of the tree as an array (inorder traversal).
157
+ #
158
+ # @return [Array<Comparable>] an array of values in sorted order
159
+ # @example
160
+ # bst.insert(5).insert(3).insert(7)
161
+ # bst.to_a # => [3, 5, 7]
162
+ def to_a
163
+ inorder
164
+ end
75
165
 
76
- if val < node.val
77
- node.left, added = insert_recursive(node.left, val)
78
- elsif val > node.val
79
- node.right, added = insert_recursive(node.right, val)
80
- else
81
- added = false
82
- end
166
+ private
83
167
 
84
- [node, added]
168
+ # Recursively inserts a value into the tree.
169
+ #
170
+ # @param node [Node, nil] the current node being examined
171
+ # @param val [Comparable] the value to insert
172
+ # @return [Array] tuple of (updated node, whether a new node was added)
173
+ def insert_recursive(node, val)
174
+ if node.nil?
175
+ return [Node.new(val: val, left: nil, right: nil), true]
85
176
  end
86
177
 
87
- def find_node(node, val)
88
- return nil unless node
89
- return node if node.val == val
90
-
91
- if val < node.val
92
- find_node(node.left, val)
93
- else
94
- find_node(node.right, val)
95
- end
178
+ if val < node.val
179
+ node.left, added = insert_recursive(node.left, val)
180
+ elsif val > node.val
181
+ node.right, added = insert_recursive(node.right, val)
182
+ else
183
+ added = false
96
184
  end
97
185
 
98
- def delete_recursive(node, val)
99
- return [nil, false] unless node
186
+ [node, added]
187
+ end
100
188
 
101
- if val < node.val
102
- node.left, deleted = delete_recursive(node.left, val)
103
- elsif val > node.val
104
- node.right, deleted = delete_recursive(node.right, val)
105
- else
106
- deleted = true
107
- return [delete_node(node), true]
108
- end
189
+ # Finds a node with the given value.
190
+ #
191
+ # @param node [Node, nil] the current node being examined
192
+ # @param val [Comparable] the value to find
193
+ # @return [Node, nil] the node if found, nil otherwise
194
+ def find_node(node, val)
195
+ return nil unless node
196
+ return node if node.val == val
109
197
 
110
- [node, deleted]
198
+ if val < node.val
199
+ find_node(node.left, val)
200
+ else
201
+ find_node(node.right, val)
111
202
  end
203
+ end
112
204
 
113
- def delete_node(node)
114
- return node.right unless node.left
115
- return node.left unless node.right
205
+ # Recursively deletes a value from the tree.
206
+ #
207
+ # @param node [Node, nil] the current node being examined
208
+ # @param val [Comparable] the value to delete
209
+ # @return [Array] tuple of (updated node, whether the value was deleted)
210
+ def delete_recursive(node, val)
211
+ return [nil, false] unless node
116
212
 
117
- successor = find_min(node.right)
118
- node.val = successor.val
119
- node.right, _ = delete_recursive(node.right, successor.val)
120
- node
213
+ if val < node.val
214
+ node.left, deleted = delete_recursive(node.left, val)
215
+ elsif val > node.val
216
+ node.right, deleted = delete_recursive(node.right, val)
217
+ else
218
+ deleted = true
219
+ return [delete_node(node), true]
121
220
  end
122
221
 
123
- def find_min(node)
124
- node = node.left while node.left
125
- node
126
- end
222
+ [node, deleted]
223
+ end
127
224
 
128
- def find_max(node)
129
- node = node.right while node.right
130
- node
131
- end
225
+ # Handles the three cases for node deletion.
226
+ #
227
+ # @param node [Node] the node to delete
228
+ # @return [Node, nil] the replacement node
229
+ def delete_node(node)
230
+ return node.right unless node.left
231
+ return node.left unless node.right
132
232
 
133
- def traverse_inorder(node, result)
134
- return unless node
135
- traverse_inorder(node.left, result)
136
- result << node.val
137
- traverse_inorder(node.right, result)
138
- end
233
+ successor = find_min(node.right)
234
+ node.val = successor.val
235
+ node.right, _ = delete_recursive(node.right, successor.val)
236
+ node
237
+ end
139
238
 
140
- def traverse_preorder(node, result)
141
- return unless node
142
- result << node.val
143
- traverse_preorder(node.left, result)
144
- traverse_preorder(node.right, result)
145
- end
239
+ # Finds the node with the minimum value in a subtree.
240
+ #
241
+ # @param node [Node] the root of the subtree
242
+ # @return [Node] the node with the minimum value
243
+ def find_min(node)
244
+ node = node.left while node.left
245
+ node
246
+ end
146
247
 
147
- def traverse_postorder(node, result)
148
- return unless node
149
- traverse_postorder(node.left, result)
150
- traverse_postorder(node.right, result)
151
- result << node.val
152
- end
248
+ # Finds the node with the maximum value in a subtree.
249
+ #
250
+ # @param node [Node] the root of the subtree
251
+ # @return [Node] the node with the maximum value
252
+ def find_max(node)
253
+ node = node.right while node.right
254
+ node
255
+ end
256
+
257
+ # Recursively traverses the tree in inorder.
258
+ #
259
+ # @param node [Node, nil] the current node
260
+ # @param result [Array] the array to accumulate values
261
+ def traverse_inorder(node, result)
262
+ return unless node
263
+ traverse_inorder(node.left, result)
264
+ result << node.val
265
+ traverse_inorder(node.right, result)
266
+ end
267
+
268
+ # Recursively traverses the tree in preorder.
269
+ #
270
+ # @param node [Node, nil] the current node
271
+ # @param result [Array] the array to accumulate values
272
+ def traverse_preorder(node, result)
273
+ return unless node
274
+ result << node.val
275
+ traverse_preorder(node.left, result)
276
+ traverse_preorder(node.right, result)
277
+ end
278
+
279
+ # Recursively traverses the tree in postorder.
280
+ #
281
+ # @param node [Node, nil] the current node
282
+ # @param result [Array] the array to accumulate values
283
+ def traverse_postorder(node, result)
284
+ return unless node
285
+ traverse_postorder(node.left, result)
286
+ traverse_postorder(node.right, result)
287
+ result << node.val
153
288
  end
154
289
  end
@@ -1,57 +1,138 @@
1
- module DSA
2
- class Deque
3
- def initialize
4
- @deque = []
5
- @head = 0
6
- end
7
-
8
- def push_front(val)
9
- @deque.unshift(val)
10
- self
11
- end
12
-
13
- def push_back(val)
14
- @deque.push(val)
15
- self
16
- end
17
-
18
- def pop_front
19
- raise IndexError, "deque is empty" if empty?
20
- @deque.shift
21
- end
22
-
23
- def pop_back
24
- raise IndexError, "deque is empty" if empty?
25
- @deque.pop
26
- end
27
-
28
- def front
29
- raise IndexError, "deque is empty" if empty?
30
- @deque.first
31
- end
32
-
33
- def back
34
- raise IndexError, "deque is empty" if empty?
35
- @deque.last
36
- end
37
-
38
- def size
39
- @deque.size
40
- end
41
-
42
- def empty?
43
- @deque.empty?
44
- end
45
-
46
- def to_a
47
- @deque.dup
48
- end
49
-
50
- include Enumerable
51
-
52
- def each(&block)
53
- return enum_for(:each) unless block_given?
54
- @deque.each(&block)
55
- end
1
+ # DSA::Deque - Double-ended queue data structure.
2
+ #
3
+ # Supports efficient insertion and removal from both ends.
4
+ # Includes Enumerable for functional-style operations.
5
+ #
6
+ # @example
7
+ # dq = DSA::Deque.new
8
+ # dq.push_front(1).push_back(2)
9
+ # dq.pop_front # => 1
10
+ # dq.pop_back # => 2
11
+ #
12
+ # # Enumerable support
13
+ # dq.push_back(1).push_back(2).push_back(3)
14
+ # dq.map { |x| x * 2 } # => [2, 4, 6]
15
+ class DSA::Deque
16
+ # Initialize a new empty deque.
17
+ #
18
+ # @return [DSA::Deque] a new empty deque
19
+ def initialize
20
+ @deque = []
21
+ @head = 0
22
+ end
23
+
24
+ # Inserts a value at the front of the deque.
25
+ #
26
+ # @param val [Object] the value to insert
27
+ # @return [DSA::Deque] self for method chaining
28
+ # @example
29
+ # dq.push_front(1).push_front(2)
30
+ def push_front(val)
31
+ @deque.unshift(val)
32
+ self
33
+ end
34
+
35
+ # Inserts a value at the back of the deque.
36
+ #
37
+ # @param val [Object] the value to insert
38
+ # @return [DSA::Deque] self for method chaining
39
+ # @example
40
+ # dq.push_back(1).push_back(2)
41
+ def push_back(val)
42
+ @deque.push(val)
43
+ self
44
+ end
45
+
46
+ # Removes and returns the value at the front of the deque.
47
+ #
48
+ # @return [Object] the value at the front
49
+ # @raise [IndexError] if the deque is empty
50
+ # @example
51
+ # dq.push_back(1).push_back(2)
52
+ # dq.pop_front # => 1
53
+ def pop_front
54
+ raise IndexError, "deque is empty" if empty?
55
+ @deque.shift
56
+ end
57
+
58
+ # Removes and returns the value at the back of the deque.
59
+ #
60
+ # @return [Object] the value at the back
61
+ # @raise [IndexError] if the deque is empty
62
+ # @example
63
+ # dq.push_back(1).push_back(2)
64
+ # dq.pop_back # => 2
65
+ def pop_back
66
+ raise IndexError, "deque is empty" if empty?
67
+ @deque.pop
68
+ end
69
+
70
+ # Returns the value at the front of the deque without removing it.
71
+ #
72
+ # @return [Object] the value at the front
73
+ # @raise [IndexError] if the deque is empty
74
+ # @example
75
+ # dq.push_back(1).push_back(2)
76
+ # dq.front # => 1
77
+ def front
78
+ raise IndexError, "deque is empty" if empty?
79
+ @deque.first
80
+ end
81
+
82
+ # Returns the value at the back of the deque without removing it.
83
+ #
84
+ # @return [Object] the value at the back
85
+ # @raise [IndexError] if the deque is empty
86
+ # @example
87
+ # dq.push_back(1).push_back(2)
88
+ # dq.back # => 2
89
+ def back
90
+ raise IndexError, "deque is empty" if empty?
91
+ @deque.last
92
+ end
93
+
94
+ # Returns the number of elements in the deque.
95
+ #
96
+ # @return [Integer] the number of elements
97
+ # @example
98
+ # dq.push_back(1).push_back(2)
99
+ # dq.size # => 2
100
+ def size
101
+ @deque.size
102
+ end
103
+
104
+ # Checks if the deque is empty.
105
+ #
106
+ # @return [Boolean] true if the deque contains no elements
107
+ # @example
108
+ # dq = DSA::Deque.new
109
+ # dq.empty? # => true
110
+ def empty?
111
+ @deque.empty?
112
+ end
113
+
114
+ # Returns a defensive copy of the deque as an array.
115
+ #
116
+ # @return [Array] an array containing all elements (front to back order)
117
+ # @example
118
+ # dq.push_back(1).push_back(2).push_back(3)
119
+ # dq.to_a # => [1, 2, 3]
120
+ def to_a
121
+ @deque.dup
122
+ end
123
+
124
+ # Includes Enumerable for functional-style operations like map, select, etc.
125
+ include Enumerable
126
+
127
+ # Yields each element in the deque from front to back.
128
+ #
129
+ # @yield [val] yields each value to the block
130
+ # @return [Enumerator] if no block given
131
+ # @example
132
+ # dq.push_back(1).push_back(2).push_back(3)
133
+ # dq.each { |x| puts x } # prints 1, 2, 3
134
+ def each(&block)
135
+ return enum_for(:each) unless block_given?
136
+ @deque.each(&block)
56
137
  end
57
138
  end