ds 0.0.6 → 0.0.7

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: d82d8b78c713c1df3c2a90ffba31fbb3cc0ec832
4
- data.tar.gz: 852f880007ed7ea444aeed7754793510f39c370b
3
+ metadata.gz: 28bf2a3cbdf0ab712586b7ff90baf472f0375077
4
+ data.tar.gz: 676f9c0d70b61cae0f139231bdb67dab74dcce6f
5
5
  SHA512:
6
- metadata.gz: dbfa87fdd20983378f200df765f5f5b9869539d4e5bf038cabe90e746b7b897b24d48d917d5e85980bb6494748b46d3424af903e530aee61a69fd271c2c4a334
7
- data.tar.gz: f9fa767205e56d6424dbe304db426dd19673716cf2335cdde7c7f960128f65fece05208dd24d79f69dcf6b548f1189e412aa409eb41601275b83aa8adf222cee
6
+ metadata.gz: 813d6d229876d8381509fcacb9343e1509366fab0c9892e8583a684bcb41a7e0f9e4c6314105548025d720d750a18b8876504b4dd9902fc71cce38baa8094363
7
+ data.tar.gz: eb40a6f12a53432b67afa580c9db20de3a11d066b6d5eeec5ce82d7491e6c0167c126dcccd1c9921929f807da1be57433291d79cdfa3919d7a35f19a67b2b9c6
@@ -160,6 +160,32 @@ Examples:
160
160
  q.peek #=> :nevermind
161
161
 
162
162
 
163
+ ==== Indexed Priority Queue
164
+
165
+ Indexed Priority Queue is special form of PriorityQueue with constant access to any element.
166
+ Additionaly you can easily change priority of any element stored on queue.
167
+
168
+ Creating new Indexed Priority Queue
169
+ q = IndexedPriorityQueue.new
170
+ or
171
+ IndexedPriorityQueue.new { |a, b| a.key < b.key }
172
+
173
+ IndexedPriorityQueue inherits from PriorityQueue so all methods from PriorityQueue are available.
174
+
175
+ Examples:
176
+ q.push(:important, 3)
177
+ q.push(:very_important, 5)
178
+ q.push(:nevermind, 1)
179
+
180
+ q.peek #=> :very_important
181
+
182
+ q.change(:nevermind, 10)
183
+ q.peek #=> :nevermind
184
+
185
+ Elements stored on priority queue are wrapped in Pair object, when you call get method this object is returned:
186
+ q.get(:very_important) #=> Pair.new(5, :very_important)
187
+ q.include?(:very_important) #=> true
188
+
163
189
  === Lists
164
190
 
165
191
  === List
data/ds.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = DS::VERSION
8
8
  s.authors = ['knife']
9
9
  s.email = ['satre@o2.pl']
10
- s.homepage = ''
10
+ s.homepage = 'https://github.com/knife/ds'
11
11
  s.summary = 'Some common data structures.'
12
12
  s.description = 'Data structures (lists, stacks, trees, heaps, graphs..) in pure Ruby.'
13
13
  s.rubyforge_project = 'ds'
data/lib/ds.rb CHANGED
@@ -6,6 +6,7 @@ require 'ds/arrays/expandable_array'
6
6
  require 'ds/arrays/array_2d'
7
7
  require 'ds/arrays/tri_matrix'
8
8
  require 'ds/arrays/heap_store'
9
+ require 'ds/arrays/indexed_heap_store'
9
10
 
10
11
  require 'ds/sets/indexed_set'
11
12
 
@@ -15,11 +16,13 @@ require 'ds/lists/list'
15
16
  require 'ds/stacks/stack'
16
17
  require 'ds/queues/simple_queue'
17
18
  require 'ds/queues/priority_queue'
19
+ require 'ds/queues/indexed_priority_queue'
18
20
 
19
21
  require 'ds/trees/tree'
20
22
  require 'ds/trees/tree_walker'
21
23
  require 'ds/trees/binary_tree'
22
24
  require 'ds/trees/binary_heap'
25
+ require 'ds/trees/indexed_binary_heap'
23
26
  require 'ds/trees/red_black_tree'
24
27
  require 'ds/trees/red_black_tree/node'
25
28
  require 'ds/trees/trie'
@@ -28,5 +28,11 @@ module DS
28
28
  def to_a
29
29
  @store[1..-1]
30
30
  end
