stakach-algorithms 1.0.6 → 1.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.
Files changed (48) hide show
  1. data/README.markdown +99 -97
  2. data/Rakefile +15 -27
  3. data/ext/algorithms/string/extconf.rb +4 -4
  4. data/ext/algorithms/string/string.c +68 -70
  5. data/ext/containers/bst/bst.c +249 -249
  6. data/ext/containers/bst/extconf.rb +4 -4
  7. data/ext/containers/deque/deque.c +248 -248
  8. data/ext/containers/deque/extconf.rb +4 -4
  9. data/ext/containers/rbtree_map/extconf.rb +4 -4
  10. data/ext/containers/rbtree_map/rbtree.c +500 -500
  11. data/ext/containers/splaytree_map/extconf.rb +4 -4
  12. data/ext/containers/splaytree_map/splaytree.c +421 -421
  13. data/lib/algorithms.rb +69 -69
  14. data/lib/algorithms/search.rb +85 -85
  15. data/lib/algorithms/sort.rb +242 -242
  16. data/lib/algorithms/string.rb +10 -10
  17. data/lib/algorithms/version.rb +3 -3
  18. data/lib/containers/deque.rb +176 -176
  19. data/lib/containers/heap.rb +501 -506
  20. data/lib/containers/kd_tree.rb +112 -112
  21. data/lib/containers/priority_queue.rb +116 -116
  22. data/lib/containers/queue.rb +71 -71
  23. data/lib/containers/rb_tree_map.rb +402 -402
  24. data/lib/containers/splay_tree_map.rb +273 -273
  25. data/lib/containers/stack.rb +70 -70
  26. data/lib/containers/suffix_array.rb +71 -71
  27. data/lib/containers/trie.rb +187 -187
  28. data/spec/bst_gc_mark_spec.rb +25 -0
  29. data/spec/bst_spec.rb +25 -0
  30. data/spec/deque_gc_mark_spec.rb +17 -0
  31. data/spec/deque_spec.rb +107 -0
  32. data/spec/heap_spec.rb +130 -0
  33. data/spec/helper.rb +4 -0
  34. data/spec/kd_expected_out.txt +10000 -0
  35. data/spec/kd_test_in.txt +10000 -0
  36. data/spec/kd_tree_spec.rb +33 -0
  37. data/spec/map_gc_mark_spec.rb +28 -0
  38. data/spec/priority_queue_spec.rb +74 -0
  39. data/spec/queue_spec.rb +60 -0
  40. data/spec/rb_tree_map_spec.rb +122 -0
  41. data/spec/search_spec.rb +27 -0
  42. data/spec/sort_spec.rb +26 -0
  43. data/spec/splay_tree_map_spec.rb +105 -0
  44. data/spec/stack_spec.rb +59 -0
  45. data/spec/string_spec.rb +12 -0
  46. data/spec/suffix_array_spec.rb +39 -0
  47. data/spec/trie_spec.rb +58 -0
  48. metadata +60 -4
