data-struct 0.0.9 → 0.0.10
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 +4 -4
- data/lib/bin_heap.rb +93 -0
- data/lib/binary_search_tree.rb +174 -0
- data/lib/data-struct.rb +10 -15
- data/lib/{single_linked_list.rb → singly_linked_list.rb} +5 -5
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9afef8d83b99609e9b5b7198f2c74d6f8f60df31
|
4
|
+
data.tar.gz: 7e8812d7bf78a9678feb71371149ba352f197f35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd8f19a9af0523dfe9176108d549882aedf4610cde4bcaeadf730254392a2bbabae73c4da7c123a8f5f041fb723d02aaef87935c79ec0121c36d833ac9328e7e
|
7
|
+
data.tar.gz: 7100ff534e0f5dd748c03ed0d8a865c6fc15754f5b0e5141a24a3aea47875c93adc3abd0e3ef09d6202c39744d280d35faac1db874126e258a0d67efd68cb7db
|
data/lib/bin_heap.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
class BinHeap
|
2
|
+
attr_reader :store
|
3
|
+
|
4
|
+
def initialize(&prc)
|
5
|
+
@store = Array.new
|
6
|
+
@prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
7
|
+
end
|
8
|
+
|
9
|
+
def insert(value)
|
10
|
+
@store << value
|
11
|
+
self.class.heapify_up(@store, @store.length - 1, &@prc)
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract
|
15
|
+
raise "Heap is empty" if @store.empty?
|
16
|
+
|
17
|
+
top_priority = @store[0]
|
18
|
+
|
19
|
+
if @store.length > 1
|
20
|
+
@store[0] = @store.pop
|
21
|
+
self.class.heapify_down(@store, 0, &@prc)
|
22
|
+
else
|
23
|
+
@store.pop
|
24
|
+
end
|
25
|
+
|
26
|
+
top_priority
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
attr_writer :prc, :store
|
31
|
+
|
32
|
+
public
|
33
|
+
def self.heapify_up(store, child_idx, &prc)
|
34
|
+
prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
35
|
+
return store if child_idx == 0
|
36
|
+
|
37
|
+
parent_idx = find_parent(child_idx)
|
38
|
+
|
39
|
+
if prc.call(store[child_idx], store[parent_idx]) == -1
|
40
|
+
store[child_idx], store[parent_idx] = store[parent_idx], store[child_idx]
|
41
|
+
heapify_up(store, parent_idx, &prc)
|
42
|
+
else
|
43
|
+
return store
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.heapify_down(store, parent_idx, &prc)
|
48
|
+
prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
49
|
+
|
50
|
+
children_idx = find_children(store.length - 1, parent_idx)
|
51
|
+
|
52
|
+
c0_idx = children_idx[0]
|
53
|
+
c1_idx = children_idx[1]
|
54
|
+
|
55
|
+
children = []
|
56
|
+
children << store[c0_idx] if c0_idx
|
57
|
+
children << store[c1_idx] if c1_idx
|
58
|
+
|
59
|
+
parent = store[parent_idx]
|
60
|
+
|
61
|
+
#When the parent index is where it's supposed to be
|
62
|
+
if children.all? { |child| prc.call(child, parent) >= 0}
|
63
|
+
return store
|
64
|
+
end
|
65
|
+
|
66
|
+
if store.length == 1
|
67
|
+
swap_idx = c0_idx
|
68
|
+
else
|
69
|
+
swap_idx = prc.call(children[0], children[1]) == 1 ? c1_idx : c0_idx
|
70
|
+
end
|
71
|
+
|
72
|
+
store[swap_idx], store[parent_idx] = parent, store[swap_idx]
|
73
|
+
|
74
|
+
heapify_down(store, swap_idx, &prc)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.find_children(last_idx, parent_idx)
|
78
|
+
child1 = (parent_idx * 2) + 1
|
79
|
+
child2 = (parent_idx * 2) + 2
|
80
|
+
|
81
|
+
|
82
|
+
return [child1, child2].select{ |idx| idx <= last_idx }
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.find_parent(child_idx)
|
86
|
+
if child_idx == 0
|
87
|
+
raise "Out of bounds"
|
88
|
+
else
|
89
|
+
return (child_idx - 1) / 2
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,174 @@
|
|
1
|
+
class BinarySearchTree
|
2
|
+
attr_accessor :value, :parent, :left, :right, :depth, :balance
|
3
|
+
|
4
|
+
def initialize(value)
|
5
|
+
@value = value
|
6
|
+
@parent = EmptyNode.new
|
7
|
+
@left = EmptyNode.new
|
8
|
+
@right = EmptyNode.new
|
9
|
+
@depth = 0
|
10
|
+
@balance = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_array(array)
|
14
|
+
BinarySearchTree.new(array.first).tap do |tree|
|
15
|
+
array.each { |val| tree.insert(val) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def children
|
20
|
+
count = 0
|
21
|
+
count += 1 if left.class == BinarySearchTree
|
22
|
+
count += 1 if right.class == BinarySearchTree
|
23
|
+
|
24
|
+
count
|
25
|
+
end
|
26
|
+
|
27
|
+
def left_rotate
|
28
|
+
# A B
|
29
|
+
# / \ / \
|
30
|
+
# D B <=> A' C
|
31
|
+
# / \ / \
|
32
|
+
# E C D E
|
33
|
+
#
|
34
|
+
|
35
|
+
# KW: still need to refactor this, unnecessary creation of new node
|
36
|
+
# reassign parent
|
37
|
+
new_left = BinarySearchTree.new(value) # A'
|
38
|
+
|
39
|
+
new_left.left = left # A' -> D
|
40
|
+
left.parent = new_left # D <- A'
|
41
|
+
new_left.right = right.left # A' -> E
|
42
|
+
right.left.parent = new_left # E <- A'
|
43
|
+
new_left.parent = self # A' <- A
|
44
|
+
|
45
|
+
new_right = right.right # C
|
46
|
+
new_right.parent = self # C <- A
|
47
|
+
|
48
|
+
@value, @left, @right = right.value, new_left, new_right
|
49
|
+
end
|
50
|
+
|
51
|
+
def right_rotate
|
52
|
+
new_right = BinarySearchTree.new(value)
|
53
|
+
|
54
|
+
new_right.right = right
|
55
|
+
right.parent = new_right
|
56
|
+
new_right.left = left.right
|
57
|
+
left.right.parent = new_right
|
58
|
+
new_right.parent = self
|
59
|
+
|
60
|
+
new_left = left.left
|
61
|
+
new_left.parent = self
|
62
|
+
|
63
|
+
@value, @left, @right = left.value, new_left, new_right
|
64
|
+
end
|
65
|
+
|
66
|
+
def insert(val)
|
67
|
+
case val <=> value
|
68
|
+
when -1 then insert_left(val)
|
69
|
+
when 1 then insert_right(val)
|
70
|
+
when 0 then false
|
71
|
+
end
|
72
|
+
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
" { #{value} : #{left.inspect} | #{right.inspect} } "
|
78
|
+
end
|
79
|
+
|
80
|
+
def include?(val)
|
81
|
+
case val <=> value
|
82
|
+
when -1 then left.include?(val)
|
83
|
+
when 1 then right.include?(val)
|
84
|
+
when 0 then true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_a
|
89
|
+
left.to_a + [value] + right.to_a
|
90
|
+
end
|
91
|
+
|
92
|
+
def recalculate_depth_and_balance
|
93
|
+
@depth = ([left.depth, right.depth].max + 1)
|
94
|
+
@balance = right.depth - left.depth
|
95
|
+
# p "RECALULATED DEPTH = #{depth}: BALANCE = #{balance}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def update_depth_and_balance
|
99
|
+
# recursively update depth and balance, rebalances if needed and crawls up the tree
|
100
|
+
recalculate_depth_and_balance
|
101
|
+
rebalance if ([-2, 2].include?(@balance))
|
102
|
+
# p "RECALULATED #{self.inspect} DEPTH = #{depth}: BALANCE = #{balance}"
|
103
|
+
parent.update_depth_and_balance
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def insert_left(val)
|
109
|
+
if (left.class != EmptyNode)
|
110
|
+
left.insert(val)
|
111
|
+
else
|
112
|
+
new_node = BinarySearchTree.new(val)
|
113
|
+
self.left, new_node.parent = new_node, self
|
114
|
+
new_node.update_depth_and_balance
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def insert_right(val)
|
119
|
+
if (right.class != EmptyNode)
|
120
|
+
right.insert(val)
|
121
|
+
else
|
122
|
+
new_node = BinarySearchTree.new(val)
|
123
|
+
self.right, new_node.parent = new_node, self
|
124
|
+
new_node.update_depth_and_balance
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def rebalance
|
129
|
+
if @balance == -2
|
130
|
+
left.left_rotate if left.balance == 1
|
131
|
+
right_rotate
|
132
|
+
elsif @balance == 2
|
133
|
+
right.right_rotate if right.balance == -1
|
134
|
+
left_rotate
|
135
|
+
end
|
136
|
+
right.recalculate_depth_and_balance
|
137
|
+
left.recalculate_depth_and_balance
|
138
|
+
recalculate_depth_and_balance
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class EmptyNode
|
143
|
+
attr_reader :depth
|
144
|
+
attr_accessor :parent
|
145
|
+
|
146
|
+
def initialize
|
147
|
+
@depth = 0
|
148
|
+
@parent = nil
|
149
|
+
end
|
150
|
+
|
151
|
+
def include?(*)
|
152
|
+
false
|
153
|
+
end
|
154
|
+
|
155
|
+
def insert(*)
|
156
|
+
false
|
157
|
+
end
|
158
|
+
|
159
|
+
def inspect
|
160
|
+
"{}"
|
161
|
+
end
|
162
|
+
|
163
|
+
def recalculate_depth_and_balance
|
164
|
+
true
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_a
|
168
|
+
[]
|
169
|
+
end
|
170
|
+
|
171
|
+
def update_depth_and_balance
|
172
|
+
true
|
173
|
+
end
|
174
|
+
end
|
data/lib/data-struct.rb
CHANGED
@@ -1,22 +1,17 @@
|
|
1
|
-
|
2
|
-
# require_relative "doubly_linked_list"
|
1
|
+
require_relative "binary_search_tree"
|
3
2
|
require_relative "dynamic_array"
|
3
|
+
# require_relative "doubly_linked_list"
|
4
4
|
require_relative "max_stack"
|
5
5
|
require_relative "min_max_stack"
|
6
6
|
# require_relative "min_max_queue"
|
7
|
-
|
7
|
+
|
8
|
+
require_relative "singly_linked_list"
|
8
9
|
# require_relative "stack_queue"
|
9
10
|
|
10
11
|
module DataStruct
|
11
|
-
class
|
12
|
-
end
|
13
|
-
|
14
|
-
class
|
15
|
-
end
|
16
|
-
|
17
|
-
class MinMaxStack < MinMaxStack
|
18
|
-
end
|
19
|
-
|
20
|
-
class SingleLinkedList < SingleLinkedList
|
21
|
-
end
|
22
|
-
end
|
12
|
+
class BinarySearchTree < BinarySearchTree; end
|
13
|
+
class DynamicArray < DynamicArray; end
|
14
|
+
class MaxStack < MaxStack; end
|
15
|
+
class MinMaxStack < MinMaxStack; end
|
16
|
+
class SinglyLinkedList < SinglyLinkedList; end
|
17
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# singly linked list
|
2
|
-
class
|
2
|
+
class SinglyLinkedList
|
3
3
|
attr_reader :sentinel
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@sentinel =
|
6
|
+
@sentinel = SinglyLink.new(nil)
|
7
7
|
end
|
8
8
|
|
9
9
|
def pop
|
@@ -15,7 +15,7 @@ class SingleLinkedList
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def push(val)
|
18
|
-
link =
|
18
|
+
link = SinglyLink.new(val)
|
19
19
|
_, last_link = walkthrough
|
20
20
|
last_link.next = link
|
21
21
|
|
@@ -32,7 +32,7 @@ class SingleLinkedList
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def unshift(val)
|
35
|
-
link =
|
35
|
+
link = SinglyLink.new(val)
|
36
36
|
@sentinel.next, link.next = link, @sentinel.next
|
37
37
|
|
38
38
|
self
|
@@ -52,7 +52,7 @@ class SingleLinkedList
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
class
|
55
|
+
class SinglyLink
|
56
56
|
attr_accessor :next, :val
|
57
57
|
|
58
58
|
def initialize(val)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data-struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Wang
|
@@ -13,18 +13,21 @@ bindir: bin
|
|
13
13
|
cert_chain: []
|
14
14
|
date: 2015-07-16 00:00:00.000000000 Z
|
15
15
|
dependencies: []
|
16
|
-
description: A simple gem that provides several useful implementations of data structures
|
16
|
+
description: A simple gem that provides several useful implementations of data structures.
|
17
|
+
Contribute at github.com/kswang2400/data-struct
|
17
18
|
email: kevinwang2400@gmail.com
|
18
19
|
executables: []
|
19
20
|
extensions: []
|
20
21
|
extra_rdoc_files: []
|
21
22
|
files:
|
23
|
+
- lib/bin_heap.rb
|
24
|
+
- lib/binary_search_tree.rb
|
22
25
|
- lib/data-struct.rb
|
23
26
|
- lib/doubly_linked_list.rb
|
24
27
|
- lib/dynamic_array.rb
|
25
28
|
- lib/max_stack.rb
|
26
29
|
- lib/min_max_stack.rb
|
27
|
-
- lib/
|
30
|
+
- lib/singly_linked_list.rb
|
28
31
|
- lib/stack_queue.rb
|
29
32
|
homepage: http://rubygems.org/gems/data-struct
|
30
33
|
licenses:
|