31
+
32
+ def swap(x, y)
33
+ temp = self[y]
34
+ self[y] = self[x]
35
+ self[x] = temp
36
+ end
31
37
  end
32
38
  end
@@ -0,0 +1,49 @@
1
+ module DS
2
+ # HeapStore with constant access to any element
3
+ class IndexedHeapStore < HeapStore
4
+
5
+ def_delegators :@store, :[]
6
+
7
+ def initialize(*args)
8
+ args = args.to_a
9
+ @map = {}
10
+ args.each_with_index do |e, i|
11
+ raise ArgumentError, 'Duplicates are not allowed' if @map[e.value]
12
+ @map[e.value] = i + 1
13
+ end
14
+ @store = [nil] + args
15
+ end
16
+
17
+ def pop
18
+ x = @store.pop
19
+ @map.delete(x)
20
+ x
21
+ end
22
+
23
+ def []=(i, x)
24
+ @map[x.value] = i
25
+ @store[i] = x
26
+ end
27
+
28
+ def push(x)
29
+ return if @map[x.value]
30
+ last = @store.size
31
+ @store.push x
32
+ @map[x.value] = last
33
+ end
34
+
35
+ def index(x)
36
+ @map[x]
37
+ end
38
+
39
+ def get(x)
40
+ self[index(x)] if index(x)
41
+ end
42
+
43
+ def swap(x, y)
44
+ super
45
+ @map[self[x].value] = x
46
+ @map[self[y].value] = y
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,32 @@
1
+ module DS
2
+ # Indexed Priority Queue
3
+ class IndexedPriorityQueue < PriorityQueue
4
+ attr_reader :store
5
+ private :store
6
+
7
+ # Creates new IndexedPriorityQueue from args.
8
+ # This is special form of PriorityQueue where you can
9
+ # access any element and update its priority
10
+ def initialize(*args)
11
+ @store = if block_given?
12
+ IndexedBinaryHeap.new(*args) do |parent, child|
13
+ yield parent.key, child.key
14
+ end
15
+ else
16
+ IndexedBinaryHeap.new(*args) { |parent, child| parent.key >= child.key }
17
+ end
18
+ end
19
+
20
+ def update(x, priority)
21
+ store.change_priority(x, priority)
22
+ end
23
+
24
+ def get(x)
25
+ store.get(x)
26
+ end
27
+
28
+ def include?(x)
29
+ store.include?(x)
30
+ end
31
+ end
32
+ end
@@ -12,6 +12,10 @@ module DS
12
12
  end
13
13
  end
14
14
 
15
+ def self.min(*args)
16
+ new(*args) { |parent, child| parent < child }
17
+ end
18
+
15
19
  # Adds element to queue with given priority.
16
20
  def enqueue(x, priority)
17
21
  pair = Pair.new(priority, x)
@@ -3,8 +3,9 @@ module DS
3
3
  # Internaly uses array or linked list to store elements.
4
4
  class Stack
5
5
  def initialize(*args)
6
- @store = if args.first.is_a? List
7
- args.first
6
+ first = args.first
7
+ @store = if first.is_a? List
8
+ first
8
9
  else
9
10
  args || []
10
11
  end
@@ -0,0 +1,46 @@
1
+ module DS
2
+ # Indexed BinaryHeap
3
+ class IndexedBinaryHeap < BinaryHeap
4
+ # Create new IndexedHeap from args.
5
+ # Given block is used to set heap relation.
6
+ # Default heap relation is Max Heap.
7
+ def initialize(*args, &block)
8
+ @relation = if block_given?
9
+ block
10
+ else
11
+ -> (parent, child) { parent.key >= child.key }
12
+ end
13
+ @store = IndexedHeapStore.new(*args)
14
+ heapify!
15
+ end
16
+
17
+ def change_priority(x, priority)
18
+ node = get(x)
19
+ old_priority = node.key
20
+ return if old_priority == priority
21
+
22
+ node.key = priority
23
+ index = store.index(node.value)
24
+
25
+ if higher?(priority, old_priority)
26
+ swim(index)
27
+ else
28
+ sink(index)
29
+ end
30
+ end
31
+
32
+ def get(x)
33
+ store.get(x)
34
+ end
35
+
36
+ def include?(x)
37
+ get(x) ? true : false
38
+ end
39
+
40
+ private
41
+
42
+ def higher?(new_priority, old_priority)
43
+ @relation.call(Pair.new(new_priority, nil), Pair.new(old_priority, nil))
44
+ end
45
+ end
46
+ end
@@ -1,4 +1,4 @@
1
1
  # Main module namespace
