ruby_binary_search 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e8f5f86b8bbbf1618e3d795de3f817bb753372c7f24005301385f7da40c720ea
4
+ data.tar.gz: 433b0100900bf1bd1846d10e785acf63c83505adfc91d5424f783360eb8504fd
5
+ SHA512:
6
+ metadata.gz: f3e41db0b009ae95f1f3ac5b12018a6df9f475ef7d483a5ba395a26c32a2f0a301297b5b12ee4815a803fc26ee25a3b6709fc3466a8b677082723e90e260569c
7
+ data.tar.gz: 5eb34f6900de0ffc7681d5a50989abf6182de46b93342f234f63716c1cabbcc7b2f58cf74bb67a5bd6de5ac9eacbb0cb002d514abca66b45a094e8efec765992
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ inherit_gem:
2
+ rubocop-rails_config:
3
+ - config/rails.yml
4
+
5
+ Style/ClassAndModuleChildren:
6
+ EnforcedStyle: nested
7
+
8
+ Lint/Debugger:
9
+ Enabled: true
10
+
11
+ Style/StringLiterals:
12
+ Enabled: true
13
+ EnforcedStyle: single_quotes
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-07-18
4
+
5
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 sebi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # BinarySearch 🌳🔍
2
+
3
+ Welcome to BinarySearch, a gem that brings the power of Red-Black Trees to your Ruby projects! 🚀
4
+
5
+ ## What is BinarySearch? 🤔
6
+
7
+ BinarySearch is a Ruby gem that implements a self-balancing binary search tree using the Red-Black Tree algorithm. It provides a list-like interface with blazing-fast search, insertion, and deletion operations. 💨
8
+
9
+ ## Why BinarySearch? 🌟
10
+
11
+ - **Efficiency**: Operations like search, insert, and delete are O(log n), making it much faster than standard arrays for large datasets. 📈
12
+ - **Self-balancing**: The Red-Black Tree ensures that the tree remains balanced, maintaining consistent performance even with frequent modifications. ⚖️
13
+ - **Sorted storage**: Elements are always stored in sorted order, making it perfect for applications that require sorted data. 📊
14
+ - **Flexible**: Supports common list operations like push, pop, shift, and unshift, as well as set operations like union and intersection. 🛠️
15
+
16
+ ## Installation 💻
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'binary_search'
22
+ ```
23
+
24
+ And then execute:
25
+ ```bash
26
+ bundle install
27
+ ```
28
+
29
+ ## Usage 🚀
30
+ Here's a quick example of how to use BinarySearch:
31
+
32
+ ```ruby
33
+ require 'binary_search'
34
+
35
+ # Create a new list
36
+ list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
37
+
38
+ # Get the sorted array
39
+ puts list.to_a # Output: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
40
+
41
+ # Check if a value exists
42
+ puts list.include?(4) # Output: true
43
+
44
+ # Remove all instances of a value
45
+ list.delete(1)
46
+ puts list.to_a # Output: [2, 3, 3, 4, 5, 5, 5, 6, 9]
47
+
48
+ # Add a new value
49
+ list.insert(7)
50
+ puts list.to_a # Output: [2, 3, 3, 4, 5, 5, 5, 6, 7, 9]
51
+
52
+ # Get the minimum and maximum values
53
+ puts list.min # Output: 2
54
+ puts list.max # Output: 9
55
+ ```
56
+ Custom objects
57
+ ```ruby
58
+ require 'binary_search'
59
+ class Person
60
+ attr_accessor :name, :age
61
+
62
+ def initialize(name, age)
63
+ @name = name
64
+ @age = age
65
+ end
66
+
67
+ def <=>(other)
68
+ @age <=> other.age
69
+ end
70
+ end
71
+
72
+
73
+ list = BinarySearch::List.new([
74
+ Person.new('Alice', 25),
75
+ Person.new('Bob', 30),
76
+ Person.new('Charlie', 20),
77
+ Person.new('David', 35)
78
+ ])
79
+
80
+ puts list.to_a.map(&:name) # Output: ["Charlie", "Alice", "Bob", "David"]
81
+ ```
82
+
83
+ ## Why is BinarySearch better than normal search? 🏆
84
+
85
+ - Speed: For large datasets, binary search is significantly faster than linear search. While a normal array search takes O(n) time, BinarySearch takes only O(log n) time. 🐇
86
+ - Always sorted: The list is always maintained in sorted order, which is useful for many applications and algorithms. 📑
87
+ - Efficient insertions and deletions: Unlike normal arrays where insertions and deletions can be O(n) operations, BinarySearch performs these in O(log n) time. 🔄
88
+ - Memory efficiency: Red-Black Trees are more memory-efficient than hash tables for certain types of data and operations. 💾
89
+ - Range queries: BinarySearch makes it easy to perform range queries efficiently, which can be cumbersome with normal arrays. 🎯
90
+
91
+ ## Development 🛠️
92
+
93
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
94
+ To install this gem onto your local machine, run `bundle exec rake install`.
95
+
96
+ ## Contributing 🤝
97
+
98
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sebyx07/binary_search. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
99
+
100
+ ## License 📄
101
+ The gem is available as open source under the terms of the MIT License.
102
+
103
+ ## Code of Conduct 🤓
104
+ Everyone interacting in the BinarySearch project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/lefthook.yml ADDED
@@ -0,0 +1,8 @@
1
+ pre-commit:
2
+ commands:
3
+ rubocop:
4
+ run: bundle exec rubocop -A
5
+ skip:
6
+ - merge
7
+ - rebase
8
+ stage_fixed: true
@@ -0,0 +1,526 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinarySearch
4
+ # A self-balancing binary search tree implementation of a list
5
+ #
6
+ # This class provides a list-like interface backed by a Red-Black Tree,
7
+ # which ensures O(log n) time complexity for most operations.
8
+ #
9
+ # @example Creating and using a BinarySearch::List
10
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
11
+ # list.to_a # => [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
12
+ # list.include?(4) # => true
13
+ # list.delete(1) # Removes all instances of 1
14
+ # list.to_a # => [2, 3, 3, 4, 5, 5, 5, 6, 9]
15
+ class List
16
+ include Enumerable
17
+
18
+ # Initialize a new BinarySearch::List
19
+ #
20
+ # @param from [Array] An array to initialize the list with
21
+ #
22
+ # @example Create an empty list
23
+ # list = BinarySearch::List.new
24
+ #
25
+ # @example Create a list from an array
26
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
27
+ def initialize(from = [])
28
+ @tree = BinarySearch::RedBlackTree.new
29
+ build_tree(from)
30
+ end
31
+
32
+ # Insert a value into the list
33
+ #
34
+ # This method inserts a value into the list, maintaining the sorted order.
35
+ # It has a time complexity of O(log n).
36
+ #
37
+ # @param value [Object] The value to insert
38
+ # @return [BinarySearch::List] The list object (for method chaining)
39
+ #
40
+ # @example Insert a value
41
+ # list.insert(4) # => #<BinarySearch::List: ...>
42
+ # list << 5 # => #<BinarySearch::List: ...>
43
+ def insert(value)
44
+ @tree.insert(value)
45
+ @size = nil
46
+ self
47
+ end
48
+ alias_method :append, :insert
49
+ alias_method :push, :insert
50
+ alias_method :<<, :insert
51
+
52
+ # Delete all occurrences of a value from the list
53
+ #
54
+ # This method removes all instances of the specified value from the list.
55
+ # It has a time complexity of O(log n) for each deletion.
56
+ #
57
+ # @param value [Object] The value to delete
58
+ # @return [Boolean] True if any elements were deleted, false otherwise
59
+ #
60
+ # @example Delete a value
61
+ # list = BinarySearch::List.new([1, 2, 2, 3, 4])
62
+ # list.delete(2) # => true
63
+ # list.to_a # => [1, 3, 4]
64
+ def delete(value)
65
+ deleted = false
66
+ while @tree.find(value)
67
+ @tree.remove(value)
68
+ @size -= 1 if @size
69
+ deleted = true
70
+ end
71
+ deleted
72
+ end
73
+
74
+ # Check if a value is in the list
75
+ #
76
+ # This method checks if the list contains the specified value.
77
+ # It has a time complexity of O(log n).
78
+ #
79
+ # @param value [Object] The value to check for
80
+ # @return [Boolean] True if the value is in the list, false otherwise
81
+ #
82
+ # @example Check for a value
83
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
84
+ # list.include?(3) # => true
85
+ # list.include?(6) # => false
86
+ def include?(value)
87
+ !@tree.find(value).nil?
88
+ end
89
+
90
+ # Convert the list to an array
91
+ #
92
+ # This method returns an array representation of the list in sorted order.
93
+ # It has a time complexity of O(n).
94
+ #
95
+ # @return [Array] An array representation of the list
96
+ #
97
+ # @example Convert to array
98
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
99
+ # list.to_a # => [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
100
+ def to_a
101
+ inorder_traversal(@tree.root)
102
+ end
103
+
104
+ # Get the size of the list
105
+ #
106
+ # This method returns the number of elements in the list.
107
+ # It has a time complexity of O(1) if the size is cached, or O(n) otherwise.
108
+ #
109
+ # @return [Integer] The number of elements in the list
110
+ #
111
+ # @example Get the size
112
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
113
+ # list.size # => 5
114
+ def size
115
+ @size ||= inorder_traversal(@tree.root).size
116
+ end
117
+
118
+ # Check if the list is empty
119
+ #
120
+ # This method checks if the list contains no elements.
121
+ # It has a time complexity of O(1).
122
+ #
123
+ # @return [Boolean] True if the list is empty, false otherwise
124
+ #
125
+ # @example Check if empty
126
+ # list = BinarySearch::List.new
127
+ # list.empty? # => true
128
+ # list.insert(1)
129
+ # list.empty? # => false
130
+ def empty?
131
+ @tree.root.nil?
132
+ end
133
+
134
+ # Access elements by index or range
135
+ #
136
+ # This method allows accessing elements by index or range, similar to Array.
137
+ # It has a time complexity of O(n) in the worst case.
138
+ #
139
+ # @param arg [Integer, Range] The index or range to access
140
+ # @return [Object, BinarySearch::List, nil] The element(s) at the given index or range, or nil if out of bounds
141
+ # @raise [ArgumentError] If the argument is not an Integer or Range
142
+ #
143
+ # @example Access by index
144
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
145
+ # list[2] # => 3
146
+ #
147
+ # @example Access by range
148
+ # list[1..3] # => #<BinarySearch::List: [2, 3, 4]>
149
+ def [](arg)
150
+ case arg
151
+ when Integer
152
+ return nil if arg < 0 || arg >= size
153
+ to_a[arg]
154
+ when Range
155
+ start = arg.begin
156
+ finish = arg.end
157
+ start = size + start if start < 0
158
+ finish = size + finish if finish < 0
159
+ finish -= 1 if arg.exclude_end?
160
+
161
+ return nil if start < 0 || start >= size
162
+
163
+ result = []
164
+ (start..finish).each do |i|
165
+ break if i >= size
166
+ result << to_a[i]
167
+ end
168
+ self.class.new(result)
169
+ else
170
+ raise ArgumentError, "Invalid argument type: #{arg.class}"
171
+ end
172
+ end
173
+
174
+ # Iterate over each element in the list
175
+ #
176
+ # This method yields each element in the list to the given block.
177
+ # It has a time complexity of O(n).
178
+ #
179
+ # @yield [Object] Gives each element in the list to the block
180
+ # @return [Enumerator] If no block is given
181
+ #
182
+ # @example Iterate over elements
183
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
184
+ # list.each { |x| puts x } # Prints each number on a new line
185
+ def each(&block)
186
+ to_a.each(&block)
187
+ end
188
+
189
+ # Clear all elements from the list
190
+ #
191
+ # This method removes all elements from the list, leaving it empty.
192
+ # It has a time complexity of O(1).
193
+ #
194
+ # @return [BinarySearch::List] The empty list object
195
+ #
196
+ # @example Clear the list
197
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
198
+ # list.clear # => #<BinarySearch::List: []>
199
+ # list.empty? # => true
200
+ def clear
201
+ @tree = BinarySearch::RedBlackTree.new
202
+ @size = 0
203
+ self
204
+ end
205
+
206
+ # Get the first element in the list
207
+ #
208
+ # This method returns the smallest element in the list.
209
+ # It has a time complexity of O(log n).
210
+ #
211
+ # @return [Object, nil] The first element, or nil if the list is empty
212
+ #
213
+ # @example Get the first element
214
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
215
+ # list.first # => 1
216
+ def first
217
+ return nil if empty?
218
+ leftmost_node(@tree.root).key
219
+ end
220
+
221
+ # Get the last element in the list
222
+ #
223
+ # This method returns the largest element in the list.
224
+ # It has a time complexity of O(log n).
225
+ #
226
+ # @return [Object, nil] The last element, or nil if the list is empty
227
+ #
228
+ # @example Get the last element
229
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
230
+ # list.last # => 9
231
+ def last
232
+ return nil if empty?
233
+ rightmost_node(@tree.root).key
234
+ end
235
+
236
+ # Remove and return the last element in the list
237
+ #
238
+ # This method removes and returns the largest element in the list.
239
+ # It has a time complexity of O(log n).
240
+ #
241
+ # @return [Object, nil] The last element, or nil if the list is empty
242
+ #
243
+ # @example Remove the last element
244
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
245
+ # list.pop # => 5
246
+ # list.to_a # => [1, 2, 3, 4]
247
+ def pop
248
+ return nil if empty?
249
+ last_value = last
250
+ @tree.remove(last_value)
251
+ @size -= 1 if @size
252
+ last_value
253
+ end
254
+
255
+ # Remove and return the first element in the list
256
+ #
257
+ # This method removes and returns the smallest element in the list.
258
+ # It has a time complexity of O(log n).
259
+ #
260
+ # @return [Object, nil] The first element, or nil if the list is empty
261
+ #
262
+ # @example Remove the first element
263
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
264
+ # list.shift # => 1
265
+ # list.to_a # => [2, 3, 4, 5]
266
+ def shift
267
+ return nil if empty?
268
+ first_value = first
269
+ @tree.remove(first_value)
270
+ @size -= 1 if @size
271
+ first_value
272
+ end
273
+
274
+ # Insert a value at the beginning of the list
275
+ #
276
+ # This method inserts a value at the beginning of the list.
277
+ # It has a time complexity of O(log n).
278
+ #
279
+ # @param value [Object] The value to insert
280
+ # @return [BinarySearch::List] The list object (for method chaining)
281
+ #
282
+ # @example Insert at the beginning
283
+ # list = BinarySearch::List.new([2, 3, 4, 5])
284
+ # list.unshift(1) # => #<BinarySearch::List: [1, 2, 3, 4, 5]>
285
+ def unshift(value)
286
+ insert(value)
287
+ self
288
+ end
289
+
290
+ # Get the maximum value in the list
291
+ #
292
+ # This method returns the largest element in the list.
293
+ # It has a time complexity of O(log n).
294
+ #
295
+ # @return [Object, nil] The maximum value, or nil if the list is empty
296
+ #
297
+ # @example Get the maximum value
298
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
299
+ # list.max # => 9
300
+ def max
301
+ last
302
+ end
303
+
304
+ # Get the minimum value in the list
305
+ #
306
+ # This method returns the smallest element in the list.
307
+ # It has a time complexity of O(log n).
308
+ #
309
+ # @return [Object, nil] The minimum value, or nil if the list is empty
310
+ #
311
+ # @example Get the minimum value
312
+ # list = BinarySearch::List.new([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])
313
+ # list.min # => 1
314
+ def min
315
+ first
316
+ end
317
+
318
+ # Calculate the sum of all elements in the list
319
+ #
320
+ # This method returns the sum of all elements in the list.
321
+ # It has a time complexity of O(n).
322
+ #
323
+ # @return [Numeric] The sum of all elements
324
+ #
325
+ # @example Calculate the sum
326
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
327
+ # list.sum # => 15
328
+ def sum
329
+ to_a.sum
330
+ end
331
+
332
+ # Find the first element that satisfies the given condition
333
+ #
334
+ # This method returns the first element for which the given block returns true.
335
+ # It has a time complexity of O(n) in the worst case.
336
+ #
337
+ # @yield [Object] Gives each element to the block
338
+ # @return [Object, nil] The first element for which the block returns true, or nil if none found
339
+ #
340
+ # @example Find an element
341
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
342
+ # list.find { |x| x > 3 } # => 4
343
+ def find
344
+ each { |element| return element if yield(element) }
345
+ nil
346
+ end
347
+
348
+ # Create a new list with duplicate elements removed
349
+ #
350
+ # This method returns a new list with all duplicate elements removed.
351
+ # It has a time complexity of O(n log n).
352
+ #
353
+ # @return [BinarySearch::List] A new list with unique elements
354
+ #
355
+ # @example Remove duplicates
356
+ # list = BinarySearch::List.new([1, 2, 2, 3, 3, 3, 4, 5])
357
+ # list.uniq.to_a # => [1, 2, 3, 4, 5]
358
+ def uniq
359
+ self.class.new(to_a.uniq)
360
+ end
361
+
362
+ # Concatenate two lists
363
+ #
364
+ # This method returns a new list containing all elements from both lists.
365
+ # It has a time complexity of O(n + m), where n and m are the sizes of the lists.
366
+ #
367
+ # @param other [BinarySearch::List] The list to concatenate
368
+ # @return [BinarySearch::List] A new list containing elements from both lists
369
+ #
370
+ # @example Concatenate lists
371
+ # list1 = BinarySearch::List.new([1, 2, 3])
372
+ # list2 = BinarySearch::List.new([4, 5, 6])
373
+ # (list1 + list2).to_a # => [1, 2, 3, 4, 5, 6]
374
+ def +(other)
375
+ self.class.new(to_a + other.to_a)
376
+ end
377
+
378
+ # Compute the difference between two lists
379
+ #
380
+ # This method returns a new list containing elements that are in the current list
381
+ # but not in the other list, taking into account the number of occurrences of each element.
382
+ # It has a time complexity of O(n log n + m log m), where n and m are the sizes of the lists.
383
+ #
384
+ # @param other [BinarySearch::List] The list to subtract
385
+ # @return [BinarySearch::List] A new list containing elements in this list but not in the other
386
+ #
387
+ # @example Compute the difference
388
+ # list1 = BinarySearch::List.new([1, 2, 2, 3, 4, 5])
389
+ # list2 = BinarySearch::List.new([2, 4, 6])
390
+ # (list1 - list2).to_a # => [1, 2, 3, 5]
391
+ def -(other)
392
+ result = self.class.new
393
+ self_counts = Hash.new(0)
394
+ other_counts = Hash.new(0)
395
+
396
+ self.each { |item| self_counts[item] += 1 }
397
+ other.each { |item| other_counts[item] += 1 }
398
+
399
+ self_counts.each do |item, count|
400
+ diff = count - other_counts[item]
401
+ diff.times { result.insert(item) } if diff > 0
402
+ end
403
+
404
+ result
405
+ end
406
+
407
+ # Compute the intersection of two lists
408
+ #
409
+ # This method returns a new list containing elements common to both lists,
410
+ # taking into account the number of occurrences of each element.
411
+ # It has a time complexity of O(n log n + m log m), where n and m are the sizes of the lists.
412
+ #
413
+ # @param other [BinarySearch::List] The list to intersect with
414
+ # @return [BinarySearch::List] A new list containing elements common to both lists
415
+ #
416
+ # @example Compute the intersection
417
+ # list1 = BinarySearch::List.new([1, 2, 2, 3, 4, 5])
418
+ # list2 = BinarySearch::List.new([2, 2, 4, 6])
419
+ # (list1 & list2).to_a # => [2, 2, 4]
420
+ def &(other)
421
+ self.class.new(to_a & other.to_a)
422
+ end
423
+
424
+ # Compute the union of two lists
425
+ #
426
+ # This method returns a new list containing unique elements from both lists.
427
+ # It has a time complexity of O(n log n + m log m), where n and m are the sizes of the lists.
428
+ #
429
+ # @param other [BinarySearch::List] The list to unite with
430
+ # @return [BinarySearch::List] A new list containing unique elements from both lists
431
+ #
432
+ # @example Compute the union
433
+ # list1 = BinarySearch::List.new([1, 2, 3, 4])
434
+ # list2 = BinarySearch::List.new([3, 4, 5, 6])
435
+ # (list1 | list2).to_a # => [1, 2, 3, 4, 5, 6]
436
+ def |(other)
437
+ self.class.new(to_a | other.to_a)
438
+ end
439
+
440
+ # Compare two lists for equality
441
+ #
442
+ # This method checks if two lists have the same elements in the same order.
443
+ # It has a time complexity of O(n), where n is the size of the lists.
444
+ #
445
+ # @param other [Object] The object to compare with
446
+ # @return [Boolean] True if the lists are equal, false otherwise
447
+ #
448
+ # @example Compare lists
449
+ # list1 = BinarySearch::List.new([1, 2, 3, 4, 5])
450
+ # list2 = BinarySearch::List.new([1, 2, 3, 4, 5])
451
+ # list3 = BinarySearch::List.new([5, 4, 3, 2, 1])
452
+ # list1 == list2 # => true
453
+ # list1 == list3 # => false
454
+ def ==(other)
455
+ return false unless other.is_a?(BinarySearch::List)
456
+ return true if self.equal?(other)
457
+ self.to_a == other.to_a
458
+ end
459
+
460
+ # Provide a string representation of the list
461
+ #
462
+ # This method returns a concise string representation of the list,
463
+ # showing the class name and the size of the list.
464
+ #
465
+ # @return [String] A string representation of the list
466
+ #
467
+ # @example Inspect the list
468
+ # list = BinarySearch::List.new([1, 2, 3, 4, 5])
469
+ # list.inspect # => "#<BinarySearch::List: (5 elements)>"
470
+ def inspect
471
+ "#<#{self.class}: (#{size} elements)>"
472
+ end
473
+
474
+ private
475
+ # Build the tree from an initial list
476
+ #
477
+ # This method inserts each element from the initial list into the tree.
478
+ # It has a time complexity of O(n log n), where n is the size of the initial list.
479
+ #
480
+ # @param list [Array] The initial list of elements
481
+ # @return [void]
482
+ def build_tree(list)
483
+ list.each { |item| @tree.insert(item) }
484
+ @size = list.size
485
+ end
486
+
487
+ # Perform an inorder traversal of the tree
488
+ #
489
+ # This method traverses the tree in-order and returns an array of the elements.
490
+ # It has a time complexity of O(n), where n is the number of nodes in the tree.
491
+ #
492
+ # @param node [BinarySearch::RedBlackTree::Node] The current node
493
+ # @param result [Array] The result array
494
+ # @return [Array] An array of elements in sorted order
495
+ def inorder_traversal(node, result = [])
496
+ return result if node.nil?
497
+ inorder_traversal(node.left, result)
498
+ result << node.key
499
+ inorder_traversal(node.right, result)
500
+ end
501
+
502
+ # Find the leftmost node in a subtree
503
+ #
504
+ # This method finds the node with the smallest key in the given subtree.
505
+ # It has a time complexity of O(log n) in a balanced tree.
506
+ #
507
+ # @param node [BinarySearch::RedBlackTree::Node] The root of the subtree
508
+ # @return [BinarySearch::RedBlackTree::Node] The leftmost node
509
+ def leftmost_node(node)
510
+ return node if node.left.nil?
511
+ leftmost_node(node.left)
512
+ end
513
+
514
+ # Find the rightmost node in a subtree
515
+ #
516
+ # This method finds the node with the largest key in the given subtree.
517
+ # It has a time complexity of O(log n) in a balanced tree.
518
+ #
519
+ # @param node [BinarySearch::RedBlackTree::Node] The root of the subtree
520
+ # @return [BinarySearch::RedBlackTree::Node] The rightmost node
521
+ def rightmost_node(node)
522
+ return node if node.right.nil?
523
+ rightmost_node(node.right)
524
+ end
525
+ end
526
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinarySearch
4
+ class RedBlackTree
5
+ # Represents a node in the Red-Black Tree
6
+ #
7
+ # A node contains a key, color, references to its left and right children,
8
+ # and a reference to its parent. The color is used to maintain the balance
9
+ # properties of the Red-Black Tree.
10
+ Node = Struct.new('Node', :key, :color, :left, :right, :parent) do
11
+ # Creates a new Node
12
+ #
13
+ # @param key [Comparable] The key stored in the node
14
+ # @param color [Symbol] The color of the node (:red or :black)
15
+ # @param left [Node, nil] The left child of the node
16
+ # @param right [Node, nil] The right child of the node
17
+ # @param parent [Node, nil] The parent of the node
18
+ def initialize(key, color = :red, left = nil, right = nil, parent = nil)
19
+ super(key, color, left, right, parent)
20
+ end
21
+
22
+ # Checks if the node is black
23
+ #
24
+ # @return [Boolean] true if the node is black, false otherwise
25
+ def black?
26
+ color == :black
27
+ end
28
+
29
+ # Checks if the node is red
30
+ #
31
+ # @return [Boolean] true if the node is red, false otherwise
32
+ def red?
33
+ color == :red
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,385 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinarySearch
4
+ # Implements a Red-Black Tree, a self-balancing binary search tree
5
+ #
6
+ # A Red-Black Tree is a type of self-balancing binary search tree that maintains
7
+ # balance through the use of node colors (red and black) and a set of properties:
8
+ #
9
+ # 1. Every node is either red or black.
10
+ # 2. The root is black.
11
+ # 3. Every leaf (NIL) is black.
12
+ # 4. If a node is red, then both its children are black.
13
+ # 5. For each node, all simple paths from the node to descendant leaves contain the
14
+ # same number of black nodes.
15
+ #
16
+ # These properties ensure that the tree remains approximately balanced during
17
+ # insertions and deletions, guaranteeing O(log n) time complexity for basic
18
+ # operations like search, insert, and delete.
19
+ class RedBlackTree
20
+ # @return [Node, nil] The root node of the tree
21
+ attr_reader :root
22
+
23
+ # Initializes an empty Red-Black Tree
24
+ def initialize
25
+ @root = nil
26
+ end
27
+
28
+ # Inserts a new key into the tree
29
+ #
30
+ # The insertion process involves:
31
+ # 1. Performing a standard BST insertion
32
+ # 2. Coloring the new node red
33
+ # 3. Rebalancing the tree to maintain Red-Black properties
34
+ #
35
+ # @param key [Comparable] The key to insert
36
+ # @return [void]
37
+ def insert(key)
38
+ new_node = Node.new(key)
39
+ if @root.nil?
40
+ @root = new_node
41
+ @root.color = :black
42
+ else
43
+ current = @root
44
+ parent = nil
45
+ while current
46
+ parent = current
47
+ comparison = key <=> current.key
48
+ case comparison
49
+ when -1
50
+ current = current.left
51
+ when 1
52
+ current = current.right
53
+ else
54
+ # For duplicates, we'll add to the right
55
+ current = current.right
56
+ end
57
+ end
58
+ new_node.parent = parent
59
+ comparison = key <=> parent.key
60
+ if comparison <= 0
61
+ parent.left = new_node
62
+ else
63
+ parent.right = new_node
64
+ end
65
+ fix_insert(new_node)
66
+ end
67
+ end
68
+
69
+ # Removes a key from the tree
70
+ #
71
+ # The removal process involves:
72
+ # 1. Finding the node to be removed
73
+ # 2. If the node has two children, replacing it with its successor
74
+ # 3. Removing the node (or its successor)
75
+ # 4. Rebalancing the tree if the removed node was black
76
+ #
77
+ # @param key [Comparable] The key to remove
78
+ # @return [Node, nil] The removed node, or nil if the key was not found
79
+ def remove(key)
80
+ node = find(key)
81
+ return nil unless node
82
+
83
+ remove_node(node)
84
+ end
85
+
86
+ # Updates a key in the tree
87
+ #
88
+ # This operation ensures that the tree structure remains valid after updating a key.
89
+ # It's implemented as a removal of the old key followed by an insertion of the new key.
90
+ #
91
+ # @param old_key [Comparable] The key to update
92
+ # @param new_key [Comparable] The new key value
93
+ # @return [Boolean, nil] true if updated, false if new_key already exists, nil if old_key not found
94
+ def update(old_key, new_key)
95
+ node = find(old_key)
96
+ return nil unless node
97
+ return false if find(new_key)
98
+
99
+ node.key = new_key
100
+ true
101
+ end
102
+
103
+ # Finds a node with the given key
104
+ #
105
+ # This method performs a standard binary search tree lookup.
106
+ #
107
+ # @param key [Comparable] The key to find
108
+ # @return [Node, nil] The node with the given key, or nil if not found
109
+ def find(key)
110
+ current = @root
111
+ while current
112
+ comparison = key <=> current.key
113
+ return current if comparison == 0
114
+ current = comparison < 0 ? current.left : current.right
115
+ end
116
+ nil
117
+ end
118
+
119
+ private
120
+ # Fixes the tree after insertion to maintain Red-Black properties
121
+ #
122
+ # This method is called after every insertion to ensure that the Red-Black
123
+ # properties are maintained. It performs color changes and rotations as necessary.
124
+ #
125
+ # @param node [Node] The newly inserted node
126
+ # @return [void]
127
+ def fix_insert(node)
128
+ while node.parent&.red?
129
+ if node.parent == node.parent.parent&.left
130
+ uncle = node.parent.parent&.right
131
+ if uncle&.red?
132
+ node.parent.color = :black
133
+ uncle.color = :black
134
+ node.parent.parent.color = :red
135
+ node = node.parent.parent
136
+ else
137
+ if node == node.parent.right
138
+ node = node.parent
139
+ left_rotate(node)
140
+ end
141
+ node.parent.color = :black
142
+ node.parent.parent.color = :red
143
+ right_rotate(node.parent.parent)
144
+ end
145
+ else
146
+ uncle = node.parent.parent&.left
147
+ if uncle&.red?
148
+ node.parent.color = :black
149
+ uncle.color = :black
150
+ node.parent.parent.color = :red
151
+ node = node.parent.parent
152
+ else
153
+ if node == node.parent.left
154
+ node = node.parent
155
+ right_rotate(node)
156
+ end
157
+ node.parent.color = :black
158
+ node.parent.parent.color = :red
159
+ left_rotate(node.parent.parent)
160
+ end
161
+ end
162
+ end
163
+ @root.color = :black
164
+ end
165
+
166
+ # Performs a left rotation on the given node
167
+ #
168
+ # A left rotation is a local operation in a search tree that changes the structure
169
+ # of the tree while preserving the search tree properties of the nodes involved.
170
+ #
171
+ # @param x [Node] The node to rotate
172
+ # @return [void]
173
+ def left_rotate(x)
174
+ y = x.right
175
+ x.right = y.left
176
+ y.left.parent = x if y.left
177
+ y.parent = x.parent
178
+ if x.parent.nil?
179
+ @root = y
180
+ elsif x == x.parent.left
181
+ x.parent.left = y
182
+ else
183
+ x.parent.right = y
184
+ end
185
+ y.left = x
186
+ x.parent = y
187
+ end
188
+
189
+ # Performs a right rotation on the given node
190
+ #
191
+ # A right rotation is the mirror operation of a left rotation.
192
+ #
193
+ # @param y [Node] The node to rotate
194
+ # @return [void]
195
+ def right_rotate(y)
196
+ x = y.left
197
+ y.left = x.right
198
+ x.right.parent = y if x.right
199
+ x.parent = y.parent
200
+ if y.parent.nil?
201
+ @root = x
202
+ elsif y == y.parent.right
203
+ y.parent.right = x
204
+ else
205
+ y.parent.left = x
206
+ end
207
+ x.right = y
208
+ y.parent = x
209
+ end
210
+
211
+ # Removes a node from the tree
212
+ #
213
+ # This method handles the actual removal of a node and calls the necessary
214
+ # fix-up routines to maintain the Red-Black properties.
215
+ #
216
+ # @param node [Node] The node to remove
217
+ # @return [void]
218
+ def remove_node(node)
219
+ if node.left && node.right
220
+ successor = minimum(node.right)
221
+ node.key = successor.key
222
+ remove_node(successor)
223
+ else
224
+ child = node.left || node.right
225
+ if node.black?
226
+ if child&.red?
227
+ child.color = :black
228
+ else
229
+ delete_case1(node)
230
+ end
231
+ end
232
+ replace_node(node, child)
233
+ end
234
+ @root.color = :black if @root
235
+ end
236
+
237
+ # Finds the minimum node in a subtree
238
+ #
239
+ # This method is used in the deletion process to find the successor of a node.
240
+ #
241
+ # @param node [Node] The root of the subtree
242
+ # @return [Node] The minimum node
243
+ def minimum(node)
244
+ node = node.left while node.left
245
+ node
246
+ end
247
+
248
+ # Replaces one node with another in the tree
249
+ #
250
+ # This method is a helper for the removal process, updating the necessary
251
+ # parent-child relationships.
252
+ #
253
+ # @param old [Node] The node to be replaced
254
+ # @param new [Node, nil] The replacement node
255
+ # @return [void]
256
+ def replace_node(old, new)
257
+ if old.parent.nil?
258
+ @root = new
259
+ elsif old == old.parent.left
260
+ old.parent.left = new
261
+ else
262
+ old.parent.right = new
263
+ end
264
+ new.parent = old.parent if new
265
+ end
266
+
267
+ # Handles case 1 of the delete fixup
268
+ #
269
+ # The delete fixup cases are part of the algorithm to maintain Red-Black
270
+ # properties after a black node is removed from the tree.
271
+ #
272
+ # @param node [Node] The node being processed
273
+ # @return [void]
274
+ def delete_case1(node)
275
+ delete_case2(node) if node.parent
276
+ end
277
+
278
+ # Handles case 2 of the delete fixup
279
+ #
280
+ # @param node [Node] The node being processed
281
+ # @return [void]
282
+ def delete_case2(node)
283
+ sibling = get_sibling(node)
284
+ return if sibling.nil? || node.parent.nil?
285
+ if sibling.red?
286
+ node.parent.color = :red
287
+ sibling.color = :black
288
+ if node == node.parent.left
289
+ left_rotate(node.parent)
290
+ else
291
+ right_rotate(node.parent)
292
+ end
293
+ end
294
+ delete_case3(node)
295
+ end
296
+
297
+ # Handles case 3 of the delete fixup
298
+ #
299
+ # @param node [Node] The node being processed
300
+ # @return [void]
301
+ def delete_case3(node)
302
+ sibling = get_sibling(node)
303
+ return if sibling.nil? || node.parent.nil?
304
+ if node.parent.black? && sibling.black? &&
305
+ (!sibling.left || sibling.left.black?) &&
306
+ (!sibling.right || sibling.right.black?)
307
+ sibling.color = :red
308
+ delete_case1(node.parent)
309
+ else
310
+ delete_case4(node)
311
+ end
312
+ end
313
+
314
+ # Handles case 4 of the delete fixup
315
+ #
316
+ # @param node [Node] The node being processed
317
+ # @return [void]
318
+ def delete_case4(node)
319
+ sibling = get_sibling(node)
320
+ return if sibling.nil? || node.parent.nil?
321
+ if node.parent.red? && sibling.black? &&
322
+ (!sibling.left || sibling.left.black?) &&
323
+ (!sibling.right || sibling.right.black?)
324
+ sibling.color = :red
325
+ node.parent.color = :black
326
+ else
327
+ delete_case5(node)
328
+ end
329
+ end
330
+
331
+ # Handles case 5 of the delete fixup
332
+ #
333
+ # @param node [Node] The node being processed
334
+ # @return [void]
335
+ def delete_case5(node)
336
+ sibling = get_sibling(node)
337
+ return if sibling.nil? || node.parent.nil?
338
+ if sibling.black?
339
+ if node == node.parent.left &&
340
+ (!sibling.right || sibling.right.black?) &&
341
+ sibling.left&.red?
342
+ sibling.color = :red
343
+ sibling.left.color = :black
344
+ right_rotate(sibling)
345
+ elsif node == node.parent.right &&
346
+ (!sibling.left || sibling.left.black?) &&
347
+ sibling.right&.red?
348
+ sibling.color = :red
349
+ sibling.right.color = :black
350
+ left_rotate(sibling)
351
+ end
352
+ end
353
+ delete_case6(node)
354
+ end
355
+
356
+ # Handles case 6 of the delete fixup
357
+ #
358
+ # @param node [Node] The node being processed
359
+ # @return [void]
360
+ def delete_case6(node)
361
+ sibling = get_sibling(node)
362
+ return if sibling.nil? || node.parent.nil?
363
+ sibling.color = node.parent.color
364
+ node.parent.color = :black
365
+ if node == node.parent.left
366
+ sibling.right.color = :black if sibling.right
367
+ left_rotate(node.parent)
368
+ else
369
+ sibling.left.color = :black if sibling.left
370
+ right_rotate(node.parent)
371
+ end
372
+ end
373
+
374
+ # Gets the sibling of a node
375
+ #
376
+ # This helper method is used in the delete fixup process.
377
+ #
378
+ # @param node [Node] The node whose sibling to find
379
+ # @return [Node, nil] The sibling node, or nil if there is no sibling
380
+ def get_sibling(node)
381
+ return nil if node.parent.nil?
382
+ node == node.parent.left ? node.parent.right : node.parent.left
383
+ end
384
+ end
385
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinarySearch
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'singleton'
5
+
6
+ Dir[File.join(__dir__, 'binary_search', '**', '*.rb')].each { |file| require file }
7
+
8
+ module BinarySearch
9
+ class Error < StandardError; end
10
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_binary_search
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - sebi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Binary search list implemented in ruby using red-black self-balancing
14
+ tree
15
+ email:
16
+ - gore.sebyx@yahoo.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - CHANGELOG.md
24
+ - CODE_OF_CONDUCT.md
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - lefthook.yml
29
+ - lib/binary_search/list.rb
30
+ - lib/binary_search/red_black_tree.rb
31
+ - lib/binary_search/red_black_tree/node.rb
32
+ - lib/binary_search/version.rb
33
+ - lib/ruby_binary_search.rb
34
+ homepage: https://github.com/sebyx07/ruby-binary-search
35
+ licenses:
36
+ - MIT
37
+ metadata:
38
+ allowed_push_host: https://rubygems.org
39
+ homepage_uri: https://github.com/sebyx07/ruby-binary-search
40
+ source_code_uri: https://github.com/sebyx07/ruby-binary-search
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.0.0
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 3.5.11
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Binary search list implemented in ruby using red-black self-balancing tree
60
+ test_files: []