data_structures 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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gem 'rake'
3
+
4
+ # Specify your gem's dependencies in data_structures.gemspec
5
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Isaac Sanders
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # DataStructures
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'data_structures'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install data_structures
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :test do
4
+ tests = FileList["test/**/*_test.rb"]
5
+ tests.each do |test|
6
+ ruby "-I lib -I test -r test_helper #{test}"
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'data_structures/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "data_structures"
8
+ gem.version = DataStructures::VERSION
9
+ gem.authors = ["Isaac Sanders"]
10
+ gem.email = ["isaac@isaacbfsanders.com"]
11
+ gem.description = %q{Data Structures that I decided to implement.}
12
+ gem.summary = %q{Data Structures that I decided to implement.}
13
+ gem.homepage = "http://isaacbfsanders.com/data_structures"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,4 @@
1
+ require "data_structures/version"
2
+
3
+ module DataStructures
4
+ end
@@ -0,0 +1,125 @@
1
+ module DataStructures
2
+ class BinaryHeap < Array
3
+ # The Binary Heap is a Max Heap by default.
4
+ # In order to make it Min Heap, pass DataStructures::BinaryHeap::LOW_TO_HIGH
5
+ # as the parameter to the constructor.
6
+ HIGH_TO_LOW = 1
7
+ LOW_TO_HIGH = -1
8
+
9
+ def initialize(ordering = HIGH_TO_LOW)
10
+ @ordering = ordering
11
+ @last_index = 0
12
+ end
13
+
14
+ def insert(element)
15
+ index = @last_index
16
+ push(element)
17
+ while has_parent_at?(index) && in_wrong_order_with_parent?(element, parent_of(index))
18
+ swap_with_parent(index)
19
+ index = parent_index(index)
20
+ end
21
+ @last_index += 1
22
+ end
23
+
24
+ def remove
25
+ if size == 0
26
+ return nil
27
+ else
28
+ value = shift
29
+ parent = pop
30
+ unshift(parent)
31
+ index = 0
32
+ bubble_down(index)
33
+ value
34
+ # Compare the new root with its children; if they are in the correct order, stop.
35
+ # If not, swap the element with one of its children and return to the previous step.
36
+ # (Swap with its smaller child in a min-heap and its larger child in a max-heap.)
37
+ end
38
+ end
39
+
40
+ def min_heap?
41
+ @ordering == LOW_TO_HIGH
42
+ end
43
+
44
+ def max_heap?
45
+ @ordering == HIGH_TO_LOW
46
+ end
47
+
48
+ private
49
+
50
+ def bubble_down(index)
51
+ while in_wrong_order_with_children?(index)
52
+ if has_two_children_at?(index)
53
+ if ((left_child(index) <=> right_child(index)) / @ordering) > 0
54
+ swap_with_parent(left_child_index(index))
55
+ index = left_child_index(index)
56
+ else
57
+ swap_with_parent(right_child_index(index))
58
+ index = right_child_index(index)
59
+ end
60
+ else
61
+ swap_with_parent(left_child_index(index))
62
+ index = left_child_index(index)
63
+ end
64
+ end
65
+ end
66
+
67
+ def right_child(index)
68
+ fetch(right_child_index(index))
69
+ end
70
+
71
+ def right_child_index(index)
72
+ (index * 2) + 2
73
+ end
74
+
75
+ def left_child(index)
76
+ fetch(left_child_index(index))
77
+ end
78
+
79
+ def left_child_index(index)
80
+ (index * 2) + 1
81
+ end
82
+
83
+ def in_wrong_order_with_children?(index)
84
+ parent = fetch(index)
85
+ (has_left_child_at?(index) && ((parent <=> left_child(index)) / @ordering < 0)) ||
86
+ (has_right_child_at?(index) && ((parent <=> right_child(index)) / @ordering < 0))
87
+ end
88
+
89
+ def has_two_children_at?(index)
90
+ has_left_child_at?(index) && has_right_child_at?(index)
91
+ end
92
+
93
+ def has_left_child_at?(index)
94
+ not self[left_child_index(index)].nil?
95
+ end
96
+
97
+ def has_right_child_at?(index)
98
+ not self[right_child_index(index)].nil?
99
+ end
100
+
101
+ def has_parent_at?(index)
102
+ parent_index(index) >= 0
103
+ end
104
+
105
+ def parent_of(index)
106
+ fetch(parent_index(index))
107
+ end
108
+
109
+ def swap_with_parent(index)
110
+ child = fetch(index)
111
+ self[index] = fetch(parent_index(index))
112
+ self[parent_index(index)] = child
113
+ nil
114
+ end
115
+
116
+ def in_wrong_order_with_parent?(child, parent)
117
+ comparison = child <=> parent
118
+ comparison / @ordering > 0
119
+ end
120
+
121
+ def parent_index(index)
122
+ (index - 1) / 2
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,164 @@
1
+ module DataStructures
2
+ class BinarySearchTree
3
+ attr_reader :root
4
+
5
+ def insert(element)
6
+ if has_root?
7
+ root.insert(element)
8
+ else
9
+ @root = DataStructures::BinarySearchTree::Node.new(element)
10
+ true
11
+ end
12
+ end
13
+
14
+ def remove(element)
15
+ if has_root?
16
+ @root = root.remove(element)
17
+ else
18
+ false
19
+ end
20
+ end
21
+
22
+ def get(element)
23
+ if has_root?
24
+ node = root
25
+ until(node.element == element)
26
+ case(node.element <=> element)
27
+ when Node::LESS_THAN_OTHER
28
+ if node.has_left_child?
29
+ node = node.left_child
30
+ end
31
+ when Node::GREATER_THAN_OTHER
32
+ if node.has_right_child?
33
+ node = node.right_child
34
+ end
35
+ end
36
+ end
37
+ node.element
38
+ else
39
+ nil
40
+ end
41
+ end
42
+
43
+ def size
44
+ in_order.size
45
+ end
46
+
47
+ def in_order
48
+ if has_root?
49
+ stack = Array.new
50
+ node = root
51
+ in_order_array = []
52
+ in_order_array += node.left_ancestors.map(&:element)
53
+
54
+ while(not stack.empty?)
55
+ node = stack.pop
56
+ in_order_array.push(node.element)
57
+ if node.has_right_child?
58
+ stack.push(node.right_child)
59
+ node = node.right_child
60
+ node.left_ancestors.each do |node|
61
+ stack.push(node)
62
+ end
63
+ end
64
+ end
65
+
66
+ in_order_array
67
+ else
68
+ []
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def has_root?
75
+ not root.nil?
76
+ end
77
+
78
+ class Node
79
+ LESS_THAN_OTHER = -1
80
+ GREATER_THAN_OTHER = 1
81
+ attr_accessor :left_child, :right_child, :element
82
+
83
+ def initialize(element)
84
+ @element = element
85
+ end
86
+
87
+ def insert(element)
88
+ case @element <=> element
89
+ when LESS_THAN_OTHER
90
+ if has_left_child?
91
+ left_child.insert(element)
92
+ else
93
+ @left_child = DataStructures::BinarySearchTree::Node.new(element)
94
+ return true
95
+ end
96
+ when GREATER_THAN_OTHER
97
+ if has_right_child?
98
+ right_child.insert(element)
99
+ else
100
+ @right_child = DataStructures::BinarySearchTree::Node.new(element)
101
+ return true
102
+ end
103
+ else
104
+ return false
105
+ end
106
+ end
107
+
108
+ def remove(element)
109
+ case @element <=> element
110
+ when LESS_THAN_OTHER
111
+ if has_left_child?
112
+ @left_child = left_child.remove(element)
113
+ else
114
+ nil
115
+ end
116
+ when GREATER_THAN_OTHER
117
+ if has_right_child?
118
+ @right_child = right_child.remove(element)
119
+ else
120
+ nil
121
+ end
122
+ else
123
+ if has_two_children?
124
+ node = left_child
125
+ while(node.has_right_child?)
126
+ node = node.right_child
127
+ end
128
+ @left_child = left_child.remove(node.element)
129
+
130
+
131
+ elsif has_left_child?
132
+ left_child
133
+ elsif has_right_child?
134
+ right_child
135
+ else
136
+ nil
137
+ end
138
+ end
139
+ end
140
+
141
+ def has_two_children?
142
+ has_left_child? and has_right_child?
143
+ end
144
+
145
+ def left_ancestors
146
+ left_ancestors = []
147
+ node = self
148
+ until node.nil?
149
+ left_ancestors << node
150
+ node = node.left_child
151
+ end
152
+ left_ancestors
153
+ end
154
+
155
+ def has_left_child?
156
+ not left_child.nil?
157
+ end
158
+
159
+ def has_right_child?
160
+ not right_child.nil?
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,37 @@
1
+ require 'data_structures/binary_heap'
2
+
3
+ module DataStructures
4
+ class PriorityQueue
5
+ extend Forwardable
6
+
7
+ def self.low_priority
8
+ new(DataStructures::BinaryHeap::LOW_TO_HIGH)
9
+ end
10
+
11
+ def initialize(ordering = DataStructures::BinaryHeap::HIGH_TO_LOW)
12
+ @heap = DataStructures::BinaryHeap.new(ordering)
13
+ end
14
+
15
+ def high_priority?
16
+ @heap.max_heap?
17
+ end
18
+
19
+ def offer(object, priority)
20
+ @heap.insert(ObjectWithPriority.new(object, priority))
21
+ end
22
+
23
+ def poll
24
+ @heap.remove.object
25
+ end
26
+
27
+ private
28
+
29
+ class ObjectWithPriority < Struct.new(:object, :priority)
30
+ include Comparable
31
+
32
+ def <=> other
33
+ priority <=> other.priority
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module DataStructures
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,51 @@
1
+ require 'data_structures/binary_heap'
2
+
3
+ class BinaryHeapTest < Test::Unit::TestCase
4
+ attr_reader :heap
5
+
6
+ def setup
7
+ @heap = DataStructures::BinaryHeap.new
8
+ end
9
+
10
+ def test_binary_heap_has_log_n_insertion
11
+ 126.times do
12
+ heap.insert(SameCounter.new)
13
+ end
14
+
15
+ counter = GreaterCounter.new
16
+ heap.insert(counter)
17
+
18
+ assert_equal(counter, heap.first)
19
+ assert_equal(6, heap.first.count)
20
+ end
21
+
22
+ def test_min_heap_insertion
23
+ heap = DataStructures::BinaryHeap.new(DataStructures::BinaryHeap::LOW_TO_HIGH)
24
+ 126.times do
25
+ heap.insert(SameCounter.new)
26
+ end
27
+
28
+ counter = LessCounter.new
29
+ heap.insert(counter)
30
+ assert_equal(counter, heap.first)
31
+ assert_equal(6, heap.first.count)
32
+ end
33
+
34
+ def test_binary_heap_has_log_n_removal
35
+ 126.times do
36
+ heap.insert(SameCounter.new)
37
+ end
38
+
39
+
40
+ greater_counter = GreaterCounter.new
41
+ heap.insert(greater_counter)
42
+ less_counter = LessCounter.new
43
+ heap.insert(less_counter)
44
+
45
+ assert_equal(greater_counter, heap.remove)
46
+ assert_equal(127, heap.size)
47
+ assert_equal(less_counter, heap.last)
48
+ # 1 comparison on insertion, 6 on removal
49
+ assert_equal(7, heap.last.count)
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ require 'data_structures/binary_search_tree'
2
+
3
+ class BinarySearchTreeTest < Test::Unit::TestCase
4
+ attr_reader :tree
5
+
6
+ def setup
7
+ @tree = DataStructures::BinarySearchTree.new
8
+ end
9
+
10
+ def test_binary_search_tree_insertion
11
+ 26.times do
12
+ tree.insert(LessCounter.new)
13
+ end
14
+
15
+ counter = SameCounter.new
16
+ assert(tree.insert(counter))
17
+ refute(tree.insert(SameCounter.new))
18
+ assert_includes(tree.in_order, counter)
19
+ assert_equal(27, tree.size)
20
+ end
21
+
22
+ def test_in_order_gives_the_sorted_order
23
+ (1..10).each do |n|
24
+ tree.insert(n)
25
+ end
26
+
27
+ assert_equal(tree.in_order, (1..10).to_a)
28
+ end
29
+
30
+ def test_binary_search_tree_removal
31
+ (1..10).each do |n|
32
+ tree.insert(n)
33
+ end
34
+
35
+ assert(tree.remove(1))
36
+ end
37
+
38
+ def test_binary_search_tree_get
39
+ 126.times do
40
+ tree.insert(LessCounter.new)
41
+ end
42
+
43
+ counter = LessCounter.new
44
+ assert(tree.insert(counter))
45
+
46
+ assert(tree.get(counter))
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ require 'data_structures/priority_queue'
2
+
3
+ class PriorityQueueTest < Test::Unit::TestCase
4
+ attr_reader :queue
5
+
6
+ def setup
7
+ @queue = DataStructures::PriorityQueue.new
8
+ end
9
+
10
+ def test_priority_queue_defaults_to_high_priority
11
+ assert(queue.high_priority?)
12
+ end
13
+
14
+ def test_high_priority_queue_poll
15
+ 126.times do |n|
16
+ queue.offer(Object.new, n)
17
+ end
18
+
19
+ object = Object.new
20
+ queue.offer(object, 200)
21
+
22
+ assert_equal(object, queue.poll)
23
+ end
24
+
25
+ def test_low_priority_queue_poll
26
+ queue = DataStructures::PriorityQueue.low_priority
27
+ 100.downto(10) do |n|
28
+ queue.offer(Object.new, n)
29
+ end
30
+
31
+ object = Object.new
32
+ queue.offer(object, 1)
33
+
34
+ assert_equal(object, queue.poll)
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ require 'test/unit'
2
+
3
+ class SameCounter
4
+ include Comparable
5
+ attr_accessor :count
6
+
7
+ def initialize
8
+ @count = 0
9
+ end
10
+
11
+ def <=>(other)
12
+ @count += 1
13
+ other.count += 1
14
+ 0
15
+ end
16
+ end
17
+
18
+ class LessCounter
19
+ include Comparable
20
+ attr_accessor :count
21
+
22
+ def initialize
23
+ @count = 0
24
+ end
25
+
26
+ def <=>(other)
27
+ @count += 1
28
+ -1
29
+ end
30
+ end
31
+
32
+ class GreaterCounter
33
+ include Comparable
34
+ attr_accessor :count
35
+
36
+ def initialize
37
+ @count = 0
38
+ end
39
+
40
+ def <=>(other)
41
+ @count += 1
42
+ other.count += 1
43
+ 1
44
+ end
45
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: data_structures
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Isaac Sanders
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Data Structures that I decided to implement.
15
+ email:
16
+ - isaac@isaacbfsanders.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - data_structures.gemspec
27
+ - lib/data_structures.rb
28
+ - lib/data_structures/binary_heap.rb
29
+ - lib/data_structures/binary_search_tree.rb
30
+ - lib/data_structures/priority_queue.rb
31
+ - lib/data_structures/version.rb
32
+ - test/data_structures/binary_heap_test.rb
33
+ - test/data_structures/binary_search_tree_test.rb
34
+ - test/data_structures/priority_queue_test.rb
35
+ - test/test_helper.rb
36
+ homepage: http://isaacbfsanders.com/data_structures
37
+ licenses: []
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ segments:
49
+ - 0
50
+ hash: 4132526296573747409
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ segments:
58
+ - 0
59
+ hash: 4132526296573747409
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 1.8.24
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Data Structures that I decided to implement.
66
+ test_files:
67
+ - test/data_structures/binary_heap_test.rb
68
+ - test/data_structures/binary_search_tree_test.rb
69
+ - test/data_structures/priority_queue_test.rb
70
+ - test/test_helper.rb