stakach-algorithms 1.0.6 → 1.0.7

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