algorithms 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cee1c06e078dc124212a3462d765d26ce5fbe16dd6b31ca6392388d8f51644c
4
- data.tar.gz: 491e3540ee5567752d208bb7b8502d1ee998b55e9664c66b5cf5fc17394e10e7
3
+ metadata.gz: 2710897393899fe90ddd5a3046f0fee0dd6d29aec842879ec28654e2767d1626
4
+ data.tar.gz: 8ccc55227d725e590ea965767765c29bb66211866cc948d81a3ed4997d6db733
5
5
  SHA512:
6
- metadata.gz: a4a533a2053ae799f87df22b51ff93744e8128e0982239f3d6717bfb6f8ee8817d9c6ebffd6b4a2b478694a3f2f742fc4465eba242e5d2d0d23bfc0c881c1daa
7
- data.tar.gz: 4ffaed30fc92fca18dd258102a702f8fceb1a77594ac6b086c627e1a3ab8ae1ad6650295acd0fb423a6ce441b6b7ab686bb56ae9ff937448d031f319d937a427
6
+ metadata.gz: 8fd77563ddfaecf2ab085f4ff9da6b49e0c63cb65ea666ebf737a3aee175498ddb481908b2135d3ae861ae51f756f9abc9749d27a91d802b4fd8c32965d8a117
7
+ data.tar.gz: d002eba1aa937be5f7afc70e32155dccb108ef5d71cc874729379b403534e34122311234aab35f05c4c1a2df5b0ecfc7fed32b645c2865d1a59b1b911a3564dd
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,7 @@
1
+ === August 20, 2025
2
+
3
+ * Fix Heap not working in certain cases
4
+
1
5
  === January 22, 2013
2
6
 
3
7
  * JRuby support
data/README.markdown CHANGED
@@ -1,4 +1,4 @@
1
- # algorithms [![Build Status](https://travis-ci.org/kanwei/algorithms.png)](https://travis-ci.org/kanwei/algorithms)
1
+ # algorithms [![Ruby CI](https://github.com/kanwei/algorithms/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/kanwei/algorithms/actions/workflows/ci.yml)
2
2
 