@@ -1,113 +1,113 @@
1
- =begin rdoc
2
-
3
- A kd-tree is a binary tree that allows one to store points (of any space dimension: 2D, 3D, etc).
4
- The structure of the resulting tree makes it so that large portions of the tree are pruned
5
- during queries.
6
-
7
- One very good use of the tree is to allow nearest neighbor searching. Let's say you have a number
8
- of points in 2D space, and you want to find the nearest 2 points from a specific point:
9
-
10
- First, put the points into the tree:
11
-
12
- kdtree = Algorithms::Containers::KDTree.new( {0 => [4, 3], 1 => [3, 4], 2 => [-1, 2], 3 => [6, 4],
13
- 4 => [3, -5], 5 => [-2, -5] })
14
-
15
- Then, query on the tree:
16
-
17
- puts kd.find_nearest([0, 0], 2) => [[5, 2], [9, 1]]
18
-
19
- The result is an array of [distance, id] pairs. There seems to be a bug in this version.
20
-
21
- Note that the point queried on does not have to exist in the tree. However, if it does exist,
22
- it will be returned.
23
-
24
- =end
25
- module Algorithms
26
- module Containers
27
- class KDTree
28
- Node = Struct.new(:id, :coords, :left, :right)
29
-
30
- # Points is a hash of id => [coord, coord] pairs.
31
- def initialize(points)
32
- raise "must pass in a hash" unless points.kind_of?(Hash)
33
- @dimensions = points[ points.keys.first ].size
34
- @root = build_tree(points.to_a)
35
- @nearest = []
36
- end
37
-
38
- # Find k closest points to given coordinates
39
- def find_nearest(target, k_nearest)
40
- @nearest = []
41
- nearest(@root, target, k_nearest, 0)
42
- end
43
-
44
- # points is an array
45
- def build_tree(points, depth=0)
46
- return if points.empty?
47
-
48
- axis = depth % @dimensions
49
-
50
- points.sort! { |a, b| a.last[axis] <=> b.last[axis] }
51
- median = points.size / 2
52
-
53
- node = Node.new(points[median].first, points[median].last, nil, nil)
54
- node.left = build_tree(points[0...median], depth+1)
55
- node.right = build_tree(points[median+1..-1], depth+1)
56
- node
57
- end
58
- private :build_tree
59
-
60
- # Euclidian distanced, squared, between a node and target coords
61
- def distance2(node, target)
62
- return nil if node.nil? or target.nil?
63
- c = (node.coords[0] - target[0])
64
- d = (node.coords[1] - target[1])
65
- c * c + d * d
66
- end
67
- private :distance2
68
-
69
- # Update array of nearest elements if necessary
70
- def check_nearest(nearest, node, target, k_nearest)
71
- d = distance2(node, target)
72
- if nearest.size < k_nearest || d < nearest.last[0]
73
- nearest.pop if nearest.size >= k_nearest
74
- nearest << [d, node.id]
75
- nearest.sort! { |a, b| a[0] <=> b[0] }
76
- end
77
- nearest
78
- end
79
- private :check_nearest
80
-
81
- # Recursively find nearest coordinates, going down the appropriate branch as needed
82
- def nearest(node, target, k_nearest, depth)
83
- axis = depth % @dimensions
84
-
85
- if node.left.nil? && node.right.nil? # Leaf node
86
- @nearest = check_nearest(@nearest, node, target, k_nearest)
87
- return
88
- end
89
-
90
- # Go down the nearest split
91
- if node.right.nil? || (node.left && target[axis] <= node.coords[axis])
92
- nearer = node.left
93
- further = node.right
94
- else
95
- nearer = node.right
96
- further = node.left
97
- end
98
- nearest(nearer, target, k_nearest, depth+1)
99
-
100
- # See if we have to check other side
101
- if further
102
- if @nearest.size < k_nearest || (target[axis] - node.coords[axis])**2 < @nearest.last[0]
103
- nearest(further, target, k_nearest, depth+1)
104
- end
105
- end
106
-
107
- @nearest = check_nearest(@nearest, node, target, k_nearest)
108
- end
109
- private :nearest
110
-
111
- end
112
- end
1
+ =begin rdoc
2
+
3
+ A kd-tree is a binary tree that allows one to store points (of any space dimension: 2D, 3D, etc).
4
+ The structure of the resulting tree makes it so that large portions of the tree are pruned
5
+ during queries.
6
+
7
+ One very good use of the tree is to allow nearest neighbor searching. Let's say you have a number
8
+ of points in 2D space, and you want to find the nearest 2 points from a specific point:
9
+
10
+ First, put the points into the tree:
11
+
12
+ kdtree = Algorithms::Containers::KDTree.new( {0 => [4, 3], 1 => [3, 4], 2 => [-1, 2], 3 => [6, 4],
13
+ 4 => [3, -5], 5 => [-2, -5] })
14
+
15
+ Then, query on the tree:
16
+
17
+ puts kd.find_nearest([0, 0], 2) => [[5, 2], [9, 1]]
18
+
19
+ The result is an array of [distance, id] pairs. There seems to be a bug in this version.
20
+
21
+ Note that the point queried on does not have to exist in the tree. However, if it does exist,
22
+ it will be returned.
23
+
24
+ =end
25
+ module Algorithms
26
+ module Containers
27
+ class KDTree
28
+ Node = Struct.new(:id, :coords, :left, :right)
29
+
30
+ # Points is a hash of id => [coord, coord] pairs.
31
+ def initialize(points)
32
+ raise "must pass in a hash" unless points.kind_of?(Hash)
33
+ @dimensions = points[ points.keys.first ].size
34
+ @root = build_tree(points.to_a)
35
+ @nearest = []
36
+ end
37
+
38
+ # Find k closest points to given coordinates
39
+ def find_nearest(target, k_nearest)
40
+ @nearest = []
41
+ nearest(@root, target, k_nearest, 0)
42
+ end
43
+
44
+ # points is an array
45
+ def build_tree(points, depth=0)
46
+ return if points.empty?
47
+
48
+ axis = depth % @dimensions
49
+
50
+ points.sort! { |a, b| a.last[axis] <=> b.last[axis] }
51
+ median = points.size / 2
52
+
53
+ node = Node.new(points[median].first, points[median].last, nil, nil)
54
+ node.left = build_tree(points[0...median], depth+1)
55
+ node.right = build_tree(points[median+1..-1], depth+1)
56
+ node
57
+ end
58
+ private :build_tree
59
+
60
+ # Euclidian distanced, squared, between a node and target coords
61
+ def distance2(node, target)
62
+ return nil if node.nil? or target.nil?
63
+ c = (node.coords[0] - target[0])
64
+ d = (node.coords[1] - target[1])
65
+ c * c + d * d
66
+ end
67
+ private :distance2
68
+
69
+ # Update array of nearest elements if necessary
70
+ def check_nearest(nearest, node, target, k_nearest)
71
+ d = distance2(node, target)
72
+ if nearest.size < k_nearest || d < nearest.last[0]
73
+ nearest.pop if nearest.size >= k_nearest
74
+ nearest << [d, node.id]
75
+ nearest.sort! { |a, b| a[0] <=> b[0] }
76
+ end
77
+ nearest
78
+ end
79
+ private :check_nearest
80
+
81
+ # Recursively find nearest coordinates, going down the appropriate branch as needed
82
+ def nearest(node, target, k_nearest, depth)
83
+ axis = depth % @dimensions
84
+
85
+ if node.left.nil? && node.right.nil? # Leaf node
86
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
87
+ return
88
+ end
89
+
90
+ # Go down the nearest split
91
+ if node.right.nil? || (node.left && target[axis] <= node.coords[axis])
92
+ nearer = node.left
93
+ further = node.right
94
+ else
95
+ nearer = node.right
96
+ further = node.left
97
+ end
98
+ nearest(nearer, target, k_nearest, depth+1)
99
+
100
+ # See if we have to check other side
101
+ if further
102
+ if @nearest.size < k_nearest || (target[axis] - node.coords[axis])**2 < @nearest.last[0]
103
+ nearest(further, target, k_nearest, depth+1)
104
+ end
105
+ end
106
+
107
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
108
+ end
109
+ private :nearest
110
+
111
+ end
112
+ end
113
113
  end
