simms_structures 0.0.0 → 0.0.1
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/simms_structures/dynamic_array.rb +75 -0
- data/lib/simms_structures/hash_map.rb +72 -0
- data/lib/simms_structures/hash_set.rb +47 -0
- data/lib/simms_structures/hashing.rb +34 -0
- data/lib/simms_structures/heap.rb +80 -0
- data/lib/simms_structures/heap_sort.rb +17 -0
- data/lib/simms_structures/int_set.rb +104 -0
- data/lib/simms_structures/linked_list.rb +92 -0
- data/lib/simms_structures/lru_cache.rb +52 -0
- data/lib/simms_structures/quick_sort.rb +63 -0
- data/lib/simms_structures/ring_buffer.rb +80 -0
- data/lib/simms_structures/static_array.rb +26 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 353026f3f3254975c9415d6aa60351d51980b84d
|
4
|
+
data.tar.gz: 822573baead5d38dc2bb6df5fa9b9f4ecb9affb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82fba3dfb293477766ca98c33d3993af22df4737b0bb6deeed21bc18a968f719b4f951fa673dcfde18fc8521af9577cd10a05ca534318ee9a88d249a4d5cee62
|
7
|
+
data.tar.gz: 9020d22aab60ff58f49a300f7f3e4991b496bd387e8f0679e025070b4b1182fc9a16d22886a2dbe72692cc73a580bb9a38761eb6165f5bd62258e6118b1d1604
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative "static_array"
|
2
|
+
|
3
|
+
class DynamicArray
|
4
|
+
attr_reader :length
|
5
|
+
|
6
|
+
def initialize(size = 8)
|
7
|
+
@store = StaticArray.new(size)
|
8
|
+
@length = 0
|
9
|
+
@capacity = size
|
10
|
+
end
|
11
|
+
|
12
|
+
# O(1)
|
13
|
+
def [](index)
|
14
|
+
raise 'index out of bounds' if index >= (@length)
|
15
|
+
@store[index]
|
16
|
+
end
|
17
|
+
|
18
|
+
# O(1)
|
19
|
+
def []=(index, value)
|
20
|
+
@store[index] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
# O(1)
|
24
|
+
def pop
|
25
|
+
raise 'index out of bounds' if @length == 0
|
26
|
+
value = self[@length - 1]
|
27
|
+
@length -= 1
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
# O(1) ammortized; O(n) worst case. Variable because of the possible
|
32
|
+
# resize.
|
33
|
+
def push(value)
|
34
|
+
resize! if @length == @capacity
|
35
|
+
self[@length] = value
|
36
|
+
@length += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
# O(n): has to shift over all the elements.
|
40
|
+
def shift
|
41
|
+
raise 'index out of bounds' if @length == 0
|
42
|
+
1.upto(@length - 1) do |idx|
|
43
|
+
self[idx - 1] = self[idx]
|
44
|
+
end
|
45
|
+
@length -= 1
|
46
|
+
end
|
47
|
+
|
48
|
+
# O(n): has to shift over all the elements.
|
49
|
+
def unshift(value)
|
50
|
+
resize! if @length == @capacity
|
51
|
+
|
52
|
+
(@length - 1).downto(0) do |idx|
|
53
|
+
self[idx + 1] = self[idx]
|
54
|
+
end if @length > 0
|
55
|
+
self[0] = value
|
56
|
+
@length += 1
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
attr_accessor :capacity, :store
|
61
|
+
attr_writer :length
|
62
|
+
|
63
|
+
def check_index(index)
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# O(n): has to copy over all the elements to the new store.
|
68
|
+
def resize!
|
69
|
+
new_capacity = @capacity * 2
|
70
|
+
new_store = StaticArray.new(new_capacity)
|
71
|
+
@length.times { |idx| new_store[idx] = self[idx] }
|
72
|
+
@store = new_store
|
73
|
+
@capacity = new_capacity
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative 'hashing'
|
2
|
+
require_relative 'linked_list'
|
3
|
+
|
4
|
+
class HashMap
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :count
|
9
|
+
|
10
|
+
def initialize(num_buckets = 8)
|
11
|
+
@store = Array.new(num_buckets) { LinkedList.new }
|
12
|
+
@count = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def include?(key)
|
16
|
+
bucket(key).include?(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(key, val)
|
20
|
+
resize! if @count == num_buckets
|
21
|
+
include?(key) ? delete(key) : (@count += 1)
|
22
|
+
bucket(key).insert(key, val)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get(key)
|
26
|
+
bucket(key).get(key)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(key)
|
30
|
+
@count-= 1 if bucket(key).remove(key)
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&block)
|
34
|
+
@store.each do |bucket|
|
35
|
+
bucket.each do |link|
|
36
|
+
block.yield(link.key, link.val)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
pairs = inject([]) do |strs, (k, v)|
|
43
|
+
strs << "#{k.to_s} => #{v.to_s}"
|
44
|
+
end
|
45
|
+
"{\n" + pairs.join(",\n") + "\n}"
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :[], :get
|
49
|
+
alias_method :[]=, :set
|
50
|
+
|
51
|
+
# private
|
52
|
+
|
53
|
+
def num_buckets
|
54
|
+
@store.length
|
55
|
+
end
|
56
|
+
|
57
|
+
def resize!
|
58
|
+
old_store = @store
|
59
|
+
@store = Array.new( num_buckets * 2 ) { LinkedList.new }
|
60
|
+
@count = 0
|
61
|
+
|
62
|
+
old_store.each do |bucket|
|
63
|
+
bucket.each do |link|
|
64
|
+
self[link.key] = link.val
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def bucket(key)
|
70
|
+
@store[key.hash % num_buckets]
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'hashing'
|
2
|
+
|
3
|
+
class HashSet
|
4
|
+
attr_reader :count
|
5
|
+
|
6
|
+
def initialize(num_buckets = 8)
|
7
|
+
@store = Array.new(num_buckets) { Array.new }
|
8
|
+
@count = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def insert(key)
|
12
|
+
resize! if @count == num_buckets
|
13
|
+
self[key] << key unless include?(key)
|
14
|
+
@count += 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def include?(key)
|
18
|
+
self[key].include?(key)
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove(key)
|
22
|
+
self[key].delete(key)
|
23
|
+
@count -= 1
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def [](num)
|
29
|
+
@store[num.hash % num_buckets]
|
30
|
+
end
|
31
|
+
|
32
|
+
def num_buckets
|
33
|
+
@store.length
|
34
|
+
end
|
35
|
+
|
36
|
+
def resize!
|
37
|
+
old_store = @store
|
38
|
+
new_num_buckets = num_buckets * 2
|
39
|
+
|
40
|
+
@store = Array.new(new_num_buckets) { Array.new }
|
41
|
+
@count = 0
|
42
|
+
|
43
|
+
old_store.each do |bucket|
|
44
|
+
bucket.each { |num| insert(num) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Array
|
2
|
+
# this doesn't type check, but needs the array to be only integer values.
|
3
|
+
# XOR and converting to binary produces a unique binary digit, which is then
|
4
|
+
# hashed with Ruby's built in Fixnum#hash
|
5
|
+
|
6
|
+
def hash
|
7
|
+
output = []
|
8
|
+
each_with_index do |el, idx|
|
9
|
+
el = el.hash unless el.is_a?(Numeric)
|
10
|
+
output << (el ^ idx).to_s(2).to_i
|
11
|
+
end
|
12
|
+
output.join.to_i.hash
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class String
|
17
|
+
def hash
|
18
|
+
characters = chars.map { |let| let.ord }
|
19
|
+
characters.hash
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Hash
|
24
|
+
def hash
|
25
|
+
hashed_array = []
|
26
|
+
each do |key, val|
|
27
|
+
hashed_array << key.hash * val.hash
|
28
|
+
end
|
29
|
+
|
30
|
+
# we need to sort the hashed_array to ensure that the same hash is
|
31
|
+
# generated from two hashes with different order of elements
|
32
|
+
hashed_array.sort.hash
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class BinaryMinHeap
|
2
|
+
def initialize(&prc)
|
3
|
+
@prc = prc
|
4
|
+
@store = Array.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def count
|
8
|
+
@store.length
|
9
|
+
end
|
10
|
+
|
11
|
+
def peek
|
12
|
+
@store.last
|
13
|
+
end
|
14
|
+
|
15
|
+
def extract
|
16
|
+
last = @store.length - 1
|
17
|
+
@store[0], @store[last] = @store[last], @store[0]
|
18
|
+
output = @store.pop
|
19
|
+
BinaryMinHeap.heapify_down(@store, 0)
|
20
|
+
output
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert(val)
|
24
|
+
@store.push(val)
|
25
|
+
BinaryMinHeap.heapify_up(@store, @store.length - 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
attr_accessor :prc, :store
|
30
|
+
|
31
|
+
public
|
32
|
+
def self.child_indices(len, parent_idx)
|
33
|
+
first_child_idx = ( parent_idx * 2 ) + 1
|
34
|
+
second_child_idx = ( parent_idx * 2 ) + 2
|
35
|
+
|
36
|
+
[first_child_idx, second_child_idx].select do |idx|
|
37
|
+
idx < len && idx > -1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.parent_index(child_idx)
|
42
|
+
raise 'root has no parent' if child_idx == 0
|
43
|
+
( child_idx - 1 ) / 2
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.heapify_down(array, parent_idx, len = array.length, &prc)
|
47
|
+
prc ||= Proc.new { |a, b| a <=> b }
|
48
|
+
|
49
|
+
child_idxs = BinaryMinHeap.child_indices(len, parent_idx)
|
50
|
+
if child_idxs.empty?
|
51
|
+
return array
|
52
|
+
elsif child_idxs.count == 1
|
53
|
+
target_child = child_idxs.first
|
54
|
+
else
|
55
|
+
if prc.call(array[child_idxs.first], array[child_idxs.last]) > -1
|
56
|
+
target_child = child_idxs.last
|
57
|
+
else
|
58
|
+
target_child = child_idxs.first
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if prc.call(array[parent_idx], array[target_child]) > -1
|
63
|
+
array[parent_idx], array[target_child] = array[target_child], array[parent_idx]
|
64
|
+
BinaryMinHeap.heapify_down(array, target_child, len, &prc)
|
65
|
+
end
|
66
|
+
array
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.heapify_up(array, child_idx, len = array.length, &prc)
|
70
|
+
return if child_idx == 0
|
71
|
+
prc ||= Proc.new { |a, b| a <=> b }
|
72
|
+
|
73
|
+
parent_idx = BinaryMinHeap.parent_index(child_idx)
|
74
|
+
if prc.call(array[parent_idx], array[child_idx]) > -1
|
75
|
+
array[parent_idx], array[child_idx] = array[child_idx], array[parent_idx]
|
76
|
+
BinaryMinHeap.heapify_up(array, parent_idx, len, &prc)
|
77
|
+
end
|
78
|
+
array
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'heap'
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def heap_sort!
|
5
|
+
|
6
|
+
0.upto(length - 1) do |idx|
|
7
|
+
BinaryMinHeap.heapify_up(self, idx)
|
8
|
+
end
|
9
|
+
|
10
|
+
(length - 1).downto(1) do |idx|
|
11
|
+
self[0], self[idx] = self[idx], self[0]
|
12
|
+
BinaryMinHeap.heapify_down(self, 0, idx )
|
13
|
+
end
|
14
|
+
|
15
|
+
reverse!
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class MaxIntSet
|
2
|
+
def initialize(max)
|
3
|
+
@store = Array.new(max, false)
|
4
|
+
end
|
5
|
+
|
6
|
+
def insert(num)
|
7
|
+
validate!(num)
|
8
|
+
@store[num] = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove(num)
|
12
|
+
validate!(num)
|
13
|
+
@store[num] = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def include?(num)
|
17
|
+
validate!(num)
|
18
|
+
@store[num]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def is_valid?(num)
|
24
|
+
num <= @store.length && num >= 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate!(num)
|
28
|
+
raise "Out of bounds" unless is_valid?(num)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class IntSet
|
34
|
+
def initialize(num_buckets = 20)
|
35
|
+
@num_buckets = num_buckets
|
36
|
+
@store = Array.new(@num_buckets) { Array.new }
|
37
|
+
end
|
38
|
+
|
39
|
+
def insert(num)
|
40
|
+
self[num] << num unless include?(num)
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove(num)
|
44
|
+
self[num].delete(num)
|
45
|
+
end
|
46
|
+
|
47
|
+
def include?(num)
|
48
|
+
self[num].include?(num)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def [](num)
|
54
|
+
@store[num % @num_buckets]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ResizingIntSet
|
59
|
+
attr_reader :count
|
60
|
+
|
61
|
+
def initialize(num_buckets = 20)
|
62
|
+
@store = Array.new(num_buckets) { Array.new }
|
63
|
+
@count = 0
|
64
|
+
end
|
65
|
+
|
66
|
+
def insert(num)
|
67
|
+
resize! if @count == num_buckets
|
68
|
+
self[num] << num unless include?(num)
|
69
|
+
@count += 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove(num)
|
73
|
+
if include?(num)
|
74
|
+
self[num].delete(num)
|
75
|
+
@count -= 1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def include?(num)
|
80
|
+
self[num].include?(num)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def [](num)
|
86
|
+
@store[num % num_buckets]
|
87
|
+
end
|
88
|
+
|
89
|
+
def num_buckets
|
90
|
+
@store.length
|
91
|
+
end
|
92
|
+
|
93
|
+
def resize!
|
94
|
+
old_store = @store
|
95
|
+
new_num_buckets = num_buckets * 2
|
96
|
+
|
97
|
+
@store = Array.new(new_num_buckets) { Array.new }
|
98
|
+
@count = 0
|
99
|
+
|
100
|
+
old_store.each do |bucket|
|
101
|
+
bucket.each { |num| insert(num) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Link
|
2
|
+
attr_accessor :key, :val, :next, :prev
|
3
|
+
|
4
|
+
def initialize(key = nil, val = nil)
|
5
|
+
@key = key
|
6
|
+
@val = val
|
7
|
+
@next = nil
|
8
|
+
@prev = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"#{@key}: #{@val}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class LinkedList
|
17
|
+
include Enumerable
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@head = nil
|
21
|
+
@tail = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](i)
|
25
|
+
each { |link, j| return link if i == j }
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def first
|
30
|
+
@head
|
31
|
+
end
|
32
|
+
|
33
|
+
def last
|
34
|
+
@tail
|
35
|
+
end
|
36
|
+
|
37
|
+
def empty?
|
38
|
+
@head == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(key)
|
42
|
+
self[key].val if include?(key)
|
43
|
+
end
|
44
|
+
|
45
|
+
def include?(key)
|
46
|
+
any? {|link| link.key == key}
|
47
|
+
end
|
48
|
+
|
49
|
+
def insert(key, val)
|
50
|
+
link = Link.new(key, val)
|
51
|
+
if empty?
|
52
|
+
@head = link
|
53
|
+
else
|
54
|
+
@tail.next = link
|
55
|
+
link.prev = @tail
|
56
|
+
end
|
57
|
+
@tail = link
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove(key)
|
61
|
+
link = self[key] #the O(n) step
|
62
|
+
|
63
|
+
return nil unless link
|
64
|
+
|
65
|
+
if link == first
|
66
|
+
link.next.prev = nil
|
67
|
+
@head = link.next
|
68
|
+
elsif link == last
|
69
|
+
link.prev.next = nil
|
70
|
+
@tail = link.prev
|
71
|
+
else
|
72
|
+
link.prev.next = link.next
|
73
|
+
link.next.prev = link.prev
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def each(&block)
|
78
|
+
return nil if empty?
|
79
|
+
|
80
|
+
link = first
|
81
|
+
loop do
|
82
|
+
block.yield(link, link.key)
|
83
|
+
link = link.next
|
84
|
+
break unless link
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_s
|
90
|
+
inject([]) { |acc, link| acc << "[#{link.key}, #{link.val}]" }.join(", ")
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'hash_map'
|
2
|
+
require_relative 'linked_list'
|
3
|
+
|
4
|
+
class LRUCache
|
5
|
+
|
6
|
+
attr_reader :count
|
7
|
+
|
8
|
+
def initialize(max, prc)
|
9
|
+
@map = HashMap.new
|
10
|
+
@store = LinkedList.new
|
11
|
+
@max = max
|
12
|
+
@prc = prc
|
13
|
+
end
|
14
|
+
|
15
|
+
def count
|
16
|
+
@map.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(key)
|
20
|
+
link = @map[key]
|
21
|
+
if link
|
22
|
+
update_link!(link)
|
23
|
+
link.val
|
24
|
+
else
|
25
|
+
eject! if @map.count == @max
|
26
|
+
calc!(key).val
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"Map: " + @map.to_s + "\n" + "Store: " + @store.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# insert an (un-cached) key
|
37
|
+
def calc!(key)
|
38
|
+
@store.insert(key, @prc.call(key))
|
39
|
+
@map[key] = @store.last
|
40
|
+
end
|
41
|
+
|
42
|
+
# move a link to the end of the list
|
43
|
+
def update_link!(link)
|
44
|
+
@store.insert(link.key, link.val)
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def eject!
|
49
|
+
link = @store.first
|
50
|
+
@store.remove(link)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class QuickSort
|
2
|
+
# Quick sort has average time complexity O(nlogn), but worst
|
3
|
+
# case O(n**2).
|
4
|
+
|
5
|
+
# Not in-place. Uses O(n) memory.
|
6
|
+
def self.sort1(array)
|
7
|
+
return array if array.length < 2
|
8
|
+
pivot = array.first
|
9
|
+
|
10
|
+
left = []
|
11
|
+
right = []
|
12
|
+
|
13
|
+
array.drop(1).each do |el|
|
14
|
+
if el < pivot
|
15
|
+
left << el
|
16
|
+
elsif el > pivot
|
17
|
+
right << el
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
QuickSort.sort1(left) + [pivot] + QuickSort.sort1(right)
|
22
|
+
end
|
23
|
+
|
24
|
+
# In-place.
|
25
|
+
def self.sort2!(array, start = 0, length = array.length, &prc)
|
26
|
+
return array if length < 2
|
27
|
+
prc ||= Proc.new { |a, b| a <=> b }
|
28
|
+
|
29
|
+
pivot_idx = QuickSort.partition(array, start, length, &prc)
|
30
|
+
|
31
|
+
left_length = pivot_idx - start
|
32
|
+
right_length = length - (left_length + 1)
|
33
|
+
|
34
|
+
sort2!(array, start, left_length, &prc)
|
35
|
+
sort2!(array, pivot_idx + 1, right_length, &prc)
|
36
|
+
array
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.partition(array, start, length = array.length, &prc)
|
40
|
+
prc ||= Proc.new { |a, b| a <=> b }
|
41
|
+
|
42
|
+
first_right_idx = nil
|
43
|
+
(start + 1).upto(start + length - 1) do |idx|
|
44
|
+
case prc.call(array[start], array[idx])
|
45
|
+
when -1
|
46
|
+
first_right_idx ||= idx
|
47
|
+
when 1
|
48
|
+
if first_right_idx
|
49
|
+
array[first_right_idx], array[idx] = array[idx], array[first_right_idx]
|
50
|
+
first_right_idx += 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# swap pivot with last 'left' element
|
56
|
+
if first_right_idx
|
57
|
+
array[start], array[first_right_idx - 1] = array[first_right_idx - 1], array[start]
|
58
|
+
(first_right_idx - 1)
|
59
|
+
else
|
60
|
+
start
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'static_array'
|
2
|
+
require_relative 'dynamic_array'
|
3
|
+
|
4
|
+
class RingBuffer
|
5
|
+
attr_reader :length
|
6
|
+
|
7
|
+
def initialize(size = 8)
|
8
|
+
@store = StaticArray.new(size)
|
9
|
+
@start_idx = 0
|
10
|
+
@length = 0
|
11
|
+
@capacity = size
|
12
|
+
end
|
13
|
+
|
14
|
+
def relative_index(index)
|
15
|
+
(@start_idx + index) % @capacity
|
16
|
+
end
|
17
|
+
|
18
|
+
# O(1)
|
19
|
+
def [](index)
|
20
|
+
check_index(index)
|
21
|
+
@store[relative_index(index)]
|
22
|
+
end
|
23
|
+
|
24
|
+
# O(1)
|
25
|
+
def []=(index, value)
|
26
|
+
check_index(index)
|
27
|
+
@store[relative_index(index)] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
# O(1)
|
31
|
+
def pop
|
32
|
+
check_index(0)
|
33
|
+
@length -= 1
|
34
|
+
@store[(@start_idx + @length) % @capacity]
|
35
|
+
end
|
36
|
+
|
37
|
+
# O(1) ammortized
|
38
|
+
def push(value)
|
39
|
+
resize! if @length == @capacity
|
40
|
+
@store[(@start_idx + @length) % @capacity] = value
|
41
|
+
@length += 1
|
42
|
+
nil
|
43
|
+
# debugger
|
44
|
+
end
|
45
|
+
|
46
|
+
# O(1)
|
47
|
+
def shift
|
48
|
+
check_index(0)
|
49
|
+
value = self[0]
|
50
|
+
@start_idx = (@start_idx + 1) % @capacity
|
51
|
+
@length -= 1
|
52
|
+
value
|
53
|
+
end
|
54
|
+
|
55
|
+
# O(1) ammortized
|
56
|
+
def unshift(value)
|
57
|
+
resize! if @length == @capacity
|
58
|
+
@start_idx = (@start_idx - 1) % @capacity
|
59
|
+
@store[@start_idx] = value
|
60
|
+
@length += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
attr_accessor :capacity, :start_idx, :store
|
65
|
+
attr_writer :length
|
66
|
+
|
67
|
+
def check_index(index)
|
68
|
+
raise 'index out of bounds' if index >= @length
|
69
|
+
end
|
70
|
+
|
71
|
+
def resize!
|
72
|
+
new_capacity = @capacity * 2
|
73
|
+
new_store = StaticArray.new(new_capacity)
|
74
|
+
@length.times { |idx| new_store[idx] = @store[relative_index(idx)]}
|
75
|
+
|
76
|
+
@store = new_store
|
77
|
+
@capacity = new_capacity
|
78
|
+
@start_idx = 0
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# This class just dumbs down a regular Array to be staticly sized.
|
2
|
+
class StaticArray
|
3
|
+
def initialize(length)
|
4
|
+
@store = Array.new(length, nil)
|
5
|
+
end
|
6
|
+
|
7
|
+
# O(1)
|
8
|
+
def [](index)
|
9
|
+
@store[index]
|
10
|
+
end
|
11
|
+
|
12
|
+
# O(1)
|
13
|
+
def []=(index, value)
|
14
|
+
check_index(index)
|
15
|
+
@store[index] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def check_index(idx)
|
21
|
+
raise TypeError 'Invalid Position' if 0 > idx || idx > @store.length
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
attr_accessor :store
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simms_structures
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Simms
|
@@ -11,12 +11,24 @@ cert_chain: []
|
|
11
11
|
date: 2016-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Structures and Algorithms implemented for fun
|
14
|
-
email:
|
14
|
+
email: cs.simms@gmail.com
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
19
|
- lib/simms_structures.rb
|
20
|
+
- lib/simms_structures/dynamic_array.rb
|
21
|
+
- lib/simms_structures/hash_map.rb
|
22
|
+
- lib/simms_structures/hash_set.rb
|
23
|
+
- lib/simms_structures/hashing.rb
|
24
|
+
- lib/simms_structures/heap.rb
|
25
|
+
- lib/simms_structures/heap_sort.rb
|
26
|
+
- lib/simms_structures/int_set.rb
|
27
|
+
- lib/simms_structures/linked_list.rb
|
28
|
+
- lib/simms_structures/lru_cache.rb
|
29
|
+
- lib/simms_structures/quick_sort.rb
|
30
|
+
- lib/simms_structures/ring_buffer.rb
|
31
|
+
- lib/simms_structures/static_array.rb
|
20
32
|
homepage: http://rubygems.org/gem/simms_structures
|
21
33
|
licenses:
|
22
34
|
- MIT
|