3
3
  [API Documentation](http://kanwei.github.io/algorithms/)
4
4
 
@@ -8,7 +8,7 @@ Started as a [Google Summer of Code 2008](http://code.google.com/soc/2008/ruby/a
8
8
 
9
9
  Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
10
10
 
11
- ### Original Proposal: ###
11
+ ## Original Proposal: ##
12
12
 
13
13
  Using the right data structure or algorithm for the situation is an important
14
14
  aspect of programming. In computer science literature, many data structures
data/algorithms.gemspec CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "algorithms"
5
- s.version = "1.0.0"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.authors = ["Kanwei Li"]
8
8
  s.email = "kanwei@gmail.com"
9
9
  s.license = 'MIT'
10
- s.date = "2021-04-04"
10
+ s.date = "2023-11-11"
11
11
  s.summary = "Useful algorithms and data structures for Ruby. Optional C extensions."
12
12
  s.description = "Heap, Priority Queue, Deque, Stack, Queue, Red-Black Trees, Splay Trees, sorting algorithms, and more"
13
13
  if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
@@ -10,7 +10,6 @@
10
10
  This library implements a Fibonacci heap, which allows O(1) complexity for most methods.
11
11
  =end
12
12
  class Containers::Heap
13
- include Enumerable
14
13
 
15
14
  # call-seq:
16
15
  # size -> int
@@ -75,13 +74,6 @@ class Containers::Heap
75
74
  end
76
75
  @size += 1
77
76
 
78
- arr = []
79
- w = @next.right
80
- until w == @next do
81
- arr << w.value
82
- w = w.right
83
- end
84
- arr << @next.value
85
77
  @stored[key] ||= []
86
78
  @stored[key] << node
87
79
  value
@@ -376,7 +368,7 @@ class Containers::Heap
376
368
  degree += 1
377
369
  end
378
370
  degrees[degree] = root
379
- min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
371
+ min = root if !@compare_fn[min.key, root.key] # this fixes a bug with duplicate keys not being in the right order
380
372
  end
381
373
  end
382
374
  @next = min
@@ -10,7 +10,6 @@ require 'containers/heap'
10
10
  This container is implemented using the Fibonacci heap included in the Collections library.
11
11
  =end
12
12
  class Containers::PriorityQueue
13
- include Enumerable
14
13
 
15
14
  # Create a new, empty PriorityQueue
16
15
  def initialize(&block)
@@ -15,7 +15,7 @@ require 'containers/stack'
15
15
  explicitly used as well; their functionality is identical.
16
16
 
17
17
  Most methods have O(log n) complexity.
18
-
18
+
19
19
  =end
20
20
  class Containers::RubyRBTreeMap
21
21
  include Enumerable
@@ -160,7 +160,7 @@ class Containers::RubyRBTreeMap
160
160
  result
161
161
  end
162
162
 
163
- # Deletes the item with the smallest key and returns the item. Returns nil
163
+ # Deletes the item with the largest key and returns the item. Returns nil
164
164
  # if key is not present.
165
165
  #
166
166
  # Complexity: O(log n)
@@ -12,10 +12,10 @@ class Containers::SuffixArray
12
12
  #
13
13
  # Complexity: O(n^2 log n)
14
14
  #
15
- # s_array = Containers::SuffixArray("abracadabra")
15
+ # s_array = Containers::SuffixArray.new("abracadabra")
16
16
  # s_array["abra"] #=> true
17
17
  #
18
- # number = Containers::SuffixArray(1234567)
18
+ # number = Containers::SuffixArray.new(1234567)
19
19
  # number[1] #=> true
20
20
  # number[13] #=> false
21
21
  def initialize(string)
@@ -65,4 +65,4 @@ class Containers::SuffixArray
65
65
  return false
66
66
  end
67
67
  alias_method :[], :has_substring?
68
- end
68
+ end
data/spec/heap_spec.rb CHANGED
@@ -1,10 +1,196 @@
1
1
  $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
2
  require 'algorithms'
3
3
 
4
+ include Comparable
5
+
6
+ class Book
7
+ attr_reader :title, :year_published
8
+
9
+ def initialize(title, year_published)
10
+ @title = title
11
+ @year_published = year_published
12
+ end
13
+
14
+ def <=>(other)
15
+ return nil unless other.is_a?(Book)
16
+
17
+ # 1. Compare by year first
18
+ year_comparison = self.year_published <=> other.year_published
19
+
20
+ # 2. If years are different, return that comparison result
21
+ return year_comparison unless year_comparison == 0
22
+
23
+ # 3. If years are the same (tie), compare by title alphabetically
24
+ # (Ensure title comparison returns -1, 0, or 1)
25
+ self.title <=> other.title
26
+ end
27
+
28
+
29
+ def to_s
30
+ "\"#{title}\" (#{year_published})" # Simplified for test output
31
+ end
32
+
33
+ # Add an equality method for clearer test failures if needed,
34
+ # though <=> returning 0 handles equality for sorting/heap purposes.
35
+ def ==(other)
36
+ other.is_a?(Book) &&
37
+ self.title == other.title &&
38
+ self.year_published == other.year_published
39
+ end
40
+ alias eql? ==
41
+
42
+ def hash
43
+ [title, year_published].hash
44
+ end
45
+
46
+ end
47
+
48
+ describe ::Containers::Heap do
49
+
50
+ # --- Test Data Setup ---
51
+ let!(:book_1932) { Book.new("Brave New World", 1932) }
52
+ let!(:book_1949) { Book.new("1984", 1949) }
53
+ let!(:book_1951a) { Book.new("Foundation", 1951) }
54
+ # Add another book from the same year to test handling of equal priority items
55
+ let!(:book_1951b) { Book.new("The Illustrated Man", 1951) }
56
+ let!(:book_1965) { Book.new("Dune", 1965) }
57
+ let!(:book_1989) { Book.new("Hyperion", 1989) }
58
+
59
+ # Use shuffle to ensure tests don't depend on insertion order
60
+ let(:books) { [book_1965, book_1951a, book_1989, book_1949, book_1932, book_1951b].shuffle }
61
+
62
+ let(:expected_min_order) { books.sort }
63
+
64
+ let(:expected_max_order) { books.sort.reverse }
65
+
66
+ context "Min-Heap (using default <=> via Comparable)" do
67
+ # Initialize heap with books; it should use Book#<=> by default
68
+ let(:min_heap) { ::Containers::Heap.new(books) }
69
+
70
+ it "initializes with the correct size" do
71
+ expect(min_heap.size).to eq(books.size)
72
+ expect(min_heap.empty?).to be false
73
+ end
74
+
75
+ it "gets the next minimum element (earliest year) without removing it" do
76
+ # next should return the element with the smallest year_published
77
+ expect(min_heap.next).to eq(book_1932)
78
+ # next should not change the size
79
+ expect(min_heap.size).to eq(books.size)
80
+ end
81
+
82
+ it "pops elements in ascending order of year_published" do
83
+ popped_books = []
84
+ while (book = min_heap.pop)
85
+ popped_books << book
86
+ end
87
+
88
+ # Verify the popped order matches the expected sorted order
89
+ expect(popped_books).to eq(expected_min_order)
90
+
91
+ # Verify the heap is now empty
92
+ expect(min_heap.size).to eq(0)
93
+ expect(min_heap.empty?).to be true
94
+ expect(min_heap.pop).to be_nil # Popping an empty heap
95
+ expect(min_heap.next).to be_nil # Getting next from an empty heap
96
+ end
97
+
98
+ it "correctly updates size after popping" do
99
+ expect(min_heap.size).to eq(books.size)
100
+ min_heap.pop
101
+ expect(min_heap.size).to eq(books.size - 1)
102
+ end
103
+ end
104
+
105
+
106
+ context "Max-Heap (using a custom comparison block)" do
107
+ # Initialize heap with books and a block for max-heap behavior
108
+ # The block returns true if x should have higher priority (be "larger") than y
109
+ let(:max_heap) { ::Containers::Heap.new(books) { |x, y| x > y } } # Use > from Comparable
110
+
111
+ it "initializes with the correct size" do
112
+ expect(max_heap.size).to eq(books.size)
113
+ expect(max_heap.empty?).to be false
114
+ end
115
+
116
+ it "gets the next maximum element (latest year) without removing it" do
117
+ # next should return the element with the largest year_published
118
+ expect(max_heap.next).to eq(book_1989)
119
+ # next should not change the size
120
+ expect(max_heap.size).to eq(books.size)
121
+ end
122
+
123
+ it "pops elements in descending order of year_published" do
124
+ popped_books = []
125
+ while (book = max_heap.pop)
126
+ popped_books << book
127
+ end
128
+
129
+ # Verify the popped order matches the expected reversed sorted order
130
+ expect(popped_books).to eq(expected_max_order)
131
+
132
+ # Verify the heap is now empty
133
+ expect(max_heap.size).to eq(0)
134
+ expect(max_heap.empty?).to be true
135
+ expect(max_heap.pop).to be_nil # Popping an empty heap
136
+ expect(max_heap.next).to be_nil # Getting next from an empty heap
137
+ end
138
+
139
+ it "correctly updates size after popping" do
140
+ expect(max_heap.size).to eq(books.size)
141
+ max_heap.pop
142
+ expect(max_heap.size).to eq(books.size - 1)
143
+ end
144
+ end
145
+
146
+ context "Edge cases" do
147
+ it "handles an empty initialization" do
148
+ heap = ::Containers::Heap.new([])
149
+ expect(heap.size).to eq(0)
150
+ expect(heap.empty?).to be true
151
+ expect(heap.pop).to be_nil
152
+ expect(heap.next).to be_nil
153
+ end
154
+
155
+ it "handles initialization with one element" do
156
+ heap = ::Containers::Heap.new([book_1965])
157
+ expect(heap.size).to eq(1)
158
+ expect(heap.next).to eq(book_1965)
159
+ expect(heap.pop).to eq(book_1965)
160
+ expect(heap.empty?).to be true
161
+ end
162
+ end
163
+
164
+ end
165
+
4
166
  describe Containers::Heap do
5
167
  before(:each) do
6
168
  @heap = Containers::MaxHeap.new
7
169
  end
170
+
171
+ it "should run without error when given Objects and a non-ordering comparator" do
172
+ # Create and store the initial distinct objects
173
+ initial_objects = 10.times.map { Object.new }
174
+ initial_object_ids = initial_objects.map(&:object_id) # Store IDs for comparison
175
+
176
+ min_heap = ::Containers::Heap.new(initial_objects) { |x, y| (x <=> y) == -1 }
177
+
178
+ expect(min_heap.size).to eq(10)
179
+
180
+ popped_elements = []
181
+ expect {
182
+ while val = min_heap.pop do
183
+ popped_elements << val
184
+ end
185
+ }.not_to raise_error
186
+
187
+ expect(min_heap.empty?).to be true
188
+ expect(popped_elements.size).to eq(10)
189
+
190
+ # Assert that exactly the same objects were returned, regardless of order.
191
+ # Comparing by object_id is the most reliable way for distinct Objects.
192
+ expect(popped_elements.map(&:object_id)).to contain_exactly(*initial_object_ids)
193
+ end
8
194
 
9
195
  it "should not let you merge with non-heaps" do
10
196
  expect { @heap.merge!(nil) }.to raise_error(ArgumentError)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algorithms
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kanwei Li
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-04-04 00:00:00.000000000 Z
10
+ date: 2023-11-11 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: Heap, Priority Queue, Deque, Stack, Queue, Red-Black Trees, Splay Trees,
14
13
  sorting algorithms, and more
@@ -78,7 +77,6 @@ homepage: https://github.com/kanwei/algorithms
78
77
  licenses:
79
78
  - MIT
80
79
  metadata: {}
81
- post_install_message:
82
80
  rdoc_options:
83
81
  - "--line-numbers"
84
82
  - "--inline-source"
@@ -100,8 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
98
  - !ruby/object:Gem::Version
101
99
  version: '0'
102
100
  requirements: []
103
- rubygems_version: 3.1.2
104
- signing_key:
101
+ rubygems_version: 3.6.9
105
102
  specification_version: 4
106
103
  summary: Useful algorithms and data structures for Ruby. Optional C extensions.
107
104
  test_files: []