@@ -1,117 +1,117 @@
1
- require 'containers/heap'
2
-
3
- =begin rdoc
4
- A Priority Queue is a data structure that behaves like a queue except that elements have an
5
- associated priority. The #next and #pop methods return the item with the next highest priority.
6
-
7
- Priority Queues are often used in graph problems, such as Dijkstra's Algorithm for shortest
8
- path, and the A* search algorithm for shortest path.
9
-
10
- This container is implemented using the Fibonacci heap included in the Collections library.
11
- =end
12
- module Algorithms
13
- module Containers
14
- class PriorityQueue
15
- include Enumerable
16
-
17
- # Create a new, empty PriorityQueue
18
- def initialize(&block)
19
- # We default to a priority queue that returns the largest value
20
- block ||= lambda { |x, y| (x <=> y) == 1 }
21
- @heap = Heap.new(&block)
22
- end
23
-
24
- # Returns the number of elements in the queue.
25
- #
26
- # q = Algorithms::Containers::PriorityQueue.new
27
- # q.size #=> 0
28
- # q.push("Alaska", 1)
29
- # q.size #=> 1
30
- def size
31
- @heap.size
32
- end
33
- alias_method :length, :size
34
-
35
- # Add an object to the queue with associated priority.
36
- #
37
- # q = Algorithms::Containers::PriorityQueue.new
38
- # q.push("Alaska", 1)
39
- # q.pop #=> "Alaska"
40
- def push(object, priority)
41
- @heap.push(priority, object)
42
- end
43
-
44
- # Clears all the items in the queue.
45
- def clear
46
- @heap.clear
47
- end
48
-
49
- # Returns true if the queue is empty, false otherwise.
50
- def empty?
51
- @heap.empty?
52
- end
53
-
54
- # call-seq:
55
- # has_priority? priority -> boolean
56
- #
57
- # Return true if the priority is in the queue, false otherwise.
58
- #
59
- # q = PriorityQueue.new
60
- # q.push("Alaska", 1)
61
- #
62
- # q.has_priority?(1) #=> true
63
- # q.has_priority?(2) #=> false
64
- def has_priority?(priority)
65
- @heap.has_key?(priority)
66
- end
67
-
68
- # call-seq:
69
- # next -> object
70
- #
71
- # Return the object with the next highest priority, but does not remove it
72
- #
73
- # q = Algorithms::Containers::PriorityQueue.new
74
- # q.push("Alaska", 50)
75
- # q.push("Delaware", 30)
76
- # q.push("Georgia", 35)
77
- # q.next #=> "Alaska"
78
- def next
79
- @heap.next
80
- end
81
-
82
- # call-seq:
83
- # pop -> object
84
- #
85
- # Return the object with the next highest priority and removes it from the queue
86
- #
87
- # q = Algorithms::Containers::PriorityQueue.new
88
- # q.push("Alaska", 50)
89
- # q.push("Delaware", 30)
90
- # q.push("Georgia", 35)
91
- # q.pop #=> "Alaska"
92
- # q.size #=> 2
93
- def pop
94
- @heap.pop
95
- end
96
- alias_method :next!, :pop
97
-
98
- # call-seq:
99
- # delete(priority) -> object
100
- # delete(priority) -> nil
101
- #
102
- # Delete an object with specified priority from the queue. If there are duplicates, an
103
- # arbitrary object with that priority is deleted and returned. Returns nil if there are
104
- # no objects with the priority.
105
- #
106
- # q = PriorityQueue.new
107
- # q.push("Alaska", 50)
108
- # q.push("Delaware", 30)
109
- # q.delete(50) #=> "Alaska"
110
- # q.delete(10) #=> nil
111
- def delete(priority)
112
- @heap.delete(priority)
113
- end
114
-
115
- end
116
- end
1
+ require 'containers/heap'
2
+
3
+ =begin rdoc
4
+ A Priority Queue is a data structure that behaves like a queue except that elements have an
5
+ associated priority. The #next and #pop methods return the item with the next highest priority.
6
+
7
+ Priority Queues are often used in graph problems, such as Dijkstra's Algorithm for shortest
8
+ path, and the A* search algorithm for shortest path.
9
+
10
+ This container is implemented using the Fibonacci heap included in the Collections library.
11
+ =end
12
+ module Algorithms
13
+ module Containers
14
+ class PriorityQueue
15
+ include Enumerable
16
+
17
+ # Create a new, empty PriorityQueue
18
+ def initialize(&block)
19
+ # We default to a priority queue that returns the largest value
20
+ block ||= lambda { |x, y| (x <=> y) == 1 }
21
+ @heap = Heap.new(&block)
22
+ end
23
+
24
+ # Returns the number of elements in the queue.
25
+ #
26
+ # q = Algorithms::Containers::PriorityQueue.new
27
+ # q.size #=> 0
28
+ # q.push("Alaska", 1)
29
+ # q.size #=> 1
30
+ def size
31
+ @heap.size
32
+ end
33
+ alias_method :length, :size
34
+
35
+ # Add an object to the queue with associated priority.
36
+ #
37
+ # q = Algorithms::Containers::PriorityQueue.new
38
+ # q.push("Alaska", 1)
39
+ # q.pop #=> "Alaska"
40
+ def push(object, priority)
41
+ @heap.push(priority, object)
42
+ end
43
+
44
+ # Clears all the items in the queue.
45
+ def clear
46
+ @heap.clear
47
+ end
48
+
49
+ # Returns true if the queue is empty, false otherwise.
50
+ def empty?
51
+ @heap.empty?
52
+ end
53
+
54
+ # call-seq:
55
+ # has_priority? priority -> boolean
56
+ #
57
+ # Return true if the priority is in the queue, false otherwise.
58
+ #
59
+ # q = PriorityQueue.new
60
+ # q.push("Alaska", 1)
61
+ #
62
+ # q.has_priority?(1) #=> true
63
+ # q.has_priority?(2) #=> false
64
+ def has_priority?(priority)
65
+ @heap.has_key?(priority)
66
+ end
67
+
68
+ # call-seq:
69
+ # next -> object
70
+ #
71
+ # Return the object with the next highest priority, but does not remove it
72
+ #
73
+ # q = Algorithms::Containers::PriorityQueue.new
74
+ # q.push("Alaska", 50)
75
+ # q.push("Delaware", 30)
76
+ # q.push("Georgia", 35)
77
+ # q.next #=> "Alaska"
78
+ def next
79
+ @heap.next
80
+ end
81
+
82
+ # call-seq:
83
+ # pop -> object
84
+ #
85
+ # Return the object with the next highest priority and removes it from the queue
86
+ #
87
+ # q = Algorithms::Containers::PriorityQueue.new
88
+ # q.push("Alaska", 50)
89
+ # q.push("Delaware", 30)
90
+ # q.push("Georgia", 35)
91
+ # q.pop #=> "Alaska"
92
+ # q.size #=> 2
93
+ def pop
94
+ @heap.pop
95
+ end
96
+ alias_method :next!, :pop
97
+
98
+ # call-seq:
99
+ # delete(priority) -> object
100
+ # delete(priority) -> nil
101
+ #
102
+ # Delete an object with specified priority from the queue. If there are duplicates, an
103
+ # arbitrary object with that priority is deleted and returned. Returns nil if there are
104
+ # no objects with the priority.
105
+ #
106
+ # q = PriorityQueue.new
107
+ # q.push("Alaska", 50)
108
+ # q.push("Delaware", 30)
109
+ # q.delete(50) #=> "Alaska"
110
+ # q.delete(10) #=> nil
111
+ def delete(priority)
112
+ @heap.delete(priority)
113
+ end
114
+
115
+ end
116
+ end
117
117
  end