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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e04c9d575010abad0bad21e41e2a428286a09689
4
- data.tar.gz: 7714183f1273c98edc2e1f5413b7e2a9a7fc5231
3
+ metadata.gz: 353026f3f3254975c9415d6aa60351d51980b84d
4
+ data.tar.gz: 822573baead5d38dc2bb6df5fa9b9f4ecb9affb1
5
5
  SHA512:
6
- metadata.gz: fa21d3dce610f58c3af9b73d7c9e58690f45fee300470c2c261dc66b7ab7af9b24695d42b2200d72f59dad913a5d43166f98650b1c5d32dd7d48afe68670292a
7
- data.tar.gz: bd0a435a9c3e8068d936aba4064103c5af3a1eca9dd5c55f92236478205b0d493ef65f13fc49ce3c7eadc5b30b637fa3fc2dc71ec5e542aca60aa2d17a1a84c6
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.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