PriorityQueue 0.1.0 → 0.1.1
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.
- 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
|