data_structures_rmolinari 0.5.7 → 0.5.8

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.
@@ -15,7 +15,7 @@ module DataStructuresRMolinari::Algorithms
15
15
  # Maheshwari, A., Nandy, S. C., Smid, M., _An In-Place Min-max Priority Search Tree_, Computational Geometry, v46 (2013), pp
16
16
  # 310-327.
17
17
  #
18
- # It runs in O(m log n) time, where m is the number of MERs enumerated and n is the number of points in P. (Contructing the
18
+ # It runs in O(m log n) time, where m is the number of MERs enumerated and n is the number of points in P. (Constructing the
19
19
  # MaxPST takes O(n log^2 n) time, but m = O(n^2) so we are still O(m log n) overall.)
20
20
  #
21
21
  # @param points [Array] an array of points in the x-y plane. Each must respond to +x+ and +y+.
@@ -30,6 +30,8 @@ module DataStructuresRMolinari::Algorithms
30
30
  sorted_points = points.sort_by(&:x)
31
31
  x_min = sorted_points.first.x
32
32
  x_max = sorted_points.last.x
33
+
34
+ # This is O(n). But it also O(m) beacause consecutive pairs of points produce a type 1 rectangle.
33
35
  y_min, y_max = sorted_points.map(&:y).minmax
34
36
 
35
37
  # Enumerate type 1
@@ -94,4 +96,35 @@ module DataStructuresRMolinari::Algorithms
94
96
  end
95
97
  end
96
98
  end
99
+
100
+ # Given an enumerable and a number k, return the k smallest items from the enumerable in ascending order.
101
+ #
102
+ # If a block is given, each element is yielded to the block to determin its sort key. Otherwise each element is its own sort key.
103
+ #
104
+ # We use a heap of size k. Run time is O(n log k).
105
+ #
106
+ # TODO: offer to return the best k items unsorted, which will be slightly faster. This requires changing Heap to produce the
107
+ # contents all at once. Probably not worth the trouble.
108
+ def self.first_k(enumerable, k, &block)
109
+ heap = DataStructuresRMolinari::Heap.new(max_heap: true, addressable: false)
110
+
111
+ enumerable.each do |item|
112
+ priority = if block_given?
113
+ yield item
114
+ else
115
+ item
116
+ end
117
+
118
+ if heap.size < k
119
+ heap.insert(item, priority)
120
+ elsif priority < heap.top_priority
121
+ heap.pop
122
+ heap.insert(item, priority)
123
+ end
124
+ end
125
+
126
+ result = []
127
+ result << heap.pop until heap.empty?
128
+ result.reverse
129
+ end
97
130
  end
@@ -42,7 +42,8 @@ require_relative 'shared'
42
42
  # DOI 10.1007/s00224-017-9760-2
43
43
  #
44
44
  # @todo
45
- # - let caller see the priority of the top element. Maybe this is useful sometimes.
45
+ # - allow a priority-calculation lambda to be specified at construction. This would mean client code doesn't have to worry about
46
+ # it.
46
47
  class DataStructuresRMolinari::Heap
47
48
  include Shared
48
49
  include Shared::BinaryTreeArithmetic
@@ -87,7 +87,7 @@ require_relative 'shared'
87
87
  #
88
88
  # So, we may say that queries on open regions will work as expected if either
89
89
  # - all coordinates of the points in the PST are finite Ruby Floats, or
90
- # - all coordinates of the points are finite Numeric values and for no such pair of x-values s, t (or pair of y-values) is it such
90
+ # - all coordinates of the points are finite Numeric values and for no such pair of x-values s < t (or pair of y-values) is it true
91
91
  # that +s.to_f.next_float > t+.
92
92
  #
93
93
  # Otherwise, use this functionality at your own risk, and not at all with coordinates that do not respond reasonably to +to_f+.
@@ -22,7 +22,8 @@ require_relative 'shared'
22
22
  # et al. But we don't do that, as we create a separate array of Points.
23
23
  # - Whereas the implementation of MaxPST means that client code gets the same (x, y) objects back in results as it passed into the
24
24
  # contructor, that's not the case here.
25
- # - we map each point in the input - which is an object responding to +#x+ and +#y+ - to an instance of +Point+, and will return (different) instances of +Point+ in response to queries.
25
+ # - we map each point in the input - which is an object responding to +#x+ and +#y+ - to an instance of +Point+, and will return
26
+ # (different) instances of +Point+ in response to queries.
26
27
  # - client code is unlikely to care, but be aware of this, just in case.
27
28
  #
28
29
  # Given a set of n points, we can answer the following questions quickly:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_structures_rmolinari
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.7
4
+ version: 0.5.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rory Molinari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
11
+ date: 2025-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: must_be
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  requirements: []
125
- rubygems_version: 3.4.5
125
+ rubygems_version: 3.3.26
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: Several miscellaneous data structures I have implemented to learn about them.