depq 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -21,7 +21,7 @@ depq is double-ended stable priority queue with priority update operation implem
21
21
  * ((<reference manual|URL:http://depq.rubyforge.org/rdoc/classes/Depq.html>))
22
22
  * ((<home page on rubyforge|URL:http://depq.rubyforge.org/>))
23
23
  * ((<project info on rubyforge|URL:http://rubyforge.org/projects/depq/>))
24
- * ((<depq on gemcutter|URL:http://gemcutter.org/gems/depq>))
24
+ * ((<depq on rubygems.org|URL:http://rubygems.org/gems/depq>))
25
25
  * ((<source repository on github|URL:http://github.com/akr/depq>))
26
26
  * ((<raa entry|URL:http://raa.ruby-lang.org/project/depq/>))
27
27
 
@@ -241,6 +241,11 @@ class Depq
241
241
  super value, subpriority, priority
242
242
  end
243
243
 
244
+ def initialize_in_queue(value, depq, index)
245
+ initialize(value, index, depq)
246
+ end
247
+ private :initialize_in_queue
248
+
244
249
  def inspect
245
250
  prio = self.priority
246
251
  if self.value == prio
@@ -377,10 +382,8 @@ class Depq
377
382
 
378
383
  def internal_inserted(depq, index)
379
384
  raise ArgumentError, "already inserted" if in_queue?
380
- priority = index_or_priority()
381
385
  self.depq_or_subpriority = depq
382
386
  self.index_or_priority = index
383
- priority
384
387
  end
385
388
  private :internal_inserted
386
389
 
@@ -432,7 +435,6 @@ class Depq
432
435
  @heapsize = 0
433
436
  @mode = nil
434
437
  @totalcount = 0
435
- #@subpriority_generator = nil
436
438
  end
437
439
 
438
440
  # :stopdoc:
@@ -456,12 +458,10 @@ class Depq
456
458
  end
457
459
  private :set_entry
458
460
 
459
- def delete_entry(i)
460
- locator, priority, subpriority = @ary[i*ARY_SLICE_SIZE, ARY_SLICE_SIZE]
461
- @ary[i*ARY_SLICE_SIZE, ARY_SLICE_SIZE] = []
462
- [locator, priority, subpriority]
461
+ def delete_last_entry
462
+ @ary.slice!(@ary.size-ARY_SLICE_SIZE, ARY_SLICE_SIZE)
463
463
  end
464
- private :delete_entry
464
+ private :delete_last_entry
465
465
 
466
466
  def each_entry
467
467
  0.upto(self.size-1) {|i|
@@ -479,25 +479,37 @@ class Depq
479
479
  private :mode_call
480
480
 
481
481
  def use_min
482
- if @mode == :min || @mode == :interval
482
+ case @mode
483
+ when :min, :interval
483
484
  if @heapsize < self.size
484
485
  @heapsize = mode_call(:heapify, @heapsize)
485
486
  end
486
- else
487
+ when :max
488
+ @mode = :interval
489
+ @heapsize = mode_call(:heapify)
490
+ when nil
487
491
  @mode = :min
488
492
  @heapsize = mode_call(:heapify)
493
+ else
494
+ raise "[bug] unexpected mode: #{@mode.inspect}"
489
495
  end
490
496
  end
491
497
  private :use_min
492
498
 
493
499
  def use_max
494
- if @mode == :max || @mode == :interval
500
+ case @mode
501
+ when :max, :interval
495
502
  if @heapsize < self.size
496
503
  @heapsize = mode_call(:heapify, @heapsize)
497
504
  end
498
- else
505
+ when :min
506
+ @mode = :interval
507
+ @heapsize = mode_call(:heapify)
508
+ when nil
499
509
  @mode = :max
500
510
  @heapsize = mode_call(:heapify)
511
+ else
512
+ raise "[bug] unexpected mode: #{@mode.inspect}"
501
513
  end
502
514
  end
503
515
  private :use_max
@@ -530,7 +542,6 @@ class Depq
530
542
  private :check_locator
531
543
 
532
544
  def default_subpriority
533
- #return @subpriority_generator.call if @subpriority_generator
534
545
  self.totalcount
535
546
  end
536
547
  private :default_subpriority
@@ -538,13 +549,14 @@ class Depq
538
549
  def initialize_copy(obj) # :nodoc:
539
550
  if defined? @ary
540
551
  @ary = @ary.dup
541
- 0.step(@ary.length-1, ARY_SLICE_SIZE) {|k|
542
- i = k / ARY_SLICE_SIZE
552
+ n = @ary.length / ARY_SLICE_SIZE
553
+ k = 0
554
+ n.times {|i|
543
555
  loc1 = @ary[k]
544
- priority = @ary[k+1]
545
- loc2 = Depq::Locator.new(loc1.value, priority)
546
- loc2.send(:internal_inserted, self, i)
556
+ loc2 = Depq::Locator.allocate
557
+ loc2.send(:initialize_in_queue, loc1.value, self, i)
547
558
  @ary[k] = loc2
559
+ k += ARY_SLICE_SIZE
548
560
  }
549
561
  end
550
562
  end
@@ -684,8 +696,9 @@ class Depq
684
696
 
685
697
  def internal_set_priority(loc, priority, subpriority)
686
698
  check_locator(loc)
687
- if @heapsize <= loc.send(:index)
688
- set_entry(loc.send(:index), loc, priority, subpriority)
699
+ index = loc.send(:index)
700
+ if @heapsize <= index
701
+ set_entry(index, loc, priority, subpriority)
689
702
  else
690
703
  mode_heapify
691
704
  mode_call(:update_prio, loc, priority, subpriority)
@@ -705,9 +718,10 @@ class Depq
705
718
  # p q.delete_min #=> 1
706
719
  #
707
720
  def insert_locator(loc)
721
+ priority = loc.priority
708
722
  subpriority = loc.subpriority || default_subpriority
709
723
  i = self.size
710
- priority = loc.send(:internal_inserted, self, i)
724
+ loc.send(:internal_inserted, self, i)
711
725
  set_entry(i, loc, priority, subpriority)
712
726
  @totalcount += 1
713
727
  loc
@@ -961,7 +975,7 @@ class Depq
961
975
  set_entry(index, loc2, priority2, subpriority2)
962
976
  loc2.send(:index=, index)
963
977
  end
964
- delete_entry(last)
978
+ delete_last_entry
965
979
  loc.send(:internal_deleted, priority, subpriority)
966
980
  loc
967
981
  else
@@ -1010,8 +1024,7 @@ class Depq
1010
1024
  #
1011
1025
  def delete_min_priority
1012
1026
  loc = delete_min_locator
1013
- return nil unless loc
1014
- [loc.value, loc.priority]
1027
+ loc and [loc.value, loc.priority]
1015
1028
  end
1016
1029
 
1017
1030
  # delete the minimum element in the queue and returns the value.
@@ -1075,8 +1088,7 @@ class Depq
1075
1088
  #
1076
1089
  def delete_max_priority
1077
1090
  loc = delete_max_locator
1078
- return nil unless loc
1079
- [loc.value, loc.priority]
1091
+ loc and [loc.value, loc.priority]
1080
1092
  end
1081
1093
 
1082
1094
  # delete the maximum element in the queue and returns the value.
@@ -1138,8 +1150,7 @@ class Depq
1138
1150
  #
1139
1151
  def delete_unspecified_priority
1140
1152
  loc = delete_unspecified_locator
1141
- return nil unless loc
1142
- [loc.value, loc.priority]
1153
+ loc and [loc.value, loc.priority]
1143
1154
  end
1144
1155
 
1145
1156
  # delete an element in the queue and returns the value.
@@ -1159,8 +1170,7 @@ class Depq
1159
1170
  #
1160
1171
  def delete_unspecified
1161
1172
  loc = delete_unspecified_locator
1162
- return nil unless loc
1163
- loc.value
1173
+ loc and loc.value
1164
1174
  end
1165
1175
 
1166
1176
  # replaces the minimum element.
@@ -1233,7 +1243,7 @@ class Depq
1233
1243
  # }
1234
1244
  #
1235
1245
  def each_locator # :yield: locator
1236
- each_entry {|locator, priority|
1246
+ each_entry {|locator,|
1237
1247
  yield locator
1238
1248
  }
1239
1249
  nil
@@ -1241,6 +1251,8 @@ class Depq
1241
1251
 
1242
1252
  # iterate over the values and priorities in the queue.
1243
1253
  #
1254
+ # The iteration order is unspecified.
1255
+ #
1244
1256
  # q = Depq.new
1245
1257
  # q.insert "durian", 1
1246
1258
  # q.insert "banana", 3
@@ -1295,6 +1307,8 @@ class Depq
1295
1307
  # p Depq.nlargest(3, [5, 2, 3, 1, 4, 6, 7]) {|e| -e } #=> [3, 2, 1]
1296
1308
  #
1297
1309
  def Depq.nlargest(n, iter)
1310
+ raise ArgumentError, "n is negative" if n < 0
1311
+ return [] if n == 0
1298
1312
  limit = (n * Math.log(1+n)).ceil
1299
1313
  limit = 1024 if limit < 1024
1300
1314
  q = Depq.new
@@ -1348,6 +1362,8 @@ class Depq
1348
1362
  # p Depq.nsmallest(5, [5, 2, 3, 1, 4, 6, 7]) {|e| -e } #=> [7, 6, 5, 4, 3]
1349
1363
  #
1350
1364
  def Depq.nsmallest(n, iter)
1365
+ raise ArgumentError, "n is negative" if n < 0
1366
+ return [] if n == 0
1351
1367
  limit = (n * Math.log(1+n)).ceil
1352
1368
  limit = 1024 if limit < 1024
1353
1369
  q = Depq.new
@@ -1436,6 +1452,102 @@ class Depq
1436
1452
  end
1437
1453
  end
1438
1454
 
1455
+ # search a graph using A* search algorithm.
1456
+ #
1457
+ # The graph is defined by _start_ argument and the given block.
1458
+ # _start_ specifies the start node for searching.
1459
+ # The block should takes a node and return an array of pairs.
1460
+ # The pair is an 2-element array which contains the next node and cost of the given node to the next node.
1461
+ #
1462
+ # The optional argument, _heuristics_ specifies
1463
+ # conservative estimation to goal.
1464
+ # It should be a Hash or a Proc that _heuristics_+[node]+ returns an estimated cost to goal.
1465
+ # The estimated cost must be smaller or equal to the true cost.
1466
+ # If _heuristics_ is not given, Hash.new(0) is used.
1467
+ # This means +Depq.astar_search+ behaves as Dijkstra's algorithm in that case.
1468
+ #
1469
+ # +Depq.astar_search+ returns an enumerator.
1470
+ # It yields 3 values: previous node, current node and total cost between start node to current node.
1471
+ # When current node is start node, nil is given for previous node.
1472
+ #
1473
+ # # 7 5 1
1474
+ # # A--->B--->C--->D
1475
+ # # | | | |
1476
+ # # 2| 4| 1| 3|
1477
+ # # | | | |
1478
+ # # V V V V
1479
+ # # E--->F--->G--->H
1480
+ # # 3 3 5
1481
+ # #
1482
+ # g = {
1483
+ # :A => [[:B, 7], [:E, 2]],
1484
+ # :B => [[:C, 5], [:F, 4]],
1485
+ # :C => [[:D, 1], [:G, 1]],
1486
+ # :D => [[:H, 3]],
1487
+ # :E => [[:F, 3]],
1488
+ # :F => [[:G, 3]],
1489
+ # :G => [[:H, 5]],
1490
+ # :H => []
1491
+ # }
1492
+ # # This doesn't specify _heuristics_. So This is Dijkstra's algorithm.
1493
+ # Depq.astar_search(:A) {|n| g[n] }.each {|prev, curr, cost| p [prev, curr, cost] }
1494
+ # #=> [nil, :A, 0]
1495
+ # # [:A, :E, 2]
1496
+ # # [:E, :F, 5]
1497
+ # # [:A, :B, 7]
1498
+ # # [:F, :G, 8]
1499
+ # # [:B, :C, 12]
1500
+ # # [:G, :H, 13] # H found.
1501
+ # # [:C, :D, 13]
1502
+ #
1503
+ # # heuristics using Manhattan distance assuming the goal is H.
1504
+ # h = {
1505
+ # :A => 4,
1506
+ # :B => 3,
1507
+ # :C => 2,
1508
+ # :D => 1,
1509
+ # :E => 3,
1510
+ # :F => 2,
1511
+ # :G => 1,
1512
+ # :H => 0
1513
+ # }
1514
+ # # This specify _heuristics_. So This is A* search algorithm.
1515
+ # Depq.astar_search(:A, h) {|n| g[n] }.each {|prev, curr, cost| p [prev, curr, cost] }
1516
+ # #=> [nil, :A, 0]
1517
+ # # [:A, :E, 2]
1518
+ # # [:E, :F, 5]
1519
+ # # [:F, :G, 8]
1520
+ # # [:A, :B, 7]
1521
+ # # [:G, :H, 13] # H found. Bit better than Dijkstra's algorithm.
1522
+ # # [:B, :C, 12]
1523
+ # # [:C, :D, 13]
1524
+ #
1525
+ # cf. http://en.wikipedia.org/wiki/A*_search_algorithm
1526
+ #
1527
+ def Depq.astar_search(start, heuristics=nil, &find_nexts)
1528
+ Enumerator.new {|y|
1529
+ heuristics ||= Hash.new(0)
1530
+ h = Hash.new {|_, k| h[k] = heuristics[k] }
1531
+ q = Depq.new
1532
+ visited = {start => q.insert([nil, start], h[start])}
1533
+ until q.empty?
1534
+ path, w1 = q.delete_min_priority
1535
+ v1 = path.last
1536
+ w1 -= h[v1]
1537
+ y.yield [path.first, path.last, w1]
1538
+ find_nexts.call(v1).each {|v2, w2|
1539
+ w3 = w1 + w2 + h[v2]
1540
+ if !visited[v2]
1541
+ visited[v2] = q.insert([path.last,v2], w3)
1542
+ elsif w3 < visited[v2].priority
1543
+ visited[v2].update([path.last,v2], w3)
1544
+ end
1545
+ }
1546
+ end
1547
+ nil
1548
+ }
1549
+ end
1550
+
1439
1551
  private
1440
1552
  # :stopdoc:
1441
1553
 
@@ -1465,17 +1577,18 @@ class Depq
1465
1577
  def mm_downheap(i, upper)
1466
1578
  while true
1467
1579
  j = i*2+1
1468
- k = i*2+2
1580
+ k = j+1
1469
1581
  return if self.size <= j
1470
1582
  if self.size == k
1471
1583
  return if upper.call(i, j)
1472
1584
  swap(i, j)
1473
1585
  i = j
1586
+ return
1474
1587
  else
1475
1588
  return if upper.call(i, j) && upper.call(i, k)
1476
- loc = upper.call(j, k) ? j : k
1477
- swap(i, loc)
1478
- i = loc
1589
+ m = upper.call(j, k) ? j : k
1590
+ swap(i, m)
1591
+ i = m
1479
1592
  end
1480
1593
  end
1481
1594
  end
@@ -1490,7 +1603,7 @@ class Depq
1490
1603
  _, priority, subpriority = get_entry(i)
1491
1604
  last = self.size - 1
1492
1605
  loc.send(:internal_deleted, priority, subpriority)
1493
- el, pl, sl = delete_entry(last)
1606
+ el, pl, sl = delete_last_entry
1494
1607
  if i != last
1495
1608
  set_entry(i, el, pl, sl)
1496
1609
  el.send(:index=, i)
@@ -1642,10 +1755,10 @@ class Depq
1642
1755
  def itv_maxside(i) i | 1 end
1643
1756
  def itv_parent_minside(j) (j-2)/2 & ~1 end
1644
1757
  def itv_parent_maxside(j) (j-2)/2 | 1 end
1645
- def itv_child1_minside(i) i &= ~1; (i*2+2) & ~1 end
1646
- def itv_child1_maxside(i) i &= ~1; (i*2+2) | 1 end
1647
- def itv_child2_minside(i) i &= ~1; (i*2+4) & ~1 end
1648
- def itv_child2_maxside(i) i &= ~1; (i*2+4) | 1 end
1758
+ def itv_child1_minside(i) i &= ~1; i*2+2 end
1759
+ def itv_child1_maxside(i) i &= ~1; i*2+3 end
1760
+ def itv_child2_minside(i) i &= ~1; i*2+4 end
1761
+ def itv_child2_maxside(i) i &= ~1; i*2+5 end
1649
1762
 
1650
1763
  def pcmp(i, j)
1651
1764
  ei, pi, si = get_entry(i)
@@ -1672,7 +1785,7 @@ class Depq
1672
1785
  imin = itv_minside(i)
1673
1786
  imax = itv_maxside(i)
1674
1787
  if range.include?(imin) && range.include?(imax)
1675
- if pcmp(imin, imax) == 0 && scmp(imin, imax) > 0
1788
+ if scmp(imin, imax) > 0 && pcmp(imin, imax) == 0
1676
1789
  swap imin, imax
1677
1790
  end
1678
1791
  end
@@ -1926,7 +2039,7 @@ class Depq
1926
2039
  _, priority, subpriority = get_entry(i)
1927
2040
  last = self.size - 1
1928
2041
  loc.send(:internal_deleted, priority, subpriority)
1929
- el, pl, sl = delete_entry(last)
2042
+ el, pl, sl = delete_last_entry
1930
2043
  if i != last
1931
2044
  set_entry(i, el, pl, sl)
1932
2045
  el.send(:index=, i)
@@ -0,0 +1,43 @@
1
+ # Dijkstra's single source shortest path finding algorithm
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/dijkstra.rb
5
+
6
+ require 'depq'
7
+
8
+ def dijkstra_shortest_path(start, edges)
9
+ h = {}
10
+ edges.each {|v1, v2, w|
11
+ (h[v1] ||= []) << [v2, w]
12
+ }
13
+ h.default = []
14
+ q = Depq.new
15
+ visited = {start => q.insert([start], 0)}
16
+ until q.empty?
17
+ path, w1 = q.delete_min_priority
18
+ v1 = path.last
19
+ h[v1].each {|v2, w2|
20
+ if !visited[v2]
21
+ visited[v2] = q.insert(path+[v2], w1 + w2)
22
+ elsif w1 + w2 < visited[v2].priority
23
+ visited[v2].update(path+[v2], w1 + w2) # update val/prio
24
+ end
25
+ }
26
+ end
27
+ result = []
28
+ visited.each_value {|loc|
29
+ result << [loc.value, loc.priority]
30
+ }
31
+ result
32
+ end
33
+
34
+ E = [
35
+ ['A', 'B', 2],
36
+ ['A', 'C', 4],
37
+ ['B', 'C', 1],
38
+ ['C', 'B', 2],
39
+ ['B', 'D', 3],
40
+ ['C', 'D', 1],
41
+ ]
42
+ p dijkstra_shortest_path('A', E)
43
+
@@ -0,0 +1,90 @@
1
+ # external quick sort
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/exqsort.rb input-file
5
+
6
+ require 'tmpdir'
7
+ require 'depq'
8
+
9
+ NUM_PIVOTS = 1024
10
+ $tmpdir = nil
11
+ $filecount = 0
12
+
13
+ def partition(input)
14
+ q = Depq.new
15
+ fn1 = "#{$tmpdir}/#{$filecount += 1}"
16
+ fn2 = "#{$tmpdir}/#{$filecount += 1}"
17
+ fn3 = "#{$tmpdir}/#{$filecount += 1}"
18
+ open(fn1, "w") {|f1|
19
+ open(fn3, "w") {|f3|
20
+ n1 = n2 = n3 = 0
21
+ input.each_line {|line|
22
+ line = line.chomp
23
+ if q.size < NUM_PIVOTS
24
+ q.insert line
25
+ else
26
+ min, max = q.minmax
27
+ if line <= min
28
+ f1.puts line
29
+ n1 += 1
30
+ elsif line < max
31
+ q.insert line
32
+ if n1 < n2
33
+ f1.puts q.delete_min
34
+ n1 += 1
35
+ else
36
+ f3.puts q.delete_max
37
+ n3 += 1
38
+ end
39
+ else
40
+ f3.puts line
41
+ n3 += 1
42
+ end
43
+ end
44
+ }
45
+ }
46
+ }
47
+ open(fn2, "w") {|f2|
48
+ while !q.empty?
49
+ f2.puts q.delete_min
50
+ end
51
+ }
52
+ if File.size(fn1) == 0
53
+ File.delete fn1
54
+ fn1 = nil
55
+ end
56
+ if File.size(fn2) == 0
57
+ File.delete fn2
58
+ fn2 = nil
59
+ end
60
+ if File.size(fn3) == 0
61
+ File.delete fn3
62
+ fn3 = nil
63
+ end
64
+ [fn1, fn2, fn3]
65
+ end
66
+
67
+ def eqs(input)
68
+ fn1, fn2, fn3 = partition(input)
69
+ r = []
70
+ if fn1
71
+ r.concat(open(fn1) {|f| eqs(f) })
72
+ end
73
+ if fn2
74
+ r << fn2
75
+ end
76
+ if fn3
77
+ r.concat(open(fn3) {|f| eqs(f) })
78
+ end
79
+ r
80
+ end
81
+
82
+ Dir.mktmpdir {|d|
83
+ $tmpdir = d
84
+ fns = eqs(ARGF)
85
+ fns.each {|fn|
86
+ File.foreach(fn) {|line|
87
+ puts line
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,37 @@
1
+ # Huffman coding
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/huffman.rb input-file
5
+
6
+ require 'depq'
7
+
8
+ h = Hash.new(0)
9
+ ARGF.each {|line|
10
+ line.scan(/\S+/).each {|word|
11
+ h[word] += 1
12
+ }
13
+ }
14
+
15
+ if h.empty?
16
+ exit
17
+ end
18
+
19
+ q = Depq.new
20
+
21
+ h.each {|word, count|
22
+ q.insert({word => ""}, count)
23
+ }
24
+
25
+ while 1 < q.size
26
+ h0, count0 = q.delete_min_priority
27
+ h1, count1 = q.delete_min_priority
28
+ hh = {}
29
+ h0.each {|w, c| hh[w] = "0" + c }
30
+ h1.each {|w, c| hh[w] = "1" + c }
31
+ q.insert hh, count0+count1
32
+ end
33
+
34
+ hh = q.delete_min
35
+ hh.keys.sort_by {|w| h[w] }.each {|w| puts "#{hh[w]} #{h[w]} #{w.inspect}" }
36
+
37
+
@@ -0,0 +1,48 @@
1
+ # search integers x, y, z from smaller x*y*z where x >= y >= z >= 1.
2
+ #
3
+ # usage:
4
+ # ruby -Ilib sample/int-3d.rb
5
+
6
+ require 'depq'
7
+
8
+ # naive version
9
+ def gen1
10
+ q = Depq.new
11
+ q.insert [1, 1,1,1]
12
+ loop {
13
+ ary = q.delete_min
14
+ while q.find_min == ary
15
+ q.delete_min
16
+ end
17
+ yield ary
18
+ w, x,y,z = ary
19
+ x1 = x + 1
20
+ y1 = y + 1
21
+ z1 = z + 1
22
+ q.insert [x1*y*z, x1,y,z] if x1 >= y && y >= z
23
+ q.insert [x*y1*z, x,y1,z] if x >= y1 && y1 >= z
24
+ q.insert [x*y*z1, x,y,z1] if x >= y && y >= z1
25
+ }
26
+ end
27
+
28
+ # faster version
29
+ def gen2
30
+ q = Depq.new
31
+ q.insert [1, 1,1,1]
32
+ loop {
33
+ ary = q.delete_min
34
+ yield ary
35
+ w, x,y,z = ary
36
+ x1 = x + 1
37
+ y1 = y + 1
38
+ z1 = z + 1
39
+ q.insert [x1*y*z, x1,y,z]
40
+ q.insert [x*y1*z, x,y1,z] if x == y1
41
+ q.insert [x*y*z1, x,y,z1] if x == y && y == z1
42
+ }
43
+ end
44
+
45
+ gen2 {|w, x,y,z|
46
+ break if 100 <= w
47
+ p [w, x,y,z]
48
+ }
@@ -0,0 +1,55 @@
1
+ # Kruskal's algorithm
2
+ #
3
+ # finds a minimum spanning tree for a connected weighted graph
4
+ #
5
+ # http://en.wikipedia.org/wiki/Kruskal's_algorithm
6
+ #
7
+ # usage:
8
+ # ruby -Ilib sample/kruskal.rb
9
+
10
+ require 'depq'
11
+
12
+ def kruskal(edge_set)
13
+ q = Depq.new
14
+ parent = {}
15
+ edge_set.each {|v1, v2, w|
16
+ parent[v1] = nil
17
+ parent[v2] = nil
18
+ q.insert [v1, v2], w
19
+ }
20
+
21
+ edge_set2 = []
22
+
23
+ until q.empty?
24
+ v1, v2 = q.delete_min
25
+ r1 = v1
26
+ r1 = parent[r1] while parent[r1]
27
+ r2 = v2
28
+ r2 = parent[r2] while parent[r2]
29
+ if r1 != r2
30
+ edge_set2 << [v1, v2]
31
+ parent[r2] = r1
32
+ end
33
+ end
34
+
35
+ edge_set2
36
+ end
37
+
38
+ if $0 == __FILE__
39
+ E = [
40
+ ['A', 'B', 7],
41
+ ['A', 'D', 5],
42
+ ['B', 'C', 8],
43
+ ['B', 'D', 9],
44
+ ['B', 'E', 7],
45
+ ['C', 'E', 5],
46
+ ['D', 'E', 15],
47
+ ['D', 'F', 6],
48
+ ['E', 'F', 8],
49
+ ['E', 'G', 9],
50
+ ['F', 'G', 11],
51
+ ]
52
+
53
+ p kruskal(E)
54
+ #=> [["A", "D"], ["C", "E"], ["D", "F"], ["A", "B"], ["B", "E"], ["E", "G"]]
55
+ end
@@ -0,0 +1,103 @@
1
+ # solve a maze using A* search algorithm
2
+ #
3
+ # usage:
4
+ # ruby -Isample -Ilib sample/maze.rb
5
+
6
+ require 'depq'
7
+
8
+ Pos = Struct.new(:x, :y)
9
+
10
+ MAZE_MAP = <<'End'
11
+ OOOOOOOOOOOOOOOOOOOOOOOOO
12
+ O OSO O O
13
+ O OOOOOOOOO O O OOO OOO O
14
+ O O O O O O
15
+ O OOOOOOO OOOOOOO OOO O O
16
+ O O O O O O
17
+ OOOOO O O OOO OOOOOOOOO O
18
+ OG O O O O O O O
19
+ O O O O OOO OOO O O O OOO
20
+ O O O O O O O O
21
+ O OOO O OOOOOOOOOOOOOOO O
22
+ O O O
23
+ OOOOOOOOOOOOOOOOOOOOOOOOO
24
+ End
25
+
26
+ MAZE = MAZE_MAP.lines.map {|line| line.chomp.split(//) }
27
+
28
+ H = HEIGHT = MAZE.length
29
+ W = WIDTH = MAZE[0].length
30
+
31
+ MAZE.each_with_index {|line,y|
32
+ line.each_with_index {|cell,x|
33
+ if cell == 'S'
34
+ START = Pos[x,y]
35
+ MAZE[y][x] = ' '
36
+ elsif cell == 'G'
37
+ GOAL = Pos[x,y]
38
+ MAZE[y][x] = ' '
39
+ end
40
+ }
41
+ }
42
+
43
+ find_nexts4 = proc {|pos|
44
+ x, y = pos.x, pos.y
45
+ r = []
46
+ r << [Pos[x-1,y],1] if 0 < x && MAZE[y][x-1] == ' '
47
+ r << [Pos[x,y-1],1] if 0 < y && MAZE[y-1][x] == ' '
48
+ r << [Pos[x+1,y],1] if x < W-1 && MAZE[y][x+1] == ' '
49
+ r << [Pos[x,y+1],1] if y < H-1 && MAZE[y+1][x] == ' '
50
+ r
51
+ }
52
+
53
+ heuristics4 = proc {|pos|
54
+ x, y = pos.x, pos.y
55
+ (x-GOAL.x).abs + (y-GOAL.y).abs
56
+ }
57
+
58
+ find_nexts8 = proc {|pos|
59
+ x, y = pos.x, pos.y
60
+ r = []
61
+ r << [[x-1,y],1] if 0 < x && MAZE[y][x-1] == ' '
62
+ r << [[x,y-1],1] if 0 < y && MAZE[y-1][x] == ' '
63
+ r << [[x+1,y],1] if x < W-1 && MAZE[y][x+1] == ' '
64
+ r << [[x,y+1],1] if y < H-1 && MAZE[y+1][x] == ' '
65
+ r << [[x-1,y-1],2] if 0 < x && 0 < y && MAZE[y-1][x-1] == ' '
66
+ r << [[x-1,y+1],2] if 0 < x && y < H-1 && MAZE[y+1][x-1] == ' '
67
+ r << [[x+1,y-1],2] if x < W-1 && 0 < y && MAZE[y-1][x+1] == ' '
68
+ r << [[x+1,y+1],2] if x < W-1 && y < H-1 && MAZE[y+1][x+1] == ' '
69
+ r
70
+ }
71
+
72
+ heuristics8 = proc {|pos|
73
+ x, y = pos.x, pos.y
74
+ (x-GOAL.x).abs + (y-GOAL.y).abs
75
+ }
76
+
77
+ t1 = Time.now
78
+ searched = {}
79
+ path = Depq.astar_search(START, heuristics4, &find_nexts4).each {|prev, cur, w|
80
+ searched[cur] = [searched[prev], cur]
81
+ if cur == GOAL
82
+ break searched[cur].flatten.compact
83
+ end
84
+ }
85
+ t2 = Time.now
86
+ p t2-t1
87
+
88
+ searched.each_key {|pos|
89
+ x, y = pos.x, pos.y
90
+ MAZE[y][x] = '.'
91
+ }
92
+
93
+ path.each {|pos|
94
+ x, y = pos.x, pos.y
95
+ MAZE[y][x] = '*'
96
+ }
97
+
98
+ MAZE[START.y][START.x] = 'S'
99
+ MAZE[GOAL.y][GOAL.x] = 'G'
100
+
101
+ MAZE.each {|line|
102
+ puts line.join('')
103
+ }
@@ -0,0 +1,78 @@
1
+ # Prim's algorithm
2
+ #
3
+ # finds a minimum spanning tree for a connected weighted graph
4
+ #
5
+ # http://en.wikipedia.org/wiki/Prim's_algorithm
6
+ #
7
+ # usage:
8
+ # ruby -Ilib sample/prim.rb
9
+ #
10
+
11
+ require 'depq'
12
+
13
+ def prim(edge_set)
14
+ vertex_set1 = {}
15
+ adj = {}
16
+ weight = {}
17
+ edge_set.each {|v1, v2, w|
18
+ vertex_set1[v1] = true
19
+ vertex_set1[v2] = true
20
+ adj[v1] ||= []
21
+ adj[v1] << v2
22
+ adj[v2] ||= []
23
+ adj[v2] << v1
24
+ weight[[v1, v2]] = weight[[v2, v1]] = w
25
+ }
26
+ adj.default = []
27
+
28
+ start = vertex_set1.first[0]
29
+ q = Depq.new
30
+ vertex_set2 = {start => true}
31
+ edge_set2 = []
32
+ prev_locators = {}
33
+
34
+ adj[start].each {|v2|
35
+ prev_locators[v2] = [start, q.insert(v2, weight[[start, v2]])]
36
+ }
37
+
38
+ while vertex_set2.size < vertex_set1.size
39
+ v2 = q.delete_min
40
+ v1, _ = prev_locators[v2]
41
+ prev_locators.delete v2
42
+ vertex_set2[v2] = true
43
+ edge_set2 << [v1, v2]
44
+ adj[v2].each {|v3|
45
+ next if vertex_set2[v3]
46
+ if prev_loc = prev_locators[v3]
47
+ _, loc = prev_loc
48
+ if weight[[v2, v3]] < loc.priority
49
+ prev_loc[0] = v2
50
+ loc.update v3, weight[[v2, v3]]
51
+ end
52
+ else
53
+ prev_locators[v3] = [v2, q.insert(v3, weight[[v2, v3]])]
54
+ end
55
+ }
56
+ end
57
+ edge_set2
58
+ end
59
+
60
+ if $0 == __FILE__
61
+ E = [
62
+ ['A', 'B', 7],
63
+ ['A', 'D', 5],
64
+ ['B', 'C', 8],
65
+ ['B', 'D', 9],
66
+ ['B', 'E', 7],
67
+ ['C', 'E', 5],
68
+ ['D', 'E', 15],
69
+ ['D', 'F', 6],
70
+ ['E', 'F', 8],
71
+ ['E', 'G', 9],
72
+ ['F', 'G', 11],
73
+ ]
74
+
75
+ p prim(E)
76
+ #=> [["A", "D"], ["D", "F"], ["A", "B"], ["B", "E"], ["E", "C"], ["E", "G"]]
77
+ end
78
+
@@ -0,0 +1,68 @@
1
+ # scheduler
2
+ #
3
+ # needs Ruby 1.9.2 for timeout argument of ConditionVariable#wait.
4
+ #
5
+ # usage:
6
+ # ruby -Ilib sample/sched.rb
7
+
8
+ require 'depq'
9
+ require 'thread'
10
+
11
+ class Sched
12
+ def initialize
13
+ @q = Depq.new
14
+ @m = Mutex.new
15
+ @cv = ConditionVariable.new
16
+ end
17
+
18
+ def sync
19
+ @m.synchronize { yield }
20
+ end
21
+
22
+ def insert(time, &block)
23
+ sync {
24
+ @q.insert block, time
25
+ }
26
+ end
27
+
28
+ def wait_next_event
29
+ sync {
30
+ block, time = @q.find_min_priority
31
+ now = Time.now
32
+ if now < time
33
+ @cv.wait(@m, time - now)
34
+ end
35
+ now
36
+ }
37
+ end
38
+
39
+ def start
40
+ until sync { @q.empty? }
41
+ now = wait_next_event
42
+ loop {
43
+ block = time = nil
44
+ sync {
45
+ raise StopIteration if @q.empty?
46
+ block, time = @q.find_min_priority
47
+ raise StopIteration if now < time
48
+ block, time = @q.delete_min_priority
49
+ }
50
+ block.call
51
+ }
52
+ end
53
+ end
54
+ end
55
+
56
+ if $0 == __FILE__
57
+ now = Time.now
58
+ sc = Sched.new
59
+ Thread.new {
60
+ sleep 1.5
61
+ sc.insert(Time.now+1) { p Time.now-now }
62
+ }
63
+ sc.insert(now+4) { p Time.now-now }
64
+ sc.insert(now+3) { p Time.now-now }
65
+ sc.insert(now+2) { p Time.now-now }
66
+ sc.insert(now+1) { p Time.now-now }
67
+ sc.start
68
+ end
@@ -1097,4 +1097,75 @@ class TestDepq < Test::Unit::TestCase
1097
1097
  assert_raise(StopIteration) { e.next }
1098
1098
  end
1099
1099
 
1100
+ def test_mode_min_first
1101
+ q = Depq.new
1102
+ q.insert 1
1103
+ q.insert 2
1104
+ assert_equal(nil, q.instance_eval { @mode })
1105
+ assert_equal(1, q.delete_min)
1106
+ assert_equal(:min, q.instance_eval { @mode })
1107
+ assert_equal(2, q.delete_max)
1108
+ assert_equal(:interval, q.instance_eval { @mode })
1109
+ end
1110
+
1111
+ def test_mode_max_first
1112
+ q = Depq.new
1113
+ q.insert 1
1114
+ q.insert 2
1115
+ assert_equal(nil, q.instance_eval { @mode })
1116
+ assert_equal(2, q.delete_max)
1117
+ assert_equal(:max, q.instance_eval { @mode })
1118
+ assert_equal(1, q.delete_min)
1119
+ assert_equal(:interval, q.instance_eval { @mode })
1120
+ end
1121
+
1122
+ def test_astar
1123
+ g = {
1124
+ :A => [[:B, 7], [:E, 2]],
1125
+ :B => [[:C, 5], [:F, 4]],
1126
+ :C => [[:D, 1], [:G, 1]],
1127
+ :D => [[:H, 3]],
1128
+ :E => [[:F, 3]],
1129
+ :F => [[:G, 3]],
1130
+ :G => [[:H, 5]],
1131
+ :H => []
1132
+ }
1133
+ res = []
1134
+ Depq.astar_search(:A) {|n| g[n] }.each {|prev, curr, cost| res << [prev, curr, cost] }
1135
+ assert_equal(
1136
+ [[nil, :A, 0],
1137
+ [:A, :E, 2],
1138
+ [:E, :F, 5],
1139
+ [:A, :B, 7],
1140
+ [:F, :G, 8],
1141
+ [:B, :C, 12],
1142
+ [:G, :H, 13],
1143
+ [:C, :D, 13]],
1144
+ res)
1145
+
1146
+ # heuristics using Manhattan distance assuming the goal is H.
1147
+ h = {
1148
+ :A => 4,
1149
+ :B => 3,
1150
+ :C => 2,
1151
+ :D => 1,
1152
+ :E => 3,
1153
+ :F => 2,
1154
+ :G => 1,
1155
+ :H => 0
1156
+ }
1157
+ res = []
1158
+ Depq.astar_search(:A, h) {|n| g[n] }.each {|prev, curr, cost| res << [prev, curr, cost] }
1159
+ assert_equal(
1160
+ [[nil, :A, 0],
1161
+ [:A, :E, 2],
1162
+ [:E, :F, 5],
1163
+ [:F, :G, 8],
1164
+ [:A, :B, 7],
1165
+ [:G, :H, 13],
1166
+ [:B, :C, 12],
1167
+ [:C, :D, 13]],
1168
+ res)
1169
+ end
1170
+
1100
1171
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: depq
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-27 00:00:00.000000000 Z
12
+ date: 2011-11-29 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'depq is a Double-Ended Priority Queue library.
15
15
 
@@ -28,6 +28,14 @@ extra_rdoc_files: []
28
28
  files:
29
29
  - README
30
30
  - lib/depq.rb
31
+ - sample/dijkstra.rb
32
+ - sample/exqsort.rb
33
+ - sample/huffman.rb
34
+ - sample/int-3d.rb
35
+ - sample/kruskal.rb
36
+ - sample/maze.rb
37
+ - sample/prim.rb
38
+ - sample/sched.rb
31
39
  - test/test-depq.rb
32
40
  homepage: http://depq.rubyforge.org/
33
41
  licenses: []