ds 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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: