This documentation is automatically generated by online-judge-tools/verification-helper
require "spec" require "../../src/datastructure/binary_heap" describe BinaryHeap do describe ".new" do it "creates empty heap" do a = BinaryHeap(Int32).new a << 3 << 1 << 2 a.sort.should eq [1, 2, 3] end it "creates with enumerable" do a = BinaryHeap(Int32).new(1..9) a.sort.should eq (1..9).to_a end it "creates with compare block" do a = BinaryHeap(Int32).new { |a, b| b <=> a } a << 3 << 1 << 2 a.sort.should eq [3, 2, 1] end it "creates with enumerable and compare block" do a = BinaryHeap(Int32).new(1..9) { |a, b| b <=> a } a.sort.should eq (1..9).reverse_each.to_a end end it "BinaryHeap{}" do a = BinaryHeap{3, 1, 2} a.sort.should eq [1, 2, 3] end it "#size" do BinaryHeap(Int32).new.size.should eq 0 BinaryHeap{1, 2, 3}.size.should eq 3 end it "#empty?" do BinaryHeap(Int32).new.should be_empty BinaryHeap{1, 2, 3}.should_not be_empty end it "#clear" do a = BinaryHeap{1, 2, 3} a.clear.should be a a.should be_empty end it "#dup" do a = BinaryHeap{[1], [2], [3]} b = a.dup b.should eq a b.should_not be a a.top.should be b.top end it "#clone" do a = BinaryHeap{[1], [2], [3]} b = a.clone b.should eq a b.should_not be a a.top.should_not be b.top end describe "compare" do a = BinaryHeap{1, 2, 3} b = BinaryHeap{3, 2, 1} c = BinaryHeap{1, 2} it "#==" do (a == b).should be_true (a == c).should be_false end it "#!=" do (a != b).should be_false (a != c).should be_true end end describe "#top" do context "when heap is not empty" do it "returns top element" do a = BinaryHeap{3, 1, 2} a.top.should eq 1 a.top?.should eq 1 a.top { "none" }.should eq 1 end end context "when heap is empty" do it "returns top element" do a = BinaryHeap(Int32).new expect_raises(IndexError) { a.top } a.top?.should be_nil a.top { "none" }.should eq "none" end end end it "#add, #<<" do a = BinaryHeap(Int32).new a.add(1).add(2).should be a (a << 1 << 2 << 3).should be a a.sort.should eq [1, 1, 2, 2, 3] end describe "#pop" do it "pops when heap is not empty" do a = BinaryHeap{1, 2, 3} a.pop.should eq 1 a.pop?.should eq 2 a.pop { "none" }.should eq 3 end it "pops when heap is empty" do a = BinaryHeap(Int32).new expect_raises(IndexError) { a.pop } a.pop?.should be_nil a.pop { "none" }.should eq "none" end it "pops many elements" do a = BinaryHeap{1, 2, 3, 4, 5} a.pop(3).should eq [1, 2, 3] a.sort.should eq [4, 5] a.pop(2).should eq [4, 5] a.sort.should eq [] of Int32 end it "pops more elements that what is available" do a = BinaryHeap{1, 2, 3, 4, 5} a.pop(9).should eq [1, 2, 3, 4, 5] a.should be_empty a.pop(1).should eq [] of Int32 end it "raises if pops negative number of elements" do a = BinaryHeap{1, 2} expect_raises(ArgumentError) { a.pop(-1) } end end describe "#each" do a = BinaryHeap{3, 1, 2} it "receives block" do b = [] of Int32 a.each { |x| b << x } b.sort.should eq [1, 2, 3] end it "returns Iterator" do a.each.should be_a Iterator(Int32) a.each.min.should eq 1 a.each.max.should eq 3 a.each.cycle(2).to_a.sort.should eq [1, 1, 2, 2, 3, 3] end end it "#sort" do a = BinaryHeap{3, 1, 2} a.sort.should eq [1, 2, 3] b = BinaryHeap.new([1, 2, 3]) { |a, b| b <=> a } b.sort.should eq [3, 2, 1] end it "#to_a" do a = BinaryHeap{3, 1, 2} a.to_a.sort.should eq [1, 2, 3] a = BinaryHeap{3, 1, 4, 1, 5} a.to_a.sort.should eq [1, 1, 3, 4, 5] end it "#to_s, #inspect" do a = BinaryHeap{3, 1, 4} a.to_s.should eq "BinaryHeap{1, 3, 4}" a.inspect.should eq "BinaryHeap{1, 3, 4}" end it "includes Enumerable(T)" do a = BinaryHeap{1, 2, 3} a.sort.should eq [1, 2, 3] a.min.should eq 1 a.max.should eq 3 end it "includes Iterable(T)" do a = BinaryHeap{1, 2, 3} a.cycle(2).should be_a Iterator(Int32) a.cycle(2).to_a.should eq [1, 2, 3, 1, 2, 3] a.each_cons(2).to_a.should eq [[1, 2], [2, 3]] end describe "big test" do it "hasn't compare proc" do n = 100000 [ Array.new(n) { rand(Int32) }, Array.new(n) { rand(100) }, (1..n).to_a, (1..n).to_a.reverse, ].each do |values| a = BinaryHeap(Int32).new values.each { |x| a << x } a.sort.should eq values.sort end end it "has compare proc" do n = 100000 [ Array.new(n) { rand(Int32) }, Array.new(n) { rand(100) }, (1..n).to_a, (1..n).to_a.reverse, ].each do |values| a = BinaryHeap(Int32).new { |a, b| b <=> a } values.each { |x| a << x } a.sort.should eq values.sort_by(&.-) end end end describe "generics" do it "Float64" do BinaryHeap{1.1, 2.2, 3.3}.to_a.should eq [1.1, 2.2, 3.3] end it "String" do BinaryHeap.new(%w[D C B A]).to_a.should eq %w[A B C D] end end end
require "spec" # require "../../src/datastructure/binary_heap" class BinaryHeap(T) # Creates a new empty heap. def initialize @heap = Array(T).new @compare_proc = nil end # Creates a new empty heap backed by a buffer that is initially *initial_capacity* big (default: `0`). # # ``` # a = BinaryHeap.new(3) # a << 3 << 1 << 2 # a.pop # => 1 # a.pop # => 2 # a.pop # => 3 # ``` def initialize(initial_capacity : Int = 0) @heap = Array(T).new(initial_capacity) @compare_proc = nil end # Creates a new heap from the elements in *enumerable*. # # ``` # a = BinaryHeap.new [3, 1, 2] # a.pop # => 1 # a.pop # => 2 # a.pop # => 3 # ``` def initialize(enumerable : Enumerable(T)) initialize enumerable.each { |x| add(x) } end # Creates a new empty heap with the custom comperator. # # The block must implement a comparison between two elements *a* and *b*, where `a < b` returns `-1`, # `a == b` returns `0`, and `a > b` returns `1`. The comparison operator `#<=>` can be used for this. # # ``` # a = BinaryHeap.new [3, 1, 2] # a.pop # => 1 # b = BinaryHeap.new [3, 1, 2] { |a, b| b <=> a } # b.pop # => 3 # ``` def initialize(initial_capacity : Int = 0, &block : T, T -> Int32?) @heap = Array(T).new(initial_capacity) @compare_proc = block end # :ditto: def initialize(enumerable : Enumerable(T), &block : T, T -> Int32?) initialize &block enumerable.each { |x| add(x) } end include Enumerable(T) include Iterable(T) def_clone # Returns true if both heap have the same elements. def ==(other : BinaryHeap(T)) : Bool return false if size != other.size @heap.sort == other.@heap.sort end # Returns the number of elements in the heap. def size : Int32 @heap.size end # Returns `true` if `self` is empty, `false` otherwise. def empty? : Bool @heap.empty? end # Removes all elements from the heap and returns `self`. def clear : self @heap.clear self end # Returns the lowest value in the `self`. # If the `self` is empty, calls the block and returns its value. def top(&block) @heap.first { yield } end # Returns the lowest value in the `self`. # If the `self` is empty, returns `nil`. def top? : T? top { nil } end # Returns the lowest value in the `self`. # If the `self` is empty, raises `IndexError`. def top : T top { raise IndexError.new } end # Requires `0 <= i < size`, `0 <= j < size`. private def compare(i : Int32, j : Int32) x, y = @heap.unsafe_fetch(i), @heap.unsafe_fetch(j) if @compare_proc v = @compare_proc.not_nil!.call(x, y) raise ArgumentError.new("Comparison of #{x} and #{y} failed") if v.nil? v > 0 else x > y end end # Adds *object* to the heap and returns `self`. def add(object : T) : self @heap << object i = size - 1 parent = i.pred // 2 while i > 0 && compare(parent, i) @heap.swap(parent, i) i, parent = parent, parent.pred // 2 end self end # :ditto: def <<(object : T) : self add(object) end # Removes the lowest value from `self` and returns the removed value. # If the array is empty, the given block is called. def pop(&block) case size when 0 yield when 1 @heap.pop else value = @heap.unsafe_fetch(0) @heap[0] = @heap.pop i = 0 loop do left, right = i * 2 + 1, i * 2 + 2 j = if right < size && compare(i, right) compare(left, right) ? right : left elsif left < size && compare(i, left) left else break end @heap.swap(i, j) i = j end value end end # Like `#pop`, but returns `nil` if `self` is empty. def pop? : T? pop { nil } end # Removes the lowest value from `self` and returns the removed value. # Raises `IndexError` if heap is of 0 size. def pop : T pop { raise IndexError.new } end # Removes the last *n* values from `self` ahd returns the removed values. def pop(n : Int) : Array(T) raise ArgumentError.new unless n >= 0 n = Math.min(n, size) Array.new(n) { pop } end # Yields each element of the heap, and returns `nil`. def each(&) : Nil @heap.each { |elem| yield elem } end # Returns an iterator for each element of the heap. def each @heap.each end # Returns a new array with all elements sorted. # # ``` # a = BinaryHeap.new [3, 1, 2] # a.sort # => [1, 2, 3] # b = BinaryHeap.new [3, 1, 2] { |a, b| b <=> a } # b.sort # => [3, 2, 1] # ``` def sort : Array(T) if @compare_proc @heap.sort { |a, b| @compare_proc.not_nil!.call(a, b) } else @heap.sort end end # Returns the elements as an Array. # # ``` # BinaryHeap{3, 1, 2}.to_a # => [1, 3, 2] # ``` def to_a : Array(T) @heap.dup end # Writes a string representation of the heap to `io`. # # ``` # BinaryHeap{1, 2}.to_s # => "BinaryHeap{1, 2}" # ``` def to_s(io : IO) : Nil io << "BinaryHeap{" # TODO: use join each_with_index do |x, i| io << ", " if i > 0 io << x end io << '}' end # Writes a string representation of the heap to `io`. # # ``` # BinaryHeap{1, 2}.inspect # => "BinaryHeap{1, 2}" # ``` def inspect(io : IO) : Nil to_s(io) end end describe BinaryHeap do describe ".new" do it "creates empty heap" do a = BinaryHeap(Int32).new a << 3 << 1 << 2 a.sort.should eq [1, 2, 3] end it "creates with enumerable" do a = BinaryHeap(Int32).new(1..9) a.sort.should eq (1..9).to_a end it "creates with compare block" do a = BinaryHeap(Int32).new { |a, b| b <=> a } a << 3 << 1 << 2 a.sort.should eq [3, 2, 1] end it "creates with enumerable and compare block" do a = BinaryHeap(Int32).new(1..9) { |a, b| b <=> a } a.sort.should eq (1..9).reverse_each.to_a end end it "BinaryHeap{}" do a = BinaryHeap{3, 1, 2} a.sort.should eq [1, 2, 3] end it "#size" do BinaryHeap(Int32).new.size.should eq 0 BinaryHeap{1, 2, 3}.size.should eq 3 end it "#empty?" do BinaryHeap(Int32).new.should be_empty BinaryHeap{1, 2, 3}.should_not be_empty end it "#clear" do a = BinaryHeap{1, 2, 3} a.clear.should be a a.should be_empty end it "#dup" do a = BinaryHeap{[1], [2], [3]} b = a.dup b.should eq a b.should_not be a a.top.should be b.top end it "#clone" do a = BinaryHeap{[1], [2], [3]} b = a.clone b.should eq a b.should_not be a a.top.should_not be b.top end describe "compare" do a = BinaryHeap{1, 2, 3} b = BinaryHeap{3, 2, 1} c = BinaryHeap{1, 2} it "#==" do (a == b).should be_true (a == c).should be_false end it "#!=" do (a != b).should be_false (a != c).should be_true end end describe "#top" do context "when heap is not empty" do it "returns top element" do a = BinaryHeap{3, 1, 2} a.top.should eq 1 a.top?.should eq 1 a.top { "none" }.should eq 1 end end context "when heap is empty" do it "returns top element" do a = BinaryHeap(Int32).new expect_raises(IndexError) { a.top } a.top?.should be_nil a.top { "none" }.should eq "none" end end end it "#add, #<<" do a = BinaryHeap(Int32).new a.add(1).add(2).should be a (a << 1 << 2 << 3).should be a a.sort.should eq [1, 1, 2, 2, 3] end describe "#pop" do it "pops when heap is not empty" do a = BinaryHeap{1, 2, 3} a.pop.should eq 1 a.pop?.should eq 2 a.pop { "none" }.should eq 3 end it "pops when heap is empty" do a = BinaryHeap(Int32).new expect_raises(IndexError) { a.pop } a.pop?.should be_nil a.pop { "none" }.should eq "none" end it "pops many elements" do a = BinaryHeap{1, 2, 3, 4, 5} a.pop(3).should eq [1, 2, 3] a.sort.should eq [4, 5] a.pop(2).should eq [4, 5] a.sort.should eq [] of Int32 end it "pops more elements that what is available" do a = BinaryHeap{1, 2, 3, 4, 5} a.pop(9).should eq [1, 2, 3, 4, 5] a.should be_empty a.pop(1).should eq [] of Int32 end it "raises if pops negative number of elements" do a = BinaryHeap{1, 2} expect_raises(ArgumentError) { a.pop(-1) } end end describe "#each" do a = BinaryHeap{3, 1, 2} it "receives block" do b = [] of Int32 a.each { |x| b << x } b.sort.should eq [1, 2, 3] end it "returns Iterator" do a.each.should be_a Iterator(Int32) a.each.min.should eq 1 a.each.max.should eq 3 a.each.cycle(2).to_a.sort.should eq [1, 1, 2, 2, 3, 3] end end it "#sort" do a = BinaryHeap{3, 1, 2} a.sort.should eq [1, 2, 3] b = BinaryHeap.new([1, 2, 3]) { |a, b| b <=> a } b.sort.should eq [3, 2, 1] end it "#to_a" do a = BinaryHeap{3, 1, 2} a.to_a.sort.should eq [1, 2, 3] a = BinaryHeap{3, 1, 4, 1, 5} a.to_a.sort.should eq [1, 1, 3, 4, 5] end it "#to_s, #inspect" do a = BinaryHeap{3, 1, 4} a.to_s.should eq "BinaryHeap{1, 3, 4}" a.inspect.should eq "BinaryHeap{1, 3, 4}" end it "includes Enumerable(T)" do a = BinaryHeap{1, 2, 3} a.sort.should eq [1, 2, 3] a.min.should eq 1 a.max.should eq 3 end it "includes Iterable(T)" do a = BinaryHeap{1, 2, 3} a.cycle(2).should be_a Iterator(Int32) a.cycle(2).to_a.should eq [1, 2, 3, 1, 2, 3] a.each_cons(2).to_a.should eq [[1, 2], [2, 3]] end describe "big test" do it "hasn't compare proc" do n = 100000 [ Array.new(n) { rand(Int32) }, Array.new(n) { rand(100) }, (1..n).to_a, (1..n).to_a.reverse, ].each do |values| a = BinaryHeap(Int32).new values.each { |x| a << x } a.sort.should eq values.sort end end it "has compare proc" do n = 100000 [ Array.new(n) { rand(Int32) }, Array.new(n) { rand(100) }, (1..n).to_a, (1..n).to_a.reverse, ].each do |values| a = BinaryHeap(Int32).new { |a, b| b <=> a } values.each { |x| a << x } a.sort.should eq values.sort_by(&.-) end end end describe "generics" do it "Float64" do BinaryHeap{1.1, 2.2, 3.3}.to_a.should eq [1.1, 2.2, 3.3] end it "String" do BinaryHeap.new(%w[D C B A]).to_a.should eq %w[A B C D] end end end