2
2
  module DS
3
- VERSION = '0.0.6'.freeze
3
+ VERSION = '0.0.7'.freeze
4
4
  end
@@ -31,4 +31,9 @@ describe HeapStore do
31
31
  @store.to_a.must_equal [1, 2, 3, 4, 5, 6, 7]
32
32
  @store.to_a.must_be_kind_of Array
33
33
  end
34
+
35
+ it '#swap swaps elements in store' do
36
+ @store.swap(1, 7)
37
+ @store.to_a.must_equal [7, 2, 3, 4, 5, 6, 1]
38
+ end
34
39
  end
@@ -0,0 +1,45 @@
1
+ require 'help'
2
+
3
+ describe IndexedBinaryHeap do
4
+ before do
5
+ @nine = Pair.new(9, :nine)
6
+ @eight = Pair.new(8, :eight)
7
+ @four = Pair.new(4, :four)
8
+ @five = Pair.new(5, :five)
9
+ @eleven = Pair.new(11, :eleven)
10
+ @six = Pair.new(6, :six)
11
+
12
+ @arr = [@nine, @eight, @four, @five, @eleven, @six]
13
+ @heap = IndexedBinaryHeap.new(*@arr)
14
+ end
15
+
16
+ it 'creates heap from array.' do
17
+ @heap.to_a.must_equal [@eleven, @nine, @six, @five, @eight, @four]
18
+ end
19
+
20
+ it '#change_priority changes priority for given heap element.' do
21
+ @heap.change_priority(:five, 20)
22
+ @heap.top.value.must_equal :five
23
+ end
24
+
25
+ it '#insert adds new element maintaining heap relation.' do
26
+ @heap.size.must_equal 6
27
+ fourteen = Pair.new(14, :fourteen)
28
+ @heap.insert(fourteen).to_a.must_equal [fourteen, @nine, @eleven, @five, @eight, @four, @six]
29
+ @heap.size.must_equal 7
30
+ end
31
+
32
+ it '#top returns max or min heap element.' do
33
+ @heap.top.must_equal @eleven
34
+ @heap.shift
35
+ @heap.top.must_equal @nine
36
+ end
37
+
38
+ it '#shift removes element from heap maintaining heap relation.' do
39
+ @heap.shift.must_equal @eleven
40
+ @heap.to_a.must_equal [@nine, @eight, @six, @five, @four]
41
+ @heap.shift.must_equal @nine
42
+ @heap.to_a.must_equal [@eight, @five, @six, @four]
43
+ @heap.shift.must_equal @eight
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ require 'help'
2
+
3
+ describe IndexedHeapStore do
4
+ before do
5
+ @first = Pair.new(1, 1)
6
+ @second = Pair.new(2, 2)
7
+ @third = Pair.new(3, 3)
8
+ @fourth = Pair.new(4, 4)
9
+ @store = IndexedHeapStore.new(@first, @second, @third, @fourth)
10
+ end
11
+
12
+ it '#new raises error if arguments contains duplicates' do
13
+ proc { IndexedHeapStore.new(Pair.new(1, 9), Pair.new(2, 9)) }
14
+ .must_raise ArgumentError
15
+ end
16
+
17
+ it '#size returns store size.' do
18
+ @store.size.must_equal 4
19
+ end
20
+
21
+ it 'indexing starts form one.' do
22
+ @store[1].must_equal @first
23
+ end
24
+
25
+ it '#first returns element at index 1.' do
26
+ @store.first.must_equal @first
27
+ end
28
+
29
+ describe '#pop' do
30
+ it 'removes last element.' do
31
+ @store.pop.must_equal @fourth
32
+ @store.size.must_equal 3
33
+ end
34
+
35
+ it 'updates store index' do
36
+ last = @store.pop
37
+ @store.index(last).must_be_nil
38
+ @store.get(last).must_be_nil
39
+ end
40
+ end
41
+
42
+ describe '#push' do
43
+ it 'adds element to store.' do
44
+ fifth = Pair.new(5, 5)
45
+ @store.push fifth
46
+ @store.size.must_equal 5
47
+ end
48
+
49
+ it 'ignores duplicates.' do
50
+ @store.push(@first).must_be_nil
51
+ @store.size.must_equal 4
52
+
53
+ @store.push(Pair.new(1, 1)).must_be_nil
54
+ @store.size.must_equal 4
55
+ end
56
+ end
57
+
58
+ it '#index returns heap index for given element' do
59
+ @store.index(@first.value).must_equal 1
60
+ @store.index(@third.value).must_equal 3
61
+ @store.index(:not_in_store).must_be_nil
62
+ end
63
+
64
+ it '#get returns element from store' do
65
+ @store.get(1).value.must_equal 1
66
+ @store.get(9).must_be_nil
67
+ end
68
+
69
+ it '#to_a returns array representation.' do
70
+ @store.to_a.must_equal [@first, @second, @third, @fourth]
71
+ @store.to_a.must_be_kind_of Array
72
+ end
73
+
74
+ it '#swap swaps elements in store' do
75
+ @store.swap(1, 4)
76
+ @store.to_a.must_equal [@fourth, @second, @third, @first]
77
+ end
78
+ end
@@ -0,0 +1,139 @@
1
+ require 'help'
2
+
3
+ describe IndexedPriorityQueue do
4
+ describe 'Empty indexed priority queue' do
5
+ before do
6
+ @empty_queue = IndexedPriorityQueue.new
7
+ end
8
+
9
+ it 'is empty.' do
10
+ @empty_queue.must_be_empty
11
+ end
12
+
13
+ it 'has zero elements.' do
14
+ @empty_queue.length.must_equal 0
15
+ end
16
+ end
17
+
18
+ describe 'Not empty indexed priority queue' do
19
+ before do
20
+ @queue = IndexedPriorityQueue.new
21
+ @queue.enqueue :important, 2
22
+ @queue.enqueue :not_important, 1
23
+ end
24
+
25
+ it 'is not empty.' do
26
+ @queue.wont_be_empty
27
+ @queue.length.must_equal 2
28
+ end
29
+
30
+ it '#update changes element priority' do
31
+ @queue.update(:important, 0)
32
+ @queue.peek.must_equal :not_important
33
+ end
34
+
35
+ it '#get returns element from queue' do
36
+ x = @queue.get(:important)
37
+ x.must_be_kind_of Pair
38
+ x.value.must_equal :important
39
+ @queue.peek.must_equal :important
40
+ end
41
+
42
+ it '#include? returns true if element is stored on queue.' do
43
+ @queue.include?(:important).must_equal true
44
+ @queue.include?(:bar).must_equal false
45
+ end
46
+
47
+ it '#peek returns element with highest priority.' do
48
+ @queue.peek.must_equal :important
49
+ end
50
+
51
+ it '#enqueue and #push should add element to priority queue.' do
52
+ @queue.enqueue :very_important, 5
53
+ @queue.push :nevermind, 0
54
+ @queue.length.must_equal 4
55
+ end
56
+
57
+ it '#dequeue and #shift should remove element with highest priority.' do
58
+ x = @queue.dequeue
59
+ @queue.length.must_equal 1
60
+ x.must_equal :important
61
+ @queue.dequeue.must_equal :not_important
62
+ @queue.length.must_equal 0
63
+ @queue.dequeue.must_be_nil
64
+ end
65
+ end
66
+
67
+ describe 'Not empty indexed priority queue with custom order' do
68
+ before do
69
+ @queue = IndexedPriorityQueue.new { |a, b| a < b }
70
+ @queue.enqueue 'gamma', 'g'
71
+ @queue.enqueue 'alpha', 'a'
72
+ @queue.enqueue 'beta', 'b'
73
+ end
74
+
75
+ it 'should not be empty.' do
76
+ refute @queue.empty?
77
+ @queue.length.must_equal 3
78
+ end
79
+
80
+ it '#peek should return element with highest priority.' do
81
+ @queue.peek.must_equal 'alpha'
82
+ end
83
+
84
+ it '#change should change element priority.' do
85
+ @queue.update('alpha', 'l')
86
+ @queue.peek.must_equal('beta')
87
+ end
88
+
89
+ it '#dequeue and #shift should remove element with highest priority.' do
90
+ x = @queue.dequeue
91
+ @queue.length.must_equal 2
92
+ x.must_equal 'alpha'
93
+ @queue.dequeue.must_equal 'beta'
94
+ @queue.length.must_equal 1
95
+ end
96
+ end
97
+
98
+ describe 'IndexedPriorityQueue with duplications' do
99
+ before do
100
+ @dup_queue = IndexedPriorityQueue.new(Pair.new(2, :same_important))
101
+ @dup_queue.enqueue :important, 2
102
+ @dup_queue.enqueue :not_important, 1
103
+ end
104
+
105
+ it 'is not empty.' do
106
+ @dup_queue.wont_be_empty
107
+ @dup_queue.length.must_equal 3
108
+ end
109
+
110
+ it '#peek returns element with highest priority.' do
111
+ [:important, :same_important].must_include @dup_queue.peek
112
+ @dup_queue.dequeue
113
+ [:important, :same_important].must_include @dup_queue.peek
114
+ @dup_queue.dequeue
115
+ @dup_queue.peek.must_equal :not_important
116
+ end
117
+
118
+ it '#enqueue and #push adds element to priority queue.' do
119
+ @dup_queue.push :nevermind, 0
120
+ @dup_queue.push :another_important, 2
121
+ @dup_queue.length.must_equal 5
122
+ end
123
+
124
+ it '#enqueue does\'t add elements that are already in queue.' do
125
+ @dup_queue.dequeue
126
+ @dup_queue.length.must_equal 2
127
+ @dup_queue.enqueue :important, 2
128
+ @dup_queue.length.must_equal 2
129
+ @dup_queue.dequeue.must_equal :important
130
+ @dup_queue.dequeue.must_equal :not_important
131
+ end
132
+
133
+ it '#dequeue and #shift removes element with highest priority.' do
134
+ x = @dup_queue.dequeue
135
+ [:important, :same_important].must_include x
136
+ @dup_queue.length.must_equal 2
137
+ end
138
+ end
139
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ds
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - knife
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-30 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -71,16 +71,19 @@ files:
71
71
  - lib/ds/arrays/array_2d.rb
