data-struct 0.0.10 → 0.0.12
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 +48 -47
- data/lib/binary_search_tree.rb +24 -57
- data/lib/doubly_linked_list.rb +7 -3
- data/lib/dynamic_array.rb +4 -2
- data/lib/priority_queue.rb +73 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c437ac066dcec6997b160235477be36c58441660
|
4
|
+
data.tar.gz: 053bae6faad59521f3ce8169d1e39ca1cf82db85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 055ccbb07e98d24aa728034e4d28b674b045c71aa354bbee01610bb19f0a2cff3f1a11dd60c452482da2656ff67261622aff975246db03eaac89cd158a16013f
|
7
|
+
data.tar.gz: ca1608ee961b31799490719f028bc8936c9bdbeeb8a0045a1a1f657f35d8b03ae3ce978173061b001e2222c7dae949fe38dfe7ddb9db229c05eda669ee135ad7
|
data/lib/bin_heap.rb
CHANGED
@@ -27,67 +27,68 @@ class BinHeap
|
|
27
27
|
end
|
28
28
|
|
29
29
|
protected
|
30
|
-
|
30
|
+
|
31
|
+
attr_writer :prc, :store
|
31
32
|
|
32
33
|
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
34
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
children_idx = find_children(store.length - 1, parent_idx)
|
51
|
-
|
52
|
-
c0_idx = children_idx[0]
|
53
|
-
c1_idx = children_idx[1]
|
35
|
+
def self.heapify_up(store, child_idx, &prc)
|
36
|
+
prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
37
|
+
return store if child_idx == 0
|
54
38
|
|
55
|
-
|
56
|
-
|
57
|
-
|
39
|
+
parent_idx = find_parent(child_idx)
|
40
|
+
|
41
|
+
if prc.call(store[child_idx], store[parent_idx]) == -1
|
42
|
+
store[child_idx], store[parent_idx] = store[parent_idx], store[child_idx]
|
43
|
+
heapify_up(store, parent_idx, &prc)
|
44
|
+
else
|
45
|
+
return store
|
46
|
+
end
|
47
|
+
end
|
58
48
|
|
59
|
-
|
49
|
+
def self.heapify_down(store, parent_idx, &prc)
|
50
|
+
prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
51
|
+
|
52
|
+
children_idx = find_children(store.length - 1, parent_idx)
|
53
|
+
|
54
|
+
c0_idx = children_idx[0]
|
55
|
+
c1_idx = children_idx[1]
|
60
56
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
57
|
+
children = []
|
58
|
+
children << store[c0_idx] if c0_idx
|
59
|
+
children << store[c1_idx] if c1_idx
|
65
60
|
|
66
|
-
|
67
|
-
swap_idx = c0_idx
|
68
|
-
else
|
69
|
-
swap_idx = prc.call(children[0], children[1]) == 1 ? c1_idx : c0_idx
|
70
|
-
end
|
61
|
+
parent = store[parent_idx]
|
71
62
|
|
72
|
-
|
63
|
+
# When the parent index is where it's supposed to be
|
64
|
+
if children.all? { |child| prc.call(child, parent) >= 0 }
|
65
|
+
return store
|
66
|
+
end
|
73
67
|
|
74
|
-
|
68
|
+
if store.length == 1
|
69
|
+
swap_idx = c0_idx
|
70
|
+
else
|
71
|
+
swap_idx = prc.call(children[0], children[1]) == 1 ? c1_idx : c0_idx
|
75
72
|
end
|
76
73
|
|
77
|
-
|
78
|
-
child1 = (parent_idx * 2) + 1
|
79
|
-
child2 = (parent_idx * 2) + 2
|
74
|
+
store[swap_idx], store[parent_idx] = parent, store[swap_idx]
|
80
75
|
|
76
|
+
heapify_down(store, swap_idx, &prc)
|
77
|
+
end
|
81
78
|
|
82
|
-
|
83
|
-
|
79
|
+
def self.find_children(last_idx, parent_idx)
|
80
|
+
child1 = (parent_idx * 2) + 1
|
81
|
+
child2 = (parent_idx * 2) + 2
|
84
82
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
83
|
+
return [child1, child2].select{ |idx| idx <= last_idx }
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.find_parent(child_idx)
|
87
|
+
if child_idx == 0
|
88
|
+
raise "Out of bounds"
|
89
|
+
else
|
90
|
+
return (child_idx - 1) / 2
|
91
91
|
end
|
92
|
+
end
|
92
93
|
end
|
93
94
|
|
data/lib/binary_search_tree.rb
CHANGED
@@ -16,57 +16,42 @@ class BinarySearchTree
|
|
16
16
|
end
|
17
17
|
end
|
18
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
19
|
def left_rotate
|
20
|
+
#
|
28
21
|
# A B
|
29
22
|
# / \ / \
|
30
|
-
# D B <=> A
|
23
|
+
# D B <=> A C
|
31
24
|
# / \ / \
|
32
25
|
# E C D E
|
33
26
|
#
|
34
27
|
|
35
|
-
|
36
|
-
|
37
|
-
new_left =
|
28
|
+
new_left = BinarySearchTree.new(value) # A'
|
29
|
+
|
30
|
+
new_left.left, left.parent = left, new_left # A' <-> D
|
31
|
+
new_left.right, right.left.parent = right.left, new_left # A' <-> E
|
32
|
+
new_left.parent = self # A' <- A
|
38
33
|
|
39
|
-
|
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
|
34
|
+
new_right, new_right.parent = right.right, self # C <-> A
|
44
35
|
|
45
|
-
new_right = right.right # C
|
46
|
-
new_right.parent = self # C <- A
|
47
|
-
|
48
36
|
@value, @left, @right = right.value, new_left, new_right
|
49
37
|
end
|
50
38
|
|
51
39
|
def right_rotate
|
52
40
|
new_right = BinarySearchTree.new(value)
|
53
41
|
|
54
|
-
new_right.right = right
|
55
|
-
right.parent = new_right
|
56
|
-
new_right.left = left.right
|
57
|
-
left.right.parent = new_right
|
42
|
+
new_right.right, right.parent = right, new_right
|
43
|
+
new_right.left, left.right.parent = left.right, new_right
|
58
44
|
new_right.parent = self
|
59
45
|
|
60
|
-
new_left = left.left
|
61
|
-
new_left.parent = self
|
46
|
+
new_left, new_left.parent = left.left, self
|
62
47
|
|
63
48
|
@value, @left, @right = left.value, new_left, new_right
|
64
49
|
end
|
65
50
|
|
66
51
|
def insert(val)
|
67
52
|
case val <=> value
|
68
|
-
when -1 then
|
69
|
-
when 1 then
|
53
|
+
when -1 then insert_at(val, left, -1)
|
54
|
+
when 1 then insert_at(val, right, 1)
|
70
55
|
when 0 then false
|
71
56
|
end
|
72
57
|
|
@@ -92,50 +77,40 @@ class BinarySearchTree
|
|
92
77
|
def recalculate_depth_and_balance
|
93
78
|
@depth = ([left.depth, right.depth].max + 1)
|
94
79
|
@balance = right.depth - left.depth
|
95
|
-
# p "RECALULATED DEPTH = #{depth}: BALANCE = #{balance}"
|
96
80
|
end
|
97
81
|
|
98
82
|
def update_depth_and_balance
|
99
83
|
# recursively update depth and balance, rebalances if needed and crawls up the tree
|
100
84
|
recalculate_depth_and_balance
|
101
85
|
rebalance if ([-2, 2].include?(@balance))
|
102
|
-
# p "RECALULATED #{self.inspect} DEPTH = #{depth}: BALANCE = #{balance}"
|
103
86
|
parent.update_depth_and_balance
|
104
87
|
end
|
105
88
|
|
106
89
|
private
|
107
90
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
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)
|
91
|
+
def insert_at(val, node, dir)
|
92
|
+
# dir: -1 => left, 1 => right
|
93
|
+
if (node.class != EmptyNode)
|
94
|
+
node.insert(val)
|
121
95
|
else
|
122
96
|
new_node = BinarySearchTree.new(val)
|
123
|
-
self.right
|
97
|
+
(dir == 1) ? self.right = new_node : self.left = new_node
|
98
|
+
new_node.parent = self
|
124
99
|
new_node.update_depth_and_balance
|
125
100
|
end
|
126
101
|
end
|
127
102
|
|
128
103
|
def rebalance
|
129
|
-
|
104
|
+
case @balance
|
105
|
+
when -2
|
130
106
|
left.left_rotate if left.balance == 1
|
131
107
|
right_rotate
|
132
|
-
|
108
|
+
when 2
|
133
109
|
right.right_rotate if right.balance == -1
|
134
110
|
left_rotate
|
135
111
|
end
|
136
|
-
|
137
|
-
left.recalculate_depth_and_balance
|
138
|
-
recalculate_depth_and_balance
|
112
|
+
|
113
|
+
[right, left, self].each { |n| n.recalculate_depth_and_balance }
|
139
114
|
end
|
140
115
|
end
|
141
116
|
|
@@ -152,18 +127,10 @@ class EmptyNode
|
|
152
127
|
false
|
153
128
|
end
|
154
129
|
|
155
|
-
def insert(*)
|
156
|
-
false
|
157
|
-
end
|
158
|
-
|
159
130
|
def inspect
|
160
131
|
"{}"
|
161
132
|
end
|
162
133
|
|
163
|
-
def recalculate_depth_and_balance
|
164
|
-
true
|
165
|
-
end
|
166
|
-
|
167
134
|
def to_a
|
168
135
|
[]
|
169
136
|
end
|
data/lib/doubly_linked_list.rb
CHANGED
@@ -9,10 +9,12 @@ class LinkedList
|
|
9
9
|
|
10
10
|
def pop
|
11
11
|
last_link = @last_sentinel.prev
|
12
|
-
|
12
|
+
return nil if last_link == @begin_sentinel
|
13
|
+
|
14
|
+
last_link.prev.next = @last_sentinel
|
13
15
|
@last_sentinel.prev = last_link.prev
|
14
16
|
|
15
|
-
val
|
17
|
+
last_link.val
|
16
18
|
end
|
17
19
|
|
18
20
|
def push(val)
|
@@ -23,7 +25,7 @@ class LinkedList
|
|
23
25
|
else
|
24
26
|
@begin_sentinel.next = link
|
25
27
|
end
|
26
|
-
|
28
|
+
@last_sentinel.prev = link
|
27
29
|
|
28
30
|
self
|
29
31
|
end
|
@@ -44,7 +46,9 @@ class LinkedList
|
|
44
46
|
def shift
|
45
47
|
first_link = @begin_sentinel.next
|
46
48
|
return nil if first_link.nil?
|
49
|
+
|
47
50
|
@begin_sentinel.next = first_link.next
|
51
|
+
first_link.next.prev = @begin_sentinel
|
48
52
|
|
49
53
|
first_link.val
|
50
54
|
end
|
data/lib/dynamic_array.rb
CHANGED
@@ -11,8 +11,8 @@ class DynamicArray
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def empty?
|
14
|
-
#
|
15
|
-
return
|
14
|
+
# not cheating by checking @store
|
15
|
+
return num_items == 0
|
16
16
|
end
|
17
17
|
|
18
18
|
def insert(val, idx)
|
@@ -38,6 +38,7 @@ class DynamicArray
|
|
38
38
|
|
39
39
|
def pop
|
40
40
|
# O(1)
|
41
|
+
raise "array is empty" if @num_items == 0
|
41
42
|
@num_items -= 1
|
42
43
|
idx = @start + @num_items
|
43
44
|
val, @store[idx] = @store[idx], nil
|
@@ -74,6 +75,7 @@ class DynamicArray
|
|
74
75
|
|
75
76
|
def shift
|
76
77
|
# O(1)
|
78
|
+
raise "array is empty" if @num_items == 0
|
77
79
|
val, @store[@start] = @store[@start], nil
|
78
80
|
@num_items -= 1
|
79
81
|
@start += 1
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
require "bin_heap"
|
3
|
+
|
4
|
+
class PriorityQueue
|
5
|
+
attr_reader :store
|
6
|
+
|
7
|
+
def initialize(&prc)
|
8
|
+
@store = Array.new
|
9
|
+
@prc = prc || Proc.new { |el1, el2| el1 <=> el2 }
|
10
|
+
end
|
11
|
+
|
12
|
+
def insert(val, priority)
|
13
|
+
@store << [val, priority]
|
14
|
+
self.heapify_up(@store.length - 1)
|
15
|
+
end
|
16
|
+
|
17
|
+
def extract
|
18
|
+
raise "PriorityQueue is empty" if @store.empty?
|
19
|
+
|
20
|
+
value, _ = @store[0]
|
21
|
+
|
22
|
+
if @store.length > 1
|
23
|
+
@store[0] = @store.pop
|
24
|
+
self.heapify_down(0)
|
25
|
+
else
|
26
|
+
@store.pop
|
27
|
+
end
|
28
|
+
|
29
|
+
value
|
30
|
+
end
|
31
|
+
|
32
|
+
def heapify_up(start_idx)
|
33
|
+
return true if start_idx == 0
|
34
|
+
|
35
|
+
parent_idx = find_parent(start_idx)
|
36
|
+
|
37
|
+
if @prc.call(@store[start_idx][1], @store[parent_idx][1]) == -1
|
38
|
+
@store[start_idx], @store[parent_idx] = @store[parent_idx], @store[start_idx]
|
39
|
+
heapify_up(parent_idx)
|
40
|
+
else
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def heapify_down(start_idx)
|
46
|
+
children_idx = find_children(start_idx)
|
47
|
+
children_idx.select! { |i| i < @store.length }
|
48
|
+
|
49
|
+
return true if children_idx.all? { |i| @prc.call(@store[i][1], @store[start_idx][1]) >= 0 }
|
50
|
+
|
51
|
+
if children_idx.length == 1
|
52
|
+
temp_idx = children_idx[0]
|
53
|
+
else
|
54
|
+
temp_idx = @prc.call(@store[children_idx[0]][1], @store[children_idx[1]][1]) == -1 ? children_idx[0] : children_idx[1]
|
55
|
+
end
|
56
|
+
|
57
|
+
@store[temp_idx], @store[start_idx] = @store[start_idx], @store[temp_idx]
|
58
|
+
|
59
|
+
heapify_down(temp_idx)
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_parent(idx)
|
63
|
+
return false if idx == 0
|
64
|
+
return (idx - 1) / 2
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_children(idx)
|
68
|
+
child_1 = (idx * 2) + 1
|
69
|
+
child_2 = (idx * 2) + 2
|
70
|
+
|
71
|
+
return [child_1, child_2].select { |i| i < @store.length }
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
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.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Wang
|
8
8
|
- Daniel Ng
|
9
9
|
- Conan Tzou
|
10
10
|
- Karen Ling
|
11
|
+
- Aaron Hong
|
11
12
|
autorequire:
|
12
13
|
bindir: bin
|
13
14
|
cert_chain: []
|
14
|
-
date: 2015-
|
15
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
15
16
|
dependencies: []
|
16
17
|
description: A simple gem that provides several useful implementations of data structures.
|
17
18
|
Contribute at github.com/kswang2400/data-struct
|
@@ -27,6 +28,7 @@ files:
|
|
27
28
|
- lib/dynamic_array.rb
|
28
29
|
- lib/max_stack.rb
|
29
30
|
- lib/min_max_stack.rb
|
31
|
+
- lib/priority_queue.rb
|
30
32
|
- lib/singly_linked_list.rb
|
31
33
|
- lib/stack_queue.rb
|
32
34
|
homepage: http://rubygems.org/gems/data-struct
|
@@ -52,5 +54,5 @@ rubyforge_project:
|
|
52
54
|
rubygems_version: 2.4.3
|
53
55
|
signing_key:
|
54
56
|
specification_version: 4
|
55
|
-
summary: Data structures
|
57
|
+
summary: Data structures
|
56
58
|
test_files: []
|