dsa-ruby 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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +245 -0
- data/lib/dsa-ruby/binary_search_tree.rb +154 -0
- data/lib/dsa-ruby/deque.rb +57 -0
- data/lib/dsa-ruby/heap.rb +145 -0
- data/lib/dsa-ruby/linked_list.rb +249 -0
- data/lib/dsa-ruby/priority_queue.rb +43 -0
- data/lib/dsa-ruby/queue.rb +34 -0
- data/lib/dsa-ruby/stack.rb +34 -0
- data/lib/dsa-ruby/trie.rb +70 -0
- data/lib/dsa-ruby/union_find.rb +50 -0
- data/lib/dsa-ruby/version.rb +3 -0
- data/lib/dsa-ruby.rb +10 -0
- metadata +70 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6d48c162c54e6f3b5a72e0ec6c5bfb01ea194db9aa01edd8b3acf22ec8e65d2a
|
|
4
|
+
data.tar.gz: 90dec8d0903d522bd53c1928f1b4bfe4e3183c51ac0cd6c6c2089864eeaf31ed
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ffc6d6ee8215956588a61c477fbf92c8a441d43ded58525f758086c07433389616c9f538bac40d2de30f113d184beec0cfb155d236cc7ddb08da815b9d1aa75f
|
|
7
|
+
data.tar.gz: 700cbc183e14b7fe0884c52b43a49c686530e6276deea50a3eaf6b7df9e65dfd23b51ccc21c38d5af38bed62496f59e1314c43c59a20d0587344d495606406c3
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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,245 @@
|
|
|
1
|
+
# dsa-ruby
|
|
2
|
+
|
|
3
|
+
Data structures for coding interviews in Ruby. Provides the missing structures
|
|
4
|
+
that Ruby's stdlib doesn't include but are essential for technical interviews.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
gem "dsa-ruby"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or install directly:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
gem install dsa-ruby
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
require "dsa-ruby"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### MinHeap / MaxHeap
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
heap = DSA::MinHeap.new
|
|
28
|
+
heap.push(5, 3, 7, 1)
|
|
29
|
+
heap.pop # => 1
|
|
30
|
+
heap.peek # => 3
|
|
31
|
+
|
|
32
|
+
max_heap = DSA::MaxHeap.new([5, 3, 7, 1])
|
|
33
|
+
max_heap.pop # => 7
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### PriorityQueue
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
pq = DSA::PriorityQueue.new(type: :min)
|
|
40
|
+
pq.push("task_a", 3)
|
|
41
|
+
pq.push("task_b", 1)
|
|
42
|
+
pq.push("task_c", 2)
|
|
43
|
+
|
|
44
|
+
pq.pop # => "task_b" (lowest priority first)
|
|
45
|
+
|
|
46
|
+
pq = DSA::PriorityQueue.new(type: :max)
|
|
47
|
+
pq.push("task_a", 3)
|
|
48
|
+
pq.push("task_b", 1)
|
|
49
|
+
pq.pop # => "task_a" (highest priority first)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Deque
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
dq = DSA::Deque.new
|
|
56
|
+
dq.push_front(1).push_back(2)
|
|
57
|
+
dq.pop_front # => 1
|
|
58
|
+
dq.pop_back # => 2
|
|
59
|
+
|
|
60
|
+
# Enumerable support
|
|
61
|
+
dq.push_back(1, 2, 3)
|
|
62
|
+
dq.map { |x| x * 2 } # => [2, 4, 6]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Trie
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
trie = DSA::Trie.new
|
|
69
|
+
trie.insert("apple")
|
|
70
|
+
trie.search("apple") # => true
|
|
71
|
+
trie.search("app") # => false
|
|
72
|
+
trie.starts_with("app") # => true
|
|
73
|
+
trie.delete("apple")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### UnionFind
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
uf = DSA::UnionFind.new(10)
|
|
80
|
+
uf.union(1, 2)
|
|
81
|
+
uf.union(2, 3)
|
|
82
|
+
uf.connected?(1, 3) # => true
|
|
83
|
+
uf.count # => 8 (started with 10, merged 2 pairs)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### LinkedList
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# Singly Linked List
|
|
90
|
+
list = DSA::LinkedList::Singly.new
|
|
91
|
+
list.push(1).push(2).push(3)
|
|
92
|
+
list.pop # => 3
|
|
93
|
+
list.to_a # => [2, 1]
|
|
94
|
+
list.reverse!
|
|
95
|
+
list.to_a # => [1, 2]
|
|
96
|
+
|
|
97
|
+
# Doubly Linked List
|
|
98
|
+
dll = DSA::LinkedList::Doubly.new
|
|
99
|
+
dll.push_back(1).push_back(2).push_back(3)
|
|
100
|
+
dll.pop_front # => 1
|
|
101
|
+
dll.pop_back # => 3
|
|
102
|
+
dll.to_a # => [2]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Stack
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
stack = DSA::Stack.new
|
|
109
|
+
stack.push(1).push(2).push(3)
|
|
110
|
+
stack.pop # => 3
|
|
111
|
+
stack.peek # => 2
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Queue
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
queue = DSA::Queue.new
|
|
118
|
+
queue.enqueue("a").enqueue("b").enqueue("c")
|
|
119
|
+
queue.dequeue # => "a"
|
|
120
|
+
queue.peek # => "b"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### BinarySearchTree
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
bst = DSA::BinarySearchTree.new
|
|
127
|
+
bst.insert(5).insert(3).insert(7).insert(1).insert(4)
|
|
128
|
+
bst.search(3) # => true
|
|
129
|
+
bst.min # => 1
|
|
130
|
+
bst.max # => 7
|
|
131
|
+
bst.inorder # => [1, 3, 4, 5, 7]
|
|
132
|
+
bst.preorder # => [5, 3, 1, 4, 7]
|
|
133
|
+
bst.postorder # => [1, 4, 3, 7, 5]
|
|
134
|
+
bst.delete(3)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## API Reference
|
|
138
|
+
|
|
139
|
+
### Stack
|
|
140
|
+
|
|
141
|
+
- `#push(val)` — add to top (O(1))
|
|
142
|
+
- `#pop` — remove and return top (O(1))
|
|
143
|
+
- `#peek` — return top without removing (O(1))
|
|
144
|
+
|
|
145
|
+
### Queue
|
|
146
|
+
|
|
147
|
+
- `#enqueue(val)` — add to back
|
|
148
|
+
- `#dequeue` — remove and return front
|
|
149
|
+
- `#peek` — return front without removing
|
|
150
|
+
|
|
151
|
+
### BinarySearchTree
|
|
152
|
+
|
|
153
|
+
- `#insert(val)` — insert value (O(log n) avg)
|
|
154
|
+
- `#search(val)` — check if value exists (boolean)
|
|
155
|
+
- `#delete(val)` — remove value, returns true if deleted
|
|
156
|
+
- `#min` / `#max` — return minimum/maximum value
|
|
157
|
+
- `#inorder` / `#preorder` / `#postorder` — traversal arrays
|
|
158
|
+
|
|
159
|
+
### Common Methods
|
|
160
|
+
|
|
161
|
+
All structures support:
|
|
162
|
+
|
|
163
|
+
- `#size` — number of elements
|
|
164
|
+
- `#empty?` — whether the structure is empty
|
|
165
|
+
- `#to_a` — returns a defensive copy as an array
|
|
166
|
+
|
|
167
|
+
### Heap (`MinHeap`, `MaxHeap`)
|
|
168
|
+
|
|
169
|
+
- `#push(val)` — insert element (O(log n))
|
|
170
|
+
- `#pop` — remove and return extremum (O(log n))
|
|
171
|
+
- `#peek` — return extremum without removing (O(1))
|
|
172
|
+
|
|
173
|
+
### PriorityQueue
|
|
174
|
+
|
|
175
|
+
- `#push(item, priority)` — insert with priority
|
|
176
|
+
- `#pop` — remove and return highest/lowest priority item
|
|
177
|
+
- `#peek` — return top item without removing
|
|
178
|
+
- `#priority_peek` — return top item's priority value
|
|
179
|
+
|
|
180
|
+
### Deque
|
|
181
|
+
|
|
182
|
+
- `#push_front(val)` / `#push_back(val)` — insert at either end
|
|
183
|
+
- `#pop_front` / `#pop_back` — remove from either end
|
|
184
|
+
- `#front` / `#back` — peek at either end
|
|
185
|
+
- Includes `Enumerable`
|
|
186
|
+
|
|
187
|
+
### Trie
|
|
188
|
+
|
|
189
|
+
- `#insert(word)` — insert a word
|
|
190
|
+
- `#search(word)` — exact word lookup
|
|
191
|
+
- `#starts_with(prefix)` — prefix lookup
|
|
192
|
+
- `#delete(word)` — remove a word
|
|
193
|
+
|
|
194
|
+
### UnionFind
|
|
195
|
+
|
|
196
|
+
- `#find(x)` — find root with path compression
|
|
197
|
+
- `#union(x, y)` — merge sets, returns true if merged
|
|
198
|
+
- `#connected?(x, y)` — check if in same set
|
|
199
|
+
- `#count` — number of disjoint sets
|
|
200
|
+
|
|
201
|
+
### LinkedList (Singly / Doubly)
|
|
202
|
+
|
|
203
|
+
- `#push(val)` / `#push_front(val)` / `#push_back(val)` — insert
|
|
204
|
+
- `#pop` / `#pop_front` / `#pop_back` — remove
|
|
205
|
+
- `#delete(val)` — remove by value
|
|
206
|
+
- `#find(val)` — find node by value
|
|
207
|
+
- `#peek` / `#front` / `#back` — peek
|
|
208
|
+
- `#reverse!` — reverse in-place (Singly only)
|
|
209
|
+
- Includes `Enumerable`
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
bundle install
|
|
215
|
+
bundle exec rspec
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Release
|
|
219
|
+
|
|
220
|
+
### Using the release script (recommended)
|
|
221
|
+
|
|
222
|
+
Bump version, build gem, push to RubyGems, and create GitHub Release:
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
./release.sh patch # 0.1.0 -> 0.1.1
|
|
226
|
+
./release.sh minor # 0.1.0 -> 0.2.0
|
|
227
|
+
./release.sh major # 0.1.0 -> 1.0.0
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Requires: `gh` CLI authenticated, `GEM_HOST_API_KEY` environment variable set.
|
|
231
|
+
|
|
232
|
+
### Using Makefile
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
make build # Build the gem
|
|
236
|
+
make test # Run tests
|
|
237
|
+
make install # Build and install locally
|
|
238
|
+
make publish # Build and push to rubygems.org
|
|
239
|
+
make release # Full release workflow
|
|
240
|
+
make help # Show all commands
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class BinarySearchTree
|
|
3
|
+
Node = Struct.new(:val, :left, :right, keyword_init: true)
|
|
4
|
+
|
|
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
|
|
19
|
+
|
|
20
|
+
def delete(val)
|
|
21
|
+
@root, deleted = delete_recursive(@root, val)
|
|
22
|
+
@size -= 1 if deleted
|
|
23
|
+
deleted
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def min
|
|
27
|
+
raise IndexError, "tree is empty" if empty?
|
|
28
|
+
find_min(@root).val
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def max
|
|
32
|
+
raise IndexError, "tree is empty" if empty?
|
|
33
|
+
find_max(@root).val
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def inorder
|
|
37
|
+
return [] if empty?
|
|
38
|
+
result = []
|
|
39
|
+
traverse_inorder(@root, result)
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def preorder
|
|
44
|
+
return [] if empty?
|
|
45
|
+
result = []
|
|
46
|
+
traverse_preorder(@root, result)
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def postorder
|
|
51
|
+
return [] if empty?
|
|
52
|
+
result = []
|
|
53
|
+
traverse_postorder(@root, result)
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def size
|
|
58
|
+
@size
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def empty?
|
|
62
|
+
@size == 0
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_a
|
|
66
|
+
inorder
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def insert_recursive(node, val)
|
|
72
|
+
if node.nil?
|
|
73
|
+
return [Node.new(val: val, left: nil, right: nil), true]
|
|
74
|
+
end
|
|
75
|
+
|
|
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
|
|
83
|
+
|
|
84
|
+
[node, added]
|
|
85
|
+
end
|
|
86
|
+
|
|
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
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def delete_recursive(node, val)
|
|
99
|
+
return [nil, false] unless node
|
|
100
|
+
|
|
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
|
|
109
|
+
|
|
110
|
+
[node, deleted]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def delete_node(node)
|
|
114
|
+
return node.right unless node.left
|
|
115
|
+
return node.left unless node.right
|
|
116
|
+
|
|
117
|
+
successor = find_min(node.right)
|
|
118
|
+
node.val = successor.val
|
|
119
|
+
node.right, _ = delete_recursive(node.right, successor.val)
|
|
120
|
+
node
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def find_min(node)
|
|
124
|
+
node = node.left while node.left
|
|
125
|
+
node
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def find_max(node)
|
|
129
|
+
node = node.right while node.right
|
|
130
|
+
node
|
|
131
|
+
end
|
|
132
|
+
|
|
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
|
|
139
|
+
|
|
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
|
|
146
|
+
|
|
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
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class MinHeap
|
|
3
|
+
def initialize(elements = [])
|
|
4
|
+
@elements = []
|
|
5
|
+
elements.each { |e| push(e) }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def push(val)
|
|
9
|
+
@elements << val
|
|
10
|
+
sift_up(@elements.size - 1)
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def pop
|
|
15
|
+
raise IndexError, "heap is empty" if empty?
|
|
16
|
+
|
|
17
|
+
swap(0, @elements.size - 1)
|
|
18
|
+
min = @elements.pop
|
|
19
|
+
sift_down(0)
|
|
20
|
+
min
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def peek
|
|
24
|
+
raise IndexError, "heap is empty" if empty?
|
|
25
|
+
@elements[0]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def size
|
|
29
|
+
@elements.size
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def empty?
|
|
33
|
+
@elements.empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_a
|
|
37
|
+
@elements.dup
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def sift_up(i)
|
|
43
|
+
while i > 0
|
|
44
|
+
parent = (i - 1) / 2
|
|
45
|
+
break if (@elements[parent] <=> @elements[i]) <= 0
|
|
46
|
+
|
|
47
|
+
swap(parent, i)
|
|
48
|
+
i = parent
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
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
|
|
58
|
+
|
|
59
|
+
smallest = left if left < n && (@elements[left] <=> @elements[smallest]) < 0
|
|
60
|
+
smallest = right if right < n && (@elements[right] <=> @elements[smallest]) < 0
|
|
61
|
+
|
|
62
|
+
break if smallest == i
|
|
63
|
+
|
|
64
|
+
swap(i, smallest)
|
|
65
|
+
i = smallest
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def swap(i, j)
|
|
70
|
+
@elements[i], @elements[j] = @elements[j], @elements[i]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class MaxHeap
|
|
75
|
+
def initialize(elements = [])
|
|
76
|
+
@elements = []
|
|
77
|
+
elements.each { |e| push(e) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def push(val)
|
|
81
|
+
@elements << val
|
|
82
|
+
sift_up(@elements.size - 1)
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def pop
|
|
87
|
+
raise IndexError, "heap is empty" if empty?
|
|
88
|
+
|
|
89
|
+
swap(0, @elements.size - 1)
|
|
90
|
+
max = @elements.pop
|
|
91
|
+
sift_down(0)
|
|
92
|
+
max
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def peek
|
|
96
|
+
raise IndexError, "heap is empty" if empty?
|
|
97
|
+
@elements[0]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def size
|
|
101
|
+
@elements.size
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def empty?
|
|
105
|
+
@elements.empty?
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def to_a
|
|
109
|
+
@elements.dup
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def sift_up(i)
|
|
115
|
+
while i > 0
|
|
116
|
+
parent = (i - 1) / 2
|
|
117
|
+
break if (@elements[parent] <=> @elements[i]) >= 0
|
|
118
|
+
|
|
119
|
+
swap(parent, i)
|
|
120
|
+
i = parent
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
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
|
|
130
|
+
|
|
131
|
+
largest = left if left < n && (@elements[left] <=> @elements[largest]) > 0
|
|
132
|
+
largest = right if right < n && (@elements[right] <=> @elements[largest]) > 0
|
|
133
|
+
|
|
134
|
+
break if largest == i
|
|
135
|
+
|
|
136
|
+
swap(i, largest)
|
|
137
|
+
i = largest
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def swap(i, j)
|
|
142
|
+
@elements[i], @elements[j] = @elements[j], @elements[i]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
module LinkedList
|
|
3
|
+
class Node
|
|
4
|
+
attr_accessor :val, :next
|
|
5
|
+
|
|
6
|
+
def initialize(val = 0, nxt = nil)
|
|
7
|
+
@val = val
|
|
8
|
+
@next = nxt
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class DoublyNode
|
|
13
|
+
attr_accessor :val, :next, :prev
|
|
14
|
+
|
|
15
|
+
def initialize(val = 0, nxt = nil, prev = nil)
|
|
16
|
+
@val = val
|
|
17
|
+
@next = nxt
|
|
18
|
+
@prev = prev
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Singly
|
|
23
|
+
def initialize
|
|
24
|
+
@head = nil
|
|
25
|
+
@size = 0
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def push(val)
|
|
29
|
+
@head = Node.new(val, @head)
|
|
30
|
+
@size += 1
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def append(val)
|
|
35
|
+
new_node = Node.new(val)
|
|
36
|
+
if @head.nil?
|
|
37
|
+
@head = new_node
|
|
38
|
+
else
|
|
39
|
+
node = @head
|
|
40
|
+
node = node.next while node.next
|
|
41
|
+
node.next = new_node
|
|
42
|
+
end
|
|
43
|
+
@size += 1
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def pop
|
|
48
|
+
raise IndexError, "list is empty" unless @head
|
|
49
|
+
|
|
50
|
+
val = @head.val
|
|
51
|
+
@head = @head.next
|
|
52
|
+
@size -= 1
|
|
53
|
+
val
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def peek
|
|
57
|
+
raise IndexError, "list is empty" unless @head
|
|
58
|
+
@head.val
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def delete(val)
|
|
62
|
+
return false unless @head
|
|
63
|
+
|
|
64
|
+
if @head.val == val
|
|
65
|
+
@head = @head.next
|
|
66
|
+
@size -= 1
|
|
67
|
+
return true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
node = @head
|
|
71
|
+
while node.next
|
|
72
|
+
if node.next.val == val
|
|
73
|
+
node.next = node.next.next
|
|
74
|
+
@size -= 1
|
|
75
|
+
return true
|
|
76
|
+
end
|
|
77
|
+
node = node.next
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
false
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def find(val)
|
|
84
|
+
node = @head
|
|
85
|
+
while node
|
|
86
|
+
return node if node.val == val
|
|
87
|
+
node = node.next
|
|
88
|
+
end
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def reverse!
|
|
93
|
+
return self unless @head
|
|
94
|
+
|
|
95
|
+
prev = nil
|
|
96
|
+
curr = @head
|
|
97
|
+
while curr
|
|
98
|
+
nxt = curr.next
|
|
99
|
+
curr.next = prev
|
|
100
|
+
prev = curr
|
|
101
|
+
curr = nxt
|
|
102
|
+
end
|
|
103
|
+
@head = prev
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def size
|
|
108
|
+
@size
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def empty?
|
|
112
|
+
@size == 0
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def to_a
|
|
116
|
+
result = []
|
|
117
|
+
node = @head
|
|
118
|
+
while node
|
|
119
|
+
result << node.val
|
|
120
|
+
node = node.next
|
|
121
|
+
end
|
|
122
|
+
result
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
include Enumerable
|
|
126
|
+
|
|
127
|
+
def each(&block)
|
|
128
|
+
return enum_for(:each) unless block_given?
|
|
129
|
+
node = @head
|
|
130
|
+
while node
|
|
131
|
+
yield node.val
|
|
132
|
+
node = node.next
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class Doubly
|
|
138
|
+
def initialize
|
|
139
|
+
@head = nil
|
|
140
|
+
@tail = nil
|
|
141
|
+
@size = 0
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def push_front(val)
|
|
145
|
+
node = DoublyNode.new(val, @head, nil)
|
|
146
|
+
@head.prev = node if @head
|
|
147
|
+
@head = node
|
|
148
|
+
@tail ||= node
|
|
149
|
+
@size += 1
|
|
150
|
+
self
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def push_back(val)
|
|
154
|
+
node = DoublyNode.new(val, nil, @tail)
|
|
155
|
+
@tail.next = node if @tail
|
|
156
|
+
@tail = node
|
|
157
|
+
@head ||= node
|
|
158
|
+
@size += 1
|
|
159
|
+
self
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def pop_front
|
|
163
|
+
raise IndexError, "list is empty" unless @head
|
|
164
|
+
|
|
165
|
+
val = @head.val
|
|
166
|
+
@head = @head.next
|
|
167
|
+
@head.prev = nil if @head
|
|
168
|
+
@tail = nil unless @head
|
|
169
|
+
@size -= 1
|
|
170
|
+
val
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def pop_back
|
|
174
|
+
raise IndexError, "list is empty" unless @tail
|
|
175
|
+
|
|
176
|
+
val = @tail.val
|
|
177
|
+
@tail = @tail.prev
|
|
178
|
+
@tail.next = nil if @tail
|
|
179
|
+
@head = nil unless @tail
|
|
180
|
+
@size -= 1
|
|
181
|
+
val
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def front
|
|
185
|
+
raise IndexError, "list is empty" unless @head
|
|
186
|
+
@head.val
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def back
|
|
190
|
+
raise IndexError, "list is empty" unless @tail
|
|
191
|
+
@tail.val
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def delete(val)
|
|
195
|
+
node = @head
|
|
196
|
+
while node
|
|
197
|
+
if node.val == val
|
|
198
|
+
node.prev.next = node.next if node.prev
|
|
199
|
+
node.next.prev = node.prev if node.next
|
|
200
|
+
@head = node.next if node == @head
|
|
201
|
+
@tail = node.prev if node == @tail
|
|
202
|
+
@size -= 1
|
|
203
|
+
return true
|
|
204
|
+
end
|
|
205
|
+
node = node.next
|
|
206
|
+
end
|
|
207
|
+
false
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def find(val)
|
|
211
|
+
node = @head
|
|
212
|
+
while node
|
|
213
|
+
return node if node.val == val
|
|
214
|
+
node = node.next
|
|
215
|
+
end
|
|
216
|
+
nil
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def size
|
|
220
|
+
@size
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def empty?
|
|
224
|
+
@size == 0
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def to_a
|
|
228
|
+
result = []
|
|
229
|
+
node = @head
|
|
230
|
+
while node
|
|
231
|
+
result << node.val
|
|
232
|
+
node = node.next
|
|
233
|
+
end
|
|
234
|
+
result
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
include Enumerable
|
|
238
|
+
|
|
239
|
+
def each(&block)
|
|
240
|
+
return enum_for(:each) unless block_given?
|
|
241
|
+
node = @head
|
|
242
|
+
while node
|
|
243
|
+
yield node.val
|
|
244
|
+
node = node.next
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class PriorityQueue
|
|
3
|
+
def initialize(type: :min)
|
|
4
|
+
@heap = type == :min ? MinHeap.new : MaxHeap.new
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def push(item, priority)
|
|
8
|
+
@counter ||= 0
|
|
9
|
+
@heap.push([priority, @counter, item])
|
|
10
|
+
@counter += 1
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def pop
|
|
15
|
+
raise IndexError, "priority queue is empty" if empty?
|
|
16
|
+
_, _, item = @heap.pop
|
|
17
|
+
item
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def peek
|
|
21
|
+
raise IndexError, "priority queue is empty" if empty?
|
|
22
|
+
_, _, item = @heap.peek
|
|
23
|
+
item
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def priority_peek
|
|
27
|
+
raise IndexError, "priority queue is empty" if empty?
|
|
28
|
+
@heap.peek[0]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def size
|
|
32
|
+
@heap.size
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def empty?
|
|
36
|
+
@heap.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
attr_reader :heap
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class Queue
|
|
3
|
+
def initialize
|
|
4
|
+
@elements = []
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def enqueue(val)
|
|
8
|
+
@elements.push(val)
|
|
9
|
+
self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def dequeue
|
|
13
|
+
raise IndexError, "queue is empty" if empty?
|
|
14
|
+
@elements.shift
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def peek
|
|
18
|
+
raise IndexError, "queue is empty" if empty?
|
|
19
|
+
@elements.first
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def size
|
|
23
|
+
@elements.size
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def empty?
|
|
27
|
+
@elements.empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_a
|
|
31
|
+
@elements.dup
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class Stack
|
|
3
|
+
def initialize
|
|
4
|
+
@elements = []
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def push(val)
|
|
8
|
+
@elements.push(val)
|
|
9
|
+
self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def pop
|
|
13
|
+
raise IndexError, "stack is empty" if empty?
|
|
14
|
+
@elements.pop
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def peek
|
|
18
|
+
raise IndexError, "stack is empty" if empty?
|
|
19
|
+
@elements.last
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def size
|
|
23
|
+
@elements.size
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def empty?
|
|
27
|
+
@elements.empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_a
|
|
31
|
+
@elements.dup
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class Trie
|
|
3
|
+
Node = Struct.new(:children, :word_end, keyword_init: true) do
|
|
4
|
+
def initialize
|
|
5
|
+
super(children: {}, word_end: false)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@root = Node.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def insert(word)
|
|
14
|
+
node = @root
|
|
15
|
+
word.each_char do |char|
|
|
16
|
+
node.children[char] ||= Node.new
|
|
17
|
+
node = node.children[char]
|
|
18
|
+
end
|
|
19
|
+
node.word_end = true
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def search(word)
|
|
24
|
+
node = find_node(word)
|
|
25
|
+
!!(node && node.word_end)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def starts_with(prefix)
|
|
29
|
+
!!find_node(prefix)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def delete(word)
|
|
33
|
+
delete_recursive(@root, word, 0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def find_node(word)
|
|
39
|
+
node = @root
|
|
40
|
+
word.each_char do |char|
|
|
41
|
+
return nil unless node.children[char]
|
|
42
|
+
node = node.children[char]
|
|
43
|
+
end
|
|
44
|
+
node
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def delete_recursive(node, word, index)
|
|
48
|
+
return false unless node
|
|
49
|
+
|
|
50
|
+
if index == word.length
|
|
51
|
+
return false unless node.word_end
|
|
52
|
+
|
|
53
|
+
node.word_end = false
|
|
54
|
+
return node.children.empty?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
char = word[index]
|
|
58
|
+
return false unless node.children[char]
|
|
59
|
+
|
|
60
|
+
should_delete = delete_recursive(node.children[char], word, index + 1)
|
|
61
|
+
|
|
62
|
+
if should_delete
|
|
63
|
+
node.children.delete(char)
|
|
64
|
+
return !node.word_end && node.children.empty?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module DSA
|
|
2
|
+
class UnionFind
|
|
3
|
+
def initialize(n)
|
|
4
|
+
@parent = (0...n).to_a
|
|
5
|
+
@rank = Array.new(n, 0)
|
|
6
|
+
@count = n
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def find(x)
|
|
10
|
+
raise IndexError, "index out of bounds" if x < 0 || x >= @parent.size
|
|
11
|
+
|
|
12
|
+
@parent[x] = find(@parent[x]) if @parent[x] != x
|
|
13
|
+
@parent[x]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def union(x, y)
|
|
17
|
+
raise IndexError, "index out of bounds" if x < 0 || x >= @parent.size
|
|
18
|
+
raise IndexError, "index out of bounds" if y < 0 || y >= @parent.size
|
|
19
|
+
|
|
20
|
+
root_x = find(x)
|
|
21
|
+
root_y = find(y)
|
|
22
|
+
|
|
23
|
+
return false if root_x == root_y
|
|
24
|
+
|
|
25
|
+
if @rank[root_x] < @rank[root_y]
|
|
26
|
+
@parent[root_x] = root_y
|
|
27
|
+
elsif @rank[root_x] > @rank[root_y]
|
|
28
|
+
@parent[root_y] = root_x
|
|
29
|
+
else
|
|
30
|
+
@parent[root_y] = root_x
|
|
31
|
+
@rank[root_x] += 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@count -= 1
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def connected?(x, y)
|
|
39
|
+
find(x) == find(y)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def count
|
|
43
|
+
@count
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def size
|
|
47
|
+
@parent.size
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/dsa-ruby.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require_relative "dsa-ruby/version"
|
|
2
|
+
require_relative "dsa-ruby/stack"
|
|
3
|
+
require_relative "dsa-ruby/queue"
|
|
4
|
+
require_relative "dsa-ruby/binary_search_tree"
|
|
5
|
+
require_relative "dsa-ruby/heap"
|
|
6
|
+
require_relative "dsa-ruby/priority_queue"
|
|
7
|
+
require_relative "dsa-ruby/deque"
|
|
8
|
+
require_relative "dsa-ruby/trie"
|
|
9
|
+
require_relative "dsa-ruby/union_find"
|
|
10
|
+
require_relative "dsa-ruby/linked_list"
|
metadata
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: dsa-ruby
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- You
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rspec
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '3.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '3.0'
|
|
26
|
+
description: Provides MinHeap, MaxHeap, PriorityQueue, Deque, Trie, UnionFind, and
|
|
27
|
+
LinkedList — data structures commonly needed for coding interviews but missing from
|
|
28
|
+
Ruby's stdlib.
|
|
29
|
+
email:
|
|
30
|
+
- you@example.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- LICENSE.txt
|
|
36
|
+
- README.md
|
|
37
|
+
- lib/dsa-ruby.rb
|
|
38
|
+
- lib/dsa-ruby/binary_search_tree.rb
|
|
39
|
+
- lib/dsa-ruby/deque.rb
|
|
40
|
+
- lib/dsa-ruby/heap.rb
|
|
41
|
+
- lib/dsa-ruby/linked_list.rb
|
|
42
|
+
- lib/dsa-ruby/priority_queue.rb
|
|
43
|
+
- lib/dsa-ruby/queue.rb
|
|
44
|
+
- lib/dsa-ruby/stack.rb
|
|
45
|
+
- lib/dsa-ruby/trie.rb
|
|
46
|
+
- lib/dsa-ruby/union_find.rb
|
|
47
|
+
- lib/dsa-ruby/version.rb
|
|
48
|
+
homepage: https://github.com/you/dsa-ruby
|
|
49
|
+
licenses:
|
|
50
|
+
- MIT
|
|
51
|
+
metadata:
|
|
52
|
+
allowed_push_host: https://rubygems.org
|
|
53
|
+
rdoc_options: []
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 3.0.0
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
requirements: []
|
|
67
|
+
rubygems_version: 4.0.9
|
|
68
|
+
specification_version: 4
|
|
69
|
+
summary: Data structures for coding interviews in Ruby
|
|
70
|
+
test_files: []
|