72
72
  - lib/ds/arrays/expandable_array.rb
73
73
  - lib/ds/arrays/heap_store.rb
74
+ - lib/ds/arrays/indexed_heap_store.rb
74
75
  - lib/ds/arrays/tri_matrix.rb
75
76
  - lib/ds/lists/list.rb
76
77
  - lib/ds/lists/list_element.rb
77
78
  - lib/ds/pair.rb
79
+ - lib/ds/queues/indexed_priority_queue.rb
78
80
  - lib/ds/queues/priority_queue.rb
79
81
  - lib/ds/queues/simple_queue.rb
80
82
  - lib/ds/sets/indexed_set.rb
81
83
  - lib/ds/stacks/stack.rb
82
84
  - lib/ds/trees/binary_heap.rb
83
85
  - lib/ds/trees/binary_tree.rb
86
+ - lib/ds/trees/indexed_binary_heap.rb
84
87
  - lib/ds/trees/red_black_tree.rb
85
88
  - lib/ds/trees/red_black_tree/node.rb
86
89
  - lib/ds/trees/tree.rb
@@ -100,6 +103,9 @@ files:
100
103
  - test/test_binary_tree.rb
101
104
  - test/test_expandable_array.rb
102
105
  - test/test_heap_store.rb
106
+ - test/test_indexed_binary_heap.rb
107
+ - test/test_indexed_heap_store.rb
108
+ - test/test_indexed_priority_queue.rb
103
109
  - test/test_indexed_set.rb
104
110
  - test/test_list.rb
105
111
  - test/test_list_element.rb
@@ -112,7 +118,7 @@ files:
112
118
  - test/test_tree_walker.rb
113
119
  - test/test_tri_matrix.rb
114
120
  - test/test_trie.rb
115
- homepage: ''
121
+ homepage: https://github.com/knife/ds
116
122
  licenses: []
117
123
  metadata: {}
118
124
  post_install_message:
@@ -131,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
137
  version: '0'
132
138
  requirements: []
133
139
  rubyforge_project: ds
134
- rubygems_version: 2.4.5.1
140
+ rubygems_version: 2.4.8
135
141
  signing_key:
136
142
  specification_version: 4
137
143
  summary: Some common data structures.
@@ -142,3 +148,4 @@ test_files:
142
148
  - test/performance/rbt_performance_test.rb
143
149
  - test/performance/simple_queue_performance_test.rb
144
150
  - test/performance/stack_test.rb
151
+ has_rdoc: