PriorityQueue 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/Makefile +140 -0
- data/README +1 -1
- data/compare_comments.rb +49 -0
- data/ext/priority_queue/priority_queue.c +94 -20
- data/lib/priority_queue/ruby_priority_queue.rb +155 -24
- data/priority_queue.o +0 -0
- data/priority_queue.so +0 -0
- data/t.rb +18 -0
- data/test/priority_queue_test.rb +19 -6
- metadata +40 -51
- data/benchmark/result-CPriorityQueue.gp +0 -8
- data/benchmark/result-CPriorityQueue.png +0 -0
- data/benchmark/result-PoorPriorityQueue.gp +0 -8
- data/benchmark/result-PoorPriorityQueue.png +0 -0
- data/benchmark/result-PriorityQueue.gp +0 -6
- data/benchmark/result-RubyPriorityQueue.gp +0 -8
- data/benchmark/result-RubyPriorityQueue.png +0 -0
- data/benchmark/results.csv +0 -37
- data/benchmark/results.gp +0 -10
- data/benchmark/results.png +0 -0
- data/doc/result-PoorPriorityQueue.png +0 -0
- data/doc/result-PriorityQueue.png +0 -0
- data/doc/result-RubyPriorityQueue.png +0 -0
- data/doc/results.png +0 -0
- data/test.rb +0 -11
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.1.1
|
2
|
+
* Removed debug cruft
|
3
|
+
* Added more documentation and examples
|
4
|
+
* Readme typo fixed
|
5
|
+
* I had the tests commented out
|
6
|
+
* Removed a bug when pushing twice onto the c priority queue (and added a test)
|
7
|
+
|
1
8
|
0.1.0
|
2
9
|
* API changes
|
3
10
|
* Added lots of unit tests
|
data/Makefile
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /usr/lib/ruby/1.8/i486-linux
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
prefix = $(DESTDIR)/usr
|
11
|
+
exec_prefix = $(prefix)
|
12
|
+
sitedir = $(DESTDIR)/usr/local/lib/site_ruby
|
13
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
14
|
+
archdir = $(rubylibdir)/$(arch)
|
15
|
+
sbindir = $(exec_prefix)/sbin
|
16
|
+
datadir = $(prefix)/share
|
17
|
+
includedir = $(prefix)/include
|
18
|
+
infodir = $(prefix)/info
|
19
|
+
sysconfdir = $(DESTDIR)/etc
|
20
|
+
mandir = $(datadir)/man
|
21
|
+
libdir = $(exec_prefix)/lib
|
22
|
+
sharedstatedir = $(prefix)/com
|
23
|
+
oldincludedir = $(DESTDIR)/usr/include
|
24
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
25
|
+
bindir = $(exec_prefix)/bin
|
26
|
+
localstatedir = $(DESTDIR)/var
|
27
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
28
|
+
libexecdir = $(exec_prefix)/libexec
|
29
|
+
|
30
|
+
CC = gcc
|
31
|
+
LIBRUBY = $(LIBRUBY_SO)
|
32
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
33
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
34
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
35
|
+
|
36
|
+
CFLAGS = -fPIC -Wall -g -O2 -fPIC
|
37
|
+
CPPFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
|
38
|
+
CXXFLAGS = $(CFLAGS)
|
39
|
+
DLDFLAGS =
|
40
|
+
LDSHARED = $(CC) -shared
|
41
|
+
AR = ar
|
42
|
+
EXEEXT =
|
43
|
+
|
44
|
+
RUBY_INSTALL_NAME = ruby1.8
|
45
|
+
RUBY_SO_NAME = ruby1.8
|
46
|
+
arch = i486-linux
|
47
|
+
sitearch = i486-linux
|
48
|
+
ruby_version = 1.8
|
49
|
+
ruby = /usr/bin/ruby1.8
|
50
|
+
RUBY = $(ruby)
|
51
|
+
RM = rm -f
|
52
|
+
MAKEDIRS = mkdir -p
|
53
|
+
INSTALL = /usr/bin/install -c
|
54
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
55
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
56
|
+
COPY = cp
|
57
|
+
|
58
|
+
#### End of system configuration section. ####
|
59
|
+
|
60
|
+
preload =
|
61
|
+
|
62
|
+
libpath = $(libdir)
|
63
|
+
LIBPATH = -L"$(libdir)"
|
64
|
+
DEFFILE =
|
65
|
+
|
66
|
+
CLEANFILES =
|
67
|
+
DISTCLEANFILES =
|
68
|
+
|
69
|
+
extout =
|
70
|
+
extout_prefix =
|
71
|
+
target_prefix =
|
72
|
+
LOCAL_LIBS =
|
73
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lcrypt -lm -lc
|
74
|
+
SRCS = priority_queue.c
|
75
|
+
OBJS = priority_queue.o
|
76
|
+
TARGET = priority_queue
|
77
|
+
DLLIB = $(TARGET).so
|
78
|
+
STATIC_LIB =
|
79
|
+
|
80
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
81
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
82
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
83
|
+
|
84
|
+
TARGET_SO = $(DLLIB)
|
85
|
+
CLEANLIBS = $(TARGET).so $(TARGET).il? $(TARGET).tds $(TARGET).map
|
86
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
87
|
+
|
88
|
+
all: $(DLLIB)
|
89
|
+
static: $(STATIC_LIB)
|
90
|
+
|
91
|
+
clean:
|
92
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
93
|
+
|
94
|
+
distclean: clean
|
95
|
+
@-$(RM) Makefile extconf.h conftest.* mkmf.log
|
96
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
97
|
+
|
98
|
+
realclean: distclean
|
99
|
+
install: install-so install-rb
|
100
|
+
|
101
|
+
install-so: $(RUBYARCHDIR)
|
102
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
103
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
104
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
105
|
+
install-rb: pre-install-rb install-rb-default
|
106
|
+
install-rb-default: pre-install-rb-default
|
107
|
+
pre-install-rb pre-install-rb-default: $(RUBYLIBDIR)
|
108
|
+
$(RUBYARCHDIR):
|
109
|
+
$(MAKEDIRS) $@
|
110
|
+
$(RUBYLIBDIR):
|
111
|
+
$(MAKEDIRS) $@
|
112
|
+
|
113
|
+
site-install: site-install-so site-install-rb
|
114
|
+
site-install-so: install-so
|
115
|
+
site-install-rb: install-rb
|
116
|
+
|
117
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
118
|
+
|
119
|
+
.cc.o:
|
120
|
+
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
|
121
|
+
|
122
|
+
.cxx.o:
|
123
|
+
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
|
124
|
+
|
125
|
+
.cpp.o:
|
126
|
+
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
|
127
|
+
|
128
|
+
.C.o:
|
129
|
+
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
|
130
|
+
|
131
|
+
.c.o:
|
132
|
+
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
|
133
|
+
|
134
|
+
$(DLLIB): $(OBJS)
|
135
|
+
@-$(RM) $@
|
136
|
+
$(LDSHARED) $(DLDFLAGS) $(LIBPATH) -o $@ $(OBJS) $(LOCAL_LIBS) $(LIBS)
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
$(OBJS): ruby.h defines.h
|
data/README
CHANGED
data/compare_comments.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
c_file = File.read("ext/priority_queue/CPriorityQueue/priority_queue.c")
|
2
|
+
rb_file = File.read("lib/priority_queue/ruby_priority_queue.rb")
|
3
|
+
|
4
|
+
c_comments = Hash.new { "" }
|
5
|
+
|
6
|
+
c_file.scan(%r(/\*(.*?)\*/\s*static\s+\w+\s*pq_(\w+)\(.*?\))m).each do | match |
|
7
|
+
c_comments[match[1]] = match[0].gsub(%r(\n\s*\* {0,1})m, "\n").strip
|
8
|
+
end
|
9
|
+
|
10
|
+
rb_comments = Hash.new { "" }
|
11
|
+
|
12
|
+
rb_file.scan(%r(((?:\n\s*#[^\n]*)*)\s*def\s+(\w+))m).each do | match |
|
13
|
+
rb_comments[match[1]] = match[0].gsub(%r(\n\s*# {0,1})m, "\n").strip
|
14
|
+
end
|
15
|
+
|
16
|
+
add_comments = Hash.new
|
17
|
+
|
18
|
+
(rb_comments.keys + c_comments.keys).uniq.each do | key |
|
19
|
+
#next if rb_comments[key].gsub(/\s+/m, " ") == c_comments[key].gsub(/\s+/m, " ")
|
20
|
+
if c_comments[key].empty?
|
21
|
+
add_comments[key] = rb_comments[key]
|
22
|
+
elsif rb_comments[key].empty?
|
23
|
+
add_comments[key] = c_comments[key]
|
24
|
+
elsif rb_comments[key] != c_comments[key]
|
25
|
+
|
26
|
+
puts key
|
27
|
+
puts "Ruby"
|
28
|
+
puts rb_comments[key]
|
29
|
+
puts "C"
|
30
|
+
puts c_comments[key]
|
31
|
+
puts
|
32
|
+
puts "Choose [c,r]"
|
33
|
+
1 until /^([cr])/ =~ gets
|
34
|
+
add_comments[key] = ($1 == "c" ? c_comments : rb_comments)[key]
|
35
|
+
puts "-" * 80
|
36
|
+
puts
|
37
|
+
else
|
38
|
+
add_comments[key] = rb_comments[key]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
File.open("lib/priority_queue/ruby_priority_queue.new.rb", "wb") do | o |
|
44
|
+
o <<
|
45
|
+
rb_file.gsub(%r(((?:\n\s*#[^\n]*)*)(\s*def\s+(\w+)))m) do | match |
|
46
|
+
name, all = $3, $2
|
47
|
+
"\n" + (add_comments[name].gsub(/^/, "#")) + all
|
48
|
+
end
|
49
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Ruby extension implementing a priority queue
|
5
5
|
*
|
6
|
-
* This is a
|
6
|
+
* This is a fibonacci heap priority queue implementation.
|
7
7
|
*
|
8
8
|
* (c) 2005 Brian Schr�der
|
9
9
|
*
|
@@ -514,8 +514,20 @@ VALUE pq_push(VALUE self, VALUE object, VALUE priority) {
|
|
514
514
|
return self;
|
515
515
|
}
|
516
516
|
|
517
|
-
/*
|
518
|
-
*
|
517
|
+
/* call-seq:
|
518
|
+
* min -> [object, priority]
|
519
|
+
*
|
520
|
+
* Return the pair [object, priority] with minimal priority or nil when the
|
521
|
+
* queue is empty.
|
522
|
+
*
|
523
|
+
* q = PriorityQueue.new
|
524
|
+
* q["a"] = 10
|
525
|
+
* q["b"] = 20
|
526
|
+
* q.min #=> ["a", 10]
|
527
|
+
* q.delete_min #=> ["a", 10]
|
528
|
+
* q.min #=> ["b", 20]
|
529
|
+
* q.delete_min #=> ["b", 20]
|
530
|
+
* q.min #=> nil
|
519
531
|
*/
|
520
532
|
static
|
521
533
|
VALUE pq_min(VALUE self) {
|
@@ -528,8 +540,19 @@ VALUE pq_min(VALUE self) {
|
|
528
540
|
return Qnil;
|
529
541
|
}
|
530
542
|
|
531
|
-
/*
|
532
|
-
*
|
543
|
+
/* call-seq:
|
544
|
+
* min_key -> object
|
545
|
+
*
|
546
|
+
* Return the key that has the minimal priority or nil when the queue is empty.
|
547
|
+
*
|
548
|
+
* q = PriorityQueue.new
|
549
|
+
* q["a"] = 10
|
550
|
+
* q["b"] = 20
|
551
|
+
* q.min_key #=> "a"
|
552
|
+
* q.delete_min #=> ["a", 10]
|
553
|
+
* q.min_key #=> "b"
|
554
|
+
* q.delete_min #=> ["b", 20]
|
555
|
+
* q.min_key #=> nil
|
533
556
|
*/
|
534
557
|
static
|
535
558
|
VALUE pq_min_key(VALUE self) {
|
@@ -542,8 +565,19 @@ VALUE pq_min_key(VALUE self) {
|
|
542
565
|
return Qnil;
|
543
566
|
}
|
544
567
|
|
545
|
-
/*
|
546
|
-
*
|
568
|
+
/* call-seq:
|
569
|
+
* min_priority -> priority
|
570
|
+
*
|
571
|
+
* Return the minimal priority or nil when the queue is empty.
|
572
|
+
*
|
573
|
+
* q = PriorityQueue.new
|
574
|
+
* q["a"] = 10
|
575
|
+
* q["b"] = 20
|
576
|
+
* q.min_priority #=> 10
|
577
|
+
* q.delete_min #=> ["a", 10]
|
578
|
+
* q.min_priority #=> 20
|
579
|
+
* q.delete_min #=> ["b", 20]
|
580
|
+
* q.min_priority #=> nil
|
547
581
|
*/
|
548
582
|
static
|
549
583
|
VALUE pq_min_priority(VALUE self) {
|
@@ -556,8 +590,17 @@ VALUE pq_min_priority(VALUE self) {
|
|
556
590
|
return Qnil;
|
557
591
|
}
|
558
592
|
|
559
|
-
/*
|
593
|
+
/* call-seq:
|
594
|
+
* delete_min -> [key, priority]
|
595
|
+
*
|
560
596
|
* Delete key with minimal priority and return [key, priority]
|
597
|
+
*
|
598
|
+
* q = PriorityQueue.new
|
599
|
+
* q["a"] = 1
|
600
|
+
* q["b"] = 0
|
601
|
+
* q.delete_min #=> ["b", 0]
|
602
|
+
* q.delete_min #=> ["a", 1]
|
603
|
+
* q.delete_min #=> nil
|
561
604
|
*/
|
562
605
|
static
|
563
606
|
VALUE pq_delete_min(VALUE self) {
|
@@ -574,8 +617,17 @@ VALUE pq_delete_min(VALUE self) {
|
|
574
617
|
}
|
575
618
|
}
|
576
619
|
|
577
|
-
/*
|
620
|
+
/* call-seq:
|
621
|
+
* delete_min_return_key -> key
|
622
|
+
*
|
578
623
|
* Delete key with minimal priority and return the key
|
624
|
+
*
|
625
|
+
* q = PriorityQueue.new
|
626
|
+
* q["a"] = 1
|
627
|
+
* q["b"] = 0
|
628
|
+
* q.delete_min_return_key #=> "b"
|
629
|
+
* q.delete_min_return_key #=> "a"
|
630
|
+
* q.delete_min_return_key #=> nil
|
579
631
|
*/
|
580
632
|
static
|
581
633
|
VALUE pq_delete_min_return_key(VALUE self) {
|
@@ -593,7 +645,17 @@ VALUE pq_delete_min_return_key(VALUE self) {
|
|
593
645
|
}
|
594
646
|
|
595
647
|
/*
|
648
|
+
* call-seq:
|
649
|
+
* delete_min_return_priority -> priority
|
650
|
+
*
|
596
651
|
* Delete key with minimal priority and return the priority value
|
652
|
+
*
|
653
|
+
* q = PriorityQueue.new
|
654
|
+
* q["a"] = 1
|
655
|
+
* q["b"] = 0
|
656
|
+
* q.delete_min_return_priority #=> 0
|
657
|
+
* q.delete_min_return_priority #=> 1
|
658
|
+
* q.delete_min_return_priority #=> nil
|
597
659
|
*/
|
598
660
|
static
|
599
661
|
VALUE pq_delete_min_return_priority(VALUE self) {
|
@@ -612,7 +674,9 @@ VALUE pq_delete_min_return_priority(VALUE self) {
|
|
612
674
|
|
613
675
|
/*
|
614
676
|
* call-seq:
|
615
|
-
*
|
677
|
+
* [key] = priority
|
678
|
+
* change_priority(key, priority)
|
679
|
+
* push(key, priority)
|
616
680
|
*
|
617
681
|
* Set the priority of a key.
|
618
682
|
*
|
@@ -641,7 +705,7 @@ VALUE pq_change_priority(VALUE self, VALUE object, VALUE priority) {
|
|
641
705
|
|
642
706
|
/*
|
643
707
|
* call-seq:
|
644
|
-
*
|
708
|
+
* [key] -> priority
|
645
709
|
*
|
646
710
|
* Return the priority of a key or nil if the key is not in the queue.
|
647
711
|
*
|
@@ -663,6 +727,9 @@ VALUE pq_get_priority(VALUE self, VALUE object) {
|
|
663
727
|
}
|
664
728
|
|
665
729
|
/*
|
730
|
+
* call-seq:
|
731
|
+
* has_key? key -> boolean
|
732
|
+
*
|
666
733
|
* Return false if the key is not in the queue, true otherwise.
|
667
734
|
*
|
668
735
|
* q = PriorityQueue.new
|
@@ -678,7 +745,9 @@ VALUE pq_has_key(VALUE self, VALUE object) {
|
|
678
745
|
|
679
746
|
return NIL_P(node_pointer) ? Qfalse : Qtrue;
|
680
747
|
}
|
681
|
-
/*
|
748
|
+
/* call-seq:
|
749
|
+
* length -> Fixnum
|
750
|
+
*
|
682
751
|
* Returns the number of elements of the queue.
|
683
752
|
*
|
684
753
|
* q = PriorityQueue.new
|
@@ -694,13 +763,17 @@ VALUE pq_length(VALUE self) {
|
|
694
763
|
}
|
695
764
|
|
696
765
|
/*
|
766
|
+
/* call-seq:
|
767
|
+
* delete(key) -> [key, priority]
|
768
|
+
* delete(key) -> nil
|
769
|
+
*
|
697
770
|
* Delete a key from the priority queue. Returns nil when the key was not in
|
698
771
|
* the queue and [key, priority] otherwise.
|
699
772
|
*
|
700
773
|
* q = PriorityQueue.new
|
701
774
|
* (0..10).each do | i | q[i.to_s] = i end
|
702
|
-
* q.delete(5)
|
703
|
-
* q.delete(5)
|
775
|
+
* q.delete(5) #=> ["5", 5]
|
776
|
+
* q.delete(5) #=> nil
|
704
777
|
*/
|
705
778
|
static
|
706
779
|
VALUE pq_delete(VALUE self, VALUE object) {
|
@@ -762,7 +835,7 @@ static
|
|
762
835
|
VALUE pq_to_dot(VALUE self) {
|
763
836
|
priority_queue* q = get_pq_from_value(self);
|
764
837
|
|
765
|
-
VALUE result_string = rb_str_new2("digraph
|
838
|
+
VALUE result_string = rb_str_new2("digraph fibonacci_heap {\n");
|
766
839
|
if (q->rootlist) {
|
767
840
|
priority_node* n1 = q->rootlist;
|
768
841
|
do {
|
@@ -789,9 +862,10 @@ void pq_each_helper(priority_queue *q, priority_node *n, void *args) {
|
|
789
862
|
};
|
790
863
|
|
791
864
|
/*
|
792
|
-
* Call the given block with each key, priority pair in the queue
|
865
|
+
* Call the given block with each [key, priority] pair in the queue
|
793
866
|
*
|
794
|
-
* Beware: Changing the queue in the block may lead to unwanted behaviour and
|
867
|
+
* Beware: Changing the queue in the block may lead to unwanted behaviour and
|
868
|
+
* even infinite loops.
|
795
869
|
*/
|
796
870
|
static
|
797
871
|
VALUE pq_each(VALUE self) {
|
@@ -806,7 +880,7 @@ VALUE pq_insert_node(VALUE node, VALUE queue) {
|
|
806
880
|
}
|
807
881
|
|
808
882
|
static
|
809
|
-
VALUE
|
883
|
+
VALUE pq_initialize_copy(VALUE copy, VALUE orig) {
|
810
884
|
if (copy == orig)
|
811
885
|
return copy;
|
812
886
|
|
@@ -851,14 +925,14 @@ void Init_CPriorityQueue() {
|
|
851
925
|
|
852
926
|
rb_define_alloc_func(cPriorityQueue, pq_alloc);
|
853
927
|
rb_define_method(cPriorityQueue, "initialize", pq_init, 0);
|
854
|
-
rb_define_method(cPriorityQueue, "initialize_copy",
|
855
|
-
rb_define_method(cPriorityQueue, "push", pq_push, 2);
|
928
|
+
rb_define_method(cPriorityQueue, "initialize_copy", pq_initialize_copy, 1);
|
856
929
|
rb_define_method(cPriorityQueue, "min", pq_min, 0);
|
857
930
|
rb_define_method(cPriorityQueue, "min_key", pq_min_key, 0);
|
858
931
|
rb_define_method(cPriorityQueue, "min_priority", pq_min_priority, 0);
|
859
932
|
rb_define_method(cPriorityQueue, "delete_min", pq_delete_min, 0);
|
860
933
|
rb_define_method(cPriorityQueue, "delete_min_return_key", pq_delete_min_return_key, 0);
|
861
934
|
rb_define_method(cPriorityQueue, "delete_min_return_priority", pq_delete_min_return_priority, 0);
|
935
|
+
rb_define_method(cPriorityQueue, "push", pq_change_priority, 2);
|
862
936
|
rb_define_method(cPriorityQueue, "change_priority", pq_change_priority, 2);
|
863
937
|
rb_define_method(cPriorityQueue, "[]=", pq_change_priority, 2);
|
864
938
|
rb_define_method(cPriorityQueue, "priority", pq_get_priority, 1);
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# Pure ruby Priority Queue
|
2
|
-
$stdout.sync = true
|
3
|
-
$stderr.sync = true
|
4
|
-
|
5
2
|
class RubyPriorityQueue
|
6
3
|
|
4
|
+
include Enumerable
|
5
|
+
|
7
6
|
private
|
8
7
|
|
8
|
+
#
|
9
9
|
def link_nodes(b1, b2)
|
10
10
|
return link_nodes(b2, b1) if b2.priority < b1.priority
|
11
11
|
|
@@ -66,8 +66,8 @@ class RubyPriorityQueue
|
|
66
66
|
|
67
67
|
return self
|
68
68
|
end
|
69
|
-
|
70
|
-
# Does not change length
|
69
|
+
|
70
|
+
# Does not change length
|
71
71
|
def insert_tree(tree)
|
72
72
|
if @rootlist == nil
|
73
73
|
@rootlist = @min = tree
|
@@ -113,7 +113,7 @@ class RubyPriorityQueue
|
|
113
113
|
raise "Child is neighbour" if c == self.left
|
114
114
|
@child = c
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
def to_dot(only_down = false, known_nodes = [])
|
118
118
|
p known_nodes.map { | n | n.dot_id }
|
119
119
|
p self.dot_id
|
@@ -151,15 +151,24 @@ class RubyPriorityQueue
|
|
151
151
|
|
152
152
|
public
|
153
153
|
|
154
|
+
# Returns the number of elements of the queue.
|
155
|
+
#
|
156
|
+
# q = PriorityQueue.new
|
157
|
+
# q.length #=> 0
|
158
|
+
# q[0] = 1
|
159
|
+
# q.length #=> 1
|
154
160
|
attr_reader :length
|
155
161
|
|
162
|
+
# Create a new, empty PriorityQueue
|
156
163
|
def initialize
|
157
164
|
@nodes = Hash.new
|
158
165
|
@rootlist = nil
|
159
166
|
@min = nil
|
160
167
|
@length = 0
|
161
168
|
end
|
162
|
-
|
169
|
+
|
170
|
+
# Print a priority queue as a dot-graph. The output can be fed to dot from the
|
171
|
+
# vizgraph suite to create a tree depicting the internal datastructure.
|
163
172
|
def to_dot
|
164
173
|
r = ["digraph fibheap {"]
|
165
174
|
#r << @rootlist.to_dot.join("\n") if @rootlist
|
@@ -175,11 +184,26 @@ class RubyPriorityQueue
|
|
175
184
|
r
|
176
185
|
end
|
177
186
|
|
187
|
+
# Call dot and gv displaying the datstructure
|
178
188
|
def display_dot
|
179
189
|
puts to_dot
|
180
190
|
system "echo '#{to_dot}' | twopi -Tps -Groot=ROOT -Goverlap=false> /tmp/dotfile.ps; gv /tmp/dotfile.ps"
|
181
191
|
end
|
182
|
-
|
192
|
+
|
193
|
+
# call-seq:
|
194
|
+
# [key] = priority
|
195
|
+
# change_priority(key, priority)
|
196
|
+
# push(key, priority)
|
197
|
+
#
|
198
|
+
# Set the priority of a key.
|
199
|
+
#
|
200
|
+
# q = PriorityQueue.new
|
201
|
+
# q["car"] = 50
|
202
|
+
# q["train"] = 50
|
203
|
+
# q["bike"] = 10
|
204
|
+
# q.min #=> ["bike", 10]
|
205
|
+
# q["car"] = 0
|
206
|
+
# q.min #=> ["car", 0]
|
183
207
|
def change_priority(key, priority)
|
184
208
|
return push(key, priority) unless @nodes[key]
|
185
209
|
|
@@ -202,7 +226,8 @@ class RubyPriorityQueue
|
|
202
226
|
|
203
227
|
self
|
204
228
|
end
|
205
|
-
|
229
|
+
|
230
|
+
# Add an object to the queue.
|
206
231
|
def push(key, priority)
|
207
232
|
return change_priority(key, priority) if @nodes[key]
|
208
233
|
@nodes[key] = node = Node.new(key, priority)
|
@@ -219,49 +244,113 @@ class RubyPriorityQueue
|
|
219
244
|
@length += 1
|
220
245
|
self
|
221
246
|
end
|
222
|
-
|
247
|
+
|
248
|
+
# Returns true if the array is empty, false otherwise.
|
223
249
|
def empty?
|
224
250
|
@rootlist.nil?
|
225
251
|
end
|
226
252
|
|
253
|
+
# call-seq:
|
254
|
+
# [key] -> priority
|
255
|
+
#
|
256
|
+
# Return the priority of a key or nil if the key is not in the queue.
|
257
|
+
#
|
258
|
+
# q = PriorityQueue.new
|
259
|
+
# (0..10).each do | i | q[i.to_s] = i end
|
260
|
+
# q["5"] #=> 5
|
261
|
+
# q[5] #=> nil
|
227
262
|
def [](key)
|
228
263
|
@nodes[key] and @nodes[key].priority
|
229
264
|
end
|
230
265
|
|
266
|
+
# call-seq:
|
267
|
+
# has_key? key -> boolean
|
268
|
+
#
|
269
|
+
# Return false if the key is not in the queue, true otherwise.
|
270
|
+
#
|
271
|
+
# q = PriorityQueue.new
|
272
|
+
# (0..10).each do | i | q[i.to_s] = i end
|
273
|
+
# q.has_key("5") #=> true
|
274
|
+
# q.has_key(5) #=> false
|
231
275
|
def has_key?(key)
|
232
276
|
@nodes.has_key?(key)
|
233
277
|
end
|
234
278
|
|
235
279
|
alias :[]= :push
|
236
280
|
|
281
|
+
# Call the given block with each [key, priority] pair in the queue
|
282
|
+
#
|
283
|
+
# Beware: Changing the queue in the block may lead to unwanted behaviour and
|
284
|
+
# even infinite loops.
|
237
285
|
def each
|
238
286
|
@nodes.each do | key, node |
|
239
287
|
yield(key, node.priority)
|
240
288
|
end
|
241
289
|
end
|
242
290
|
|
243
|
-
|
244
|
-
|
291
|
+
# call-seq:
|
292
|
+
# min -> [object, priority]
|
293
|
+
#
|
294
|
+
# Return the pair [object, priority] with minimal priority or nil when the
|
295
|
+
# queue is empty.
|
296
|
+
#
|
297
|
+
# q = PriorityQueue.new
|
298
|
+
# q["a"] = 10
|
299
|
+
# q["b"] = 20
|
300
|
+
# q.min #=> ["a", 10]
|
301
|
+
# q.delete_min #=> ["a", 10]
|
302
|
+
# q.min #=> ["b", 20]
|
303
|
+
# q.delete_min #=> ["b", 20]
|
304
|
+
# q.min #=> nil
|
245
305
|
def min
|
246
306
|
[@min.key, @min.priority] rescue nil
|
247
307
|
end
|
248
|
-
|
308
|
+
|
309
|
+
# call-seq:
|
310
|
+
# min_key -> object
|
311
|
+
#
|
312
|
+
# Return the key that has the minimal priority or nil when the queue is empty.
|
313
|
+
#
|
314
|
+
# q = PriorityQueue.new
|
315
|
+
# q["a"] = 10
|
316
|
+
# q["b"] = 20
|
317
|
+
# q.min_key #=> "a"
|
318
|
+
# q.delete_min #=> ["a", 10]
|
319
|
+
# q.min_key #=> "b"
|
320
|
+
# q.delete_min #=> ["b", 20]
|
321
|
+
# q.min_key #=> nil
|
249
322
|
def min_key
|
250
323
|
@min.key rescue nil
|
251
324
|
end
|
252
|
-
|
325
|
+
|
326
|
+
# call-seq:
|
327
|
+
# min_priority -> priority
|
328
|
+
#
|
329
|
+
# Return the minimal priority or nil when the queue is empty.
|
330
|
+
#
|
331
|
+
# q = PriorityQueue.new
|
332
|
+
# q["a"] = 10
|
333
|
+
# q["b"] = 20
|
334
|
+
# q.min_priority #=> 10
|
335
|
+
# q.delete_min #=> ["a", 10]
|
336
|
+
# q.min_priority #=> 20
|
337
|
+
# q.delete_min #=> ["b", 20]
|
338
|
+
# q.min_priority #=> nil
|
253
339
|
def min_priority
|
254
340
|
@min.priority rescue nil
|
255
341
|
end
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
342
|
+
|
343
|
+
# call-seq:
|
344
|
+
# delete(key) -> [key, priority]
|
345
|
+
# delete(key) -> nil
|
346
|
+
#
|
347
|
+
# Delete a key from the priority queue. Returns nil when the key was not in
|
348
|
+
# the queue and [key, priority] otherwise.
|
349
|
+
#
|
350
|
+
# q = PriorityQueue.new
|
351
|
+
# (0..10).each do | i | q[i.to_s] = i end
|
352
|
+
# q.delete(5) #=> ["5", 5]
|
353
|
+
# q.delete(5) #=> nil
|
265
354
|
def delete(key)
|
266
355
|
return nil unless n = @nodes.delete(key)
|
267
356
|
|
@@ -298,6 +387,47 @@ class RubyPriorityQueue
|
|
298
387
|
return [n.key, n.priority]
|
299
388
|
end
|
300
389
|
|
390
|
+
# call-seq:
|
391
|
+
# delete_min_return_key -> key
|
392
|
+
#
|
393
|
+
# Delete key with minimal priority and return the key
|
394
|
+
#
|
395
|
+
# q = PriorityQueue.new
|
396
|
+
# q["a"] = 1
|
397
|
+
# q["b"] = 0
|
398
|
+
# q.delete_min_return_key #=> "b"
|
399
|
+
# q.delete_min_return_key #=> "a"
|
400
|
+
# q.delete_min_return_key #=> nil
|
401
|
+
def delete_min_return_key
|
402
|
+
delete_min[0] rescue nil
|
403
|
+
end
|
404
|
+
|
405
|
+
# call-seq:
|
406
|
+
# delete_min_return_priority -> priority
|
407
|
+
#
|
408
|
+
# Delete key with minimal priority and return the priority value
|
409
|
+
#
|
410
|
+
# q = PriorityQueue.new
|
411
|
+
# q["a"] = 1
|
412
|
+
# q["b"] = 0
|
413
|
+
# q.delete_min_return_priority #=> 0
|
414
|
+
# q.delete_min_return_priority #=> 1
|
415
|
+
# q.delete_min_return_priority #=> nil
|
416
|
+
def delete_min_return_priority
|
417
|
+
delete_min[1] rescue nil
|
418
|
+
end
|
419
|
+
|
420
|
+
# call-seq:
|
421
|
+
# delete_min -> [key, priority]
|
422
|
+
#
|
423
|
+
# Delete key with minimal priority and return [key, priority]
|
424
|
+
#
|
425
|
+
# q = PriorityQueue.new
|
426
|
+
# q["a"] = 1
|
427
|
+
# q["b"] = 0
|
428
|
+
# q.delete_min #=> ["b", 0]
|
429
|
+
# q.delete_min #=> ["a", 1]
|
430
|
+
# q.delete_min #=> nil
|
301
431
|
def delete_min
|
302
432
|
return nil if self.empty?
|
303
433
|
result = self.min
|
@@ -351,7 +481,8 @@ class RubyPriorityQueue
|
|
351
481
|
|
352
482
|
result
|
353
483
|
end
|
354
|
-
|
484
|
+
|
485
|
+
# Returns a string representation of the priority queue.
|
355
486
|
def inspect
|
356
487
|
"<PriorityQueue: #{@nodes.map{|(_, n)| [n.key, n.priority]}.sort_by{|(_,p)|p}.inspect}>"
|
357
488
|
end
|
data/priority_queue.o
ADDED
Binary file
|
data/priority_queue.so
ADDED
Binary file
|
data/t.rb
ADDED
data/test/priority_queue_test.rb
CHANGED
@@ -93,6 +93,22 @@ module PriorityQueueTest
|
|
93
93
|
assert_equal(false, @q.empty?, "Filled queue should return false on empty?")
|
94
94
|
end
|
95
95
|
|
96
|
+
def test_push
|
97
|
+
20.times do | i |
|
98
|
+
@q.push i, i+10
|
99
|
+
end
|
100
|
+
|
101
|
+
20.times do | i |
|
102
|
+
@q.push i, i
|
103
|
+
end
|
104
|
+
|
105
|
+
20.times do | i |
|
106
|
+
assert_equal([i, i], @q.delete_min)
|
107
|
+
end
|
108
|
+
|
109
|
+
assert_equal(nil, @q.delete_min)
|
110
|
+
end
|
111
|
+
|
96
112
|
def test_push_pop
|
97
113
|
20.times do | i |
|
98
114
|
@q.push i, i
|
@@ -233,9 +249,6 @@ module PriorityQueueTest
|
|
233
249
|
end
|
234
250
|
qq = @q.dup
|
235
251
|
until @q.empty?
|
236
|
-
puts "--"
|
237
|
-
puts @q.inspect
|
238
|
-
puts qq.inspect
|
239
252
|
assert_equal(@q.delete_min, qq.delete_min)
|
240
253
|
end
|
241
254
|
end
|
@@ -251,7 +264,7 @@ module PriorityQueueTest
|
|
251
264
|
extend self
|
252
265
|
end
|
253
266
|
|
254
|
-
class CPriorityQueueTest
|
267
|
+
class CPriorityQueueTest < Test::Unit::TestCase
|
255
268
|
include PriorityQueueTest
|
256
269
|
|
257
270
|
def setup
|
@@ -264,7 +277,7 @@ class CPriorityQueueTest #< Test::Unit::TestCase
|
|
264
277
|
end
|
265
278
|
@q.delete_min
|
266
279
|
assert_equal(
|
267
|
-
['digraph
|
280
|
+
['digraph fibonacci_heap {',
|
268
281
|
' NODE [label="N1 (1)",shape=box];',
|
269
282
|
' NODE [label="N3 (3)",shape=box];',
|
270
283
|
' NODE [label="N4 (4)",shape=box];',
|
@@ -277,7 +290,7 @@ class CPriorityQueueTest #< Test::Unit::TestCase
|
|
277
290
|
|
278
291
|
end
|
279
292
|
|
280
|
-
class PoorPriorityQueueTest
|
293
|
+
class PoorPriorityQueueTest < Test::Unit::TestCase
|
281
294
|
include PriorityQueueTest
|
282
295
|
|
283
296
|
def setup
|
metadata
CHANGED
@@ -1,78 +1,67 @@
|
|
1
|
-
|
1
|
+
!ruby/object:Gem::Specification
|
2
2
|
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: PriorityQueue
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
6
|
+
version: 0.1.1
|
7
7
|
date: 2005-10-26 00:00:00 +02:00
|
8
|
-
summary: This is a
|
8
|
+
summary: This is a fibonacci-heap priority-queue implementation
|
9
9
|
require_paths:
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
- lib
|
11
|
+
- lib
|
12
|
+
- ext
|
13
13
|
email: priority_queue@brian-schroeder.de
|
14
14
|
homepage: http://ruby.brian-schroeder.de/priority_queue
|
15
15
|
rubyforge_project:
|
16
|
-
description: "This is a
|
17
|
-
O(1) decrease_priority: Amortized O(1) delete_min: Amortized O(log n)
|
18
|
-
This project is different from K. Kodamas PQueue in that it allows a decrease
|
19
|
-
key operation. That makes PriorityQueue usable for algorithms like dijkstras
|
20
|
-
shortest path algorithm, while PQueue is more suitable for Heapsort and the
|
21
|
-
like."
|
16
|
+
description: "This is a fibonacci-heap priority-queue implementation. That means insert: O(1) decrease_priority: Amortized O(1) delete_min: Amortized O(log n) This project is different from K. Kodamas PQueue in that it allows a decrease key operation. That makes PriorityQueue usable for algorithms like dijkstras shortest path algorithm, while PQueue is more suitable for Heapsort and the like."
|
22
17
|
autorequire: priority_queue.rb
|
23
18
|
default_executable:
|
24
19
|
bindir: bin
|
25
20
|
has_rdoc: true
|
26
21
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
27
22
|
requirements:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
version: 0.0.0
|
23
|
+
- - ">"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.0.0
|
32
26
|
version:
|
33
27
|
platform: ruby
|
34
28
|
signing_key:
|
35
29
|
cert_chain:
|
36
30
|
authors:
|
37
|
-
|
31
|
+
- Brian Schroeder
|
38
32
|
files:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
- benchmark/result-PriorityQueue.gp
|
61
|
-
- benchmark/result-RubyPriorityQueue.gp
|
62
|
-
- benchmark/dijkstra.rb
|
63
|
-
- benchmark/result-PoorPriorityQueue.gp
|
64
|
-
- benchmark/result-CPriorityQueue.png
|
65
|
-
- benchmark/results.csv
|
66
|
-
- benchmark/results.png
|
67
|
-
- benchmark/result-PoorPriorityQueue.png
|
68
|
-
- benchmark/result-RubyPriorityQueue.png
|
69
|
-
- benchmark/results.gp
|
70
|
-
- benchmark/result-CPriorityQueue.gp
|
33
|
+
- t.rb
|
34
|
+
- Makefile
|
35
|
+
- priority_queue.so
|
36
|
+
- README
|
37
|
+
- priority_queue.o
|
38
|
+
- compare_comments.rb
|
39
|
+
- CHANGELOG
|
40
|
+
- setup.rb
|
41
|
+
- ext
|
42
|
+
- lib
|
43
|
+
- test
|
44
|
+
- benchmark
|
45
|
+
- ext/priority_queue
|
46
|
+
- ext/priority_queue/extconf.rb
|
47
|
+
- ext/priority_queue/priority_queue.c
|
48
|
+
- lib/priority_queue.rb
|
49
|
+
- lib/priority_queue
|
50
|
+
- lib/priority_queue/poor_priority_queue.rb
|
51
|
+
- lib/priority_queue/ruby_priority_queue.rb
|
52
|
+
- test/priority_queue_test.rb
|
53
|
+
- benchmark/dijkstra.rb
|
71
54
|
test_files: []
|
55
|
+
|
72
56
|
rdoc_options: []
|
57
|
+
|
73
58
|
extra_rdoc_files: []
|
59
|
+
|
74
60
|
executables: []
|
61
|
+
|
75
62
|
extensions:
|
76
|
-
|
63
|
+
- ext/priority_queue/extconf.rb
|
77
64
|
requirements: []
|
78
|
-
|
65
|
+
|
66
|
+
dependencies: []
|
67
|
+
|
@@ -1,8 +0,0 @@
|
|
1
|
-
set term png
|
2
|
-
set out 'result-CPriorityQueue.png'
|
3
|
-
set xlabel 'Number of nodes'
|
4
|
-
set ylabel 'Time in seconds (real)'
|
5
|
-
set logscale xy
|
6
|
-
set title 'Dijkstras Shortest Path Algorithm on Networks of different degrees'
|
7
|
-
plot \
|
8
|
-
'results.csv' using 1:2 with lines title "CPriorityQueue (Graph of Degree: 16)"
|
Binary file
|
@@ -1,8 +0,0 @@
|
|
1
|
-
set term png
|
2
|
-
set out 'result-PoorPriorityQueue.png'
|
3
|
-
set xlabel 'Number of nodes'
|
4
|
-
set ylabel 'Time in seconds (real)'
|
5
|
-
set logscale xy
|
6
|
-
set title 'Dijkstras Shortest Path Algorithm on Networks of different degrees'
|
7
|
-
plot \
|
8
|
-
'results.csv' using 1:3 with lines title "PoorPriorityQueue (Graph of Degree: 16)"
|
Binary file
|
@@ -1,8 +0,0 @@
|
|
1
|
-
set term png
|
2
|
-
set out 'result-RubyPriorityQueue.png'
|
3
|
-
set xlabel 'Number of nodes'
|
4
|
-
set ylabel 'Time in seconds (real)'
|
5
|
-
set logscale xy
|
6
|
-
set title 'Dijkstras Shortest Path Algorithm on Networks of different degrees'
|
7
|
-
plot \
|
8
|
-
'results.csv' using 1:4 with lines title "RubyPriorityQueue (Graph of Degree: 16)"
|
Binary file
|
data/benchmark/results.csv
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
size "CPriorityQueue (Graph of Degree: 16)" "PoorPriorityQueue (Graph of Degree: 16)" "RubyPriorityQueue (Graph of Degree: 16)"
|
2
|
-
100 0.00583611594306098 0.0372195773654514 0.0697224669986301
|
3
|
-
200 0.0115931034088135 0.0454702642228868 0.545423454708523
|
4
|
-
300 0.0729258590274387 0.480532619688246 0.325443373786079
|
5
|
-
400 0.189983632829454 0.993642012278239 0.342083692550659
|
6
|
-
500 0.196244796117147 1.43146456612481 0.533440616395738
|
7
|
-
600 0.202457533942329 2.06269836425781 0.600252681308322
|
8
|
-
700 0.264183335834079 2.801170402103 0.72682441605462
|
9
|
-
800 0.270467466778225 3.94072720739577 0.799134042527941
|
10
|
-
900 0.443829695383708 4.89565277099609 0.985143608517117
|
11
|
-
1000 0.465132978227403 6.15393000178867 1.00162262386746
|
12
|
-
2000 0.740832858615451 27.4882550504473 2.40040622817145
|
13
|
-
3000 1.07575758298238 55.2952709992727 3.59957594341702
|
14
|
-
4000 1.47195853127374 '' 4.79923190010919
|
15
|
-
5000 1.86880042817858 '' 6.23916390207079
|
16
|
-
6000 2.40524856249491 '' 7.67889030774434
|
17
|
-
7000 2.80519718594021 '' 9.1503213511573
|
18
|
-
8000 3.32880263858371 '' 11.0491805076599
|
19
|
-
9000 3.58584565586514 '' 11.493485238817
|
20
|
-
10000 3.9917475912306 '' 13.0166101190779
|
21
|
-
20000 8.20343301031325 '' 26.9999283419715
|
22
|
-
30000 13.1478295061323 '' 43.9837118784587
|
23
|
-
40000 16.7911659081777 '' ''
|
24
|
-
50000 22.3882454766168 '' ''
|
25
|
-
60000 26.7571367687649 '' ''
|
26
|
-
70000 29.91215411822 '' ''
|
27
|
-
80000 37.1148204538557 '' ''
|
28
|
-
90000 '' '' ''
|
29
|
-
100000 '' '' ''
|
30
|
-
200000 '' '' ''
|
31
|
-
300000 '' '' ''
|
32
|
-
400000 '' '' ''
|
33
|
-
500000 '' '' ''
|
34
|
-
600000 '' '' ''
|
35
|
-
700000 '' '' ''
|
36
|
-
800000 '' '' ''
|
37
|
-
900000 '' '' ''
|
data/benchmark/results.gp
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
set term png
|
2
|
-
set out 'results.png'
|
3
|
-
set xlabel 'Number of nodes'
|
4
|
-
set ylabel 'Time in seconds (real)'
|
5
|
-
set logscale xy
|
6
|
-
set title 'Dijkstras Shortest Path Algorithm using different PQ Implementations'
|
7
|
-
plot \
|
8
|
-
'results.csv' using 1:2 with lines title "CPriorityQueue (Graph of Degree: 16)",\
|
9
|
-
'results.csv' using 1:3 with lines title "PoorPriorityQueue (Graph of Degree: 16)",\
|
10
|
-
'results.csv' using 1:4 with lines title "RubyPriorityQueue (Graph of Degree: 16)"
|
data/benchmark/results.png
DELETED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/doc/results.png
DELETED
Binary file
|