This documentation is automatically generated by online-judge-tools/verification-helper
require "./spec_helper" require "../../../src/datastructure/smultiset/red_black_tree" class SMultiSet::RedBlackTree::Node def verify if nil_node? left.nil_node?.should be_true right.nil_node?.should be_true end if left.node? key.should be >= left.key (red? && left.red?).should be_false left.parent.should eq self left.verify end if right.node? key.should be <= right.key (red? && right.red?).should be_false right.parent.should eq self right.verify end end end class SMultiSet::RedBlackTree def verify if root.node? root.parent.nil_node?.should be_true end root.verify end end run_smultiset_spec(SMultiSet::RedBlackTree, "SMultiSet::RedBlackTree")
# require "./spec_helper" require "spec" def run_smultiset_spec(type : MS.class, class_name : String) forall MS describe class_name + "(Int32)" do it "{}" do MS{3, 1, 4, 1, 5}.to_a.should eq [1, 1, 3, 4, 5] end it "#root" do s = MS(Int32).new s.root.nil_node?.should be_true end it "#size" do s = MS(Int32).new s.size.should eq 0 s.add 1 s.size.should eq 1 s.add 1 s.size.should eq 2 s.delete 1 s.size.should eq 1 end it "#empty?" do s = MS(Int32).new s.empty?.should be_true s.add 1 s.empty?.should be_false end it "#clear" do s = MS(Int32).new s.add 1 s.clear.size.should eq 0 end it "#add?" do s = MS(Int32).new s.add?(1).should be_true s.add?(1).should be_true s.verify end it "#add, #<<" do s = MS(Int32).new s.add(1).add(2).add(1) s.size.should eq 3 s << 3 << 4 << 3 s.size.should eq 6 s.verify end it "#min_node, #max_node" do s = MS(Int32).new s.min_node.nil_node?.should be_true s.max_node.nil_node?.should be_true s << 1 << 2 s.min_node.key?.should eq 1 s.max_node.key?.should eq 2 end it "#min?, #min, #max?, #max" do s = MS(Int32).new s.min?.should be_nil s.max?.should be_nil expect_raises(MS::EmptyError) { s.min } expect_raises(MS::EmptyError) { s.max } s << 1 << 2 s.min?.should eq 1 s.max?.should eq 2 s.min.should eq 1 s.max.should eq 2 end it "#split" do 1000.times do s = MS(Int32).new(1..10) l, r = s.split(5) l.to_a.should eq [1, 2, 3, 4, 5] r.to_a.should eq [6, 7, 8, 9, 10] s.verify end 10.times do s = MS(Int32).new(1..1000) l, r = s.split(500) l.to_a.should eq (1..500).to_a r.to_a.should eq (501..1000).to_a s.verify end end it "#each" do s = MS{3, 1, 4, 1, 5} a = [] of Int32 s.each { |x| a << x } a.should eq [1, 1, 3, 4, 5] end it "#reverse_each" do s = MS{3, 1, 4, 1, 5} a = [] of Int32 s.reverse_each { |x| a << x } a.should eq [5, 4, 3, 1, 1] end it "#includes?" do s = MS{1, 3, 3, 5} {1, 3, 5}.each { |x| s.includes?(x).should be_true } {0, 2, 4}.each { |x| s.includes?(x).should be_false } end it "#search" do s = MS{1, 3, 3, 5} {1, 3, 5}.each { |x| s.search(x).key?.should eq x } {0, 2, 4}.each { |x| s.search(x).nil_node?.should be_true } end it "#le, #le!, #le_node" do s = MS{1, 3} [nil, 1, 1, 3, 3].each_with_index { |e, x| s.le(x).should eq e } expect_raises(NilAssertionError) { s.le!(0) } [1, 1, 3, 3].each_with_index(1) { |e, x| s.le!(x).should eq e } s = MS{1, 1, 3} s.le_node(0).nil_node?.should be_true s.le_node(1).should eq s.min_node.succ s.le_node(2).should eq s.min_node.succ s.le_node(3).should eq s.max_node s.le_node(4).should eq s.max_node end it "#lt, #lt!, #lt_node" do s = MS{1, 3} [nil, nil, 1, 1, 3, 3].each_with_index { |e, x| s.lt(x).should eq e } expect_raises(NilAssertionError) { s.lt!(0) } expect_raises(NilAssertionError) { s.lt!(1) } [1, 1, 3, 3].each_with_index(2) { |e, x| s.lt!(x).should eq e } s = MS{1, 1, 3} s.lt_node(0).nil_node?.should be_true s.lt_node(1).nil_node?.should be_true s.lt_node(2).should eq s.min_node.succ s.lt_node(3).should eq s.min_node.succ s.lt_node(4).should eq s.max_node end it "#ge, #ge!, #ge_node" do s = MS{1, 3} [1, 1, 3, 3, nil].each_with_index { |e, x| s.ge(x).should eq e } expect_raises(NilAssertionError) { s.ge!(4) } [1, 1, 3, 3].each_with_index { |e, x| s.ge!(x).should eq e } s = MS{1, 1, 3} s.ge_node(0).should eq s.min_node s.ge_node(1).should eq s.min_node s.ge_node(2).should eq s.max_node s.ge_node(3).should eq s.max_node s.ge_node(4).nil_node?.should be_true end it "#gt, #gt!, #gt_node" do s = MS{1, 3} [1, 3, 3, nil, nil].each_with_index { |e, x| s.gt(x).should eq e } expect_raises(NilAssertionError) { s.gt!(3) } expect_raises(NilAssertionError) { s.gt!(4) } [1, 3, 3].each_with_index { |e, x| s.gt!(x).should eq e } s = MS{1, 1, 3} s.gt_node(0).should eq s.min_node s.gt_node(1).should eq s.max_node s.gt_node(2).should eq s.max_node s.gt_node(3).nil_node?.should be_true end it "#to_s, #inspect" do s = MS{1, 2, 3, 4} s.to_s.should eq "#{class_name}{1, 2, 3, 4}" s.inspect.should eq "#{class_name}{1, 2, 3, 4}" end it "big" do n = 10**4 s = MS(Int32).new (1..n).each do |x| s << x s.size.should eq x s.min.should eq 1 s.max.should eq x s.verify end s.to_a.should eq (1..n).to_a (-n..n*2).each do |x| s.includes?(x).should(1 <= x <= n ? be_true : be_false) end (1..n).each do |x| s.delete(x).should be_true s.delete(x).should be_false end end end it class_name + "(String)" do MS{"a", "c", "b"}.to_a.should eq %w[a b c] MS{"a", "ab", "abc", "abc"}.to_a.should eq %w[a ab abc abc] end end # require "../../../src/datastructure/smultiset/red_black_tree" # require "../binary_tree" module TreeNode(T) abstract def key : T abstract def left abstract def right abstract def parent def node? true end def nil_node? false end def key? : T? key end def key! : T key end def min_node : self x = self while x.left.node? x = x.left end x end def max_node : self x = self while x.right.node? x = x.right end x end def succ : self if right.node? return right.min_node end x, y = self, parent while y.node? && x != y.left x = y y = y.parent end y end def pred : self if left.node? return left.max_node end x, y = self, parent while y.node? && x != y.right x = y y = y.parent end y end def to_s(io : IO) io << '[' << key << ']' end def inspect(io : IO) to_s(io) end end module TreeNilNode(T) def node? false end def nil_node? true end def key? : T? nil end def key! raise NilAssertionError.new end def to_s(io : IO) io << "NilNode" end def inspect(io : IO) to_s(io) end end module BinaryTree(T, Node, NilNode) class EmptyError < Exception def initialize(message = "Empty RedBlackTree") super(message) end end include Enumerable(T) include Iterable(T) abstract def root abstract def size : Int32 abstract def add?(key : T) : Bool abstract def delete(key : T) : Bool def empty? : Bool root.nil_node? end def clear : self @root = NilNode.new @size = 0 self end def add(key : T) : self add?(key) self end def <<(key : T) : self add(key) end def rotate_left(x : Node) : Nil raise "x.right is nil!" if x.right.nil_node? y = x.right x.right = y.left y.left.parent = x if y.left.node? y.parent = x.parent if x.parent.nil_node? @root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.left = x x.parent = y end def rotate_right(x : Node) : Nil raise "x.left is nil!" if x.left.nil_node? y = x.left x.left = y.right y.right.parent = x if y.right.node? y.parent = x.parent if x.parent.nil_node? @root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.right = x x.parent = y end def min_node : Node root.min_node end def max_node : Node root.max_node end def min? : T? min_node.key? end def min : T min? || raise EmptyError.new end def max? : T? max_node.key? end def max : T max? || raise EmptyError.new end private class InorderWalkIterator(T, Node) include Iterator(T) def initialize(@node : Node) end def next if @node.nil_node? stop else @node.key.tap { @node = @node.succ } end end end def each(node : Node = min_node, &block) : Nil while node.node? yield node.key node = node.succ end end def each(node : Node = min_node) InorderWalkIterator(T, Node).new(node) end private class ReverseInorderWalkIterator(T, Node) include Iterator(T) def initialize(@node : Node) end def next if @node.nil_node? stop else @node.key.tap { @node = @node.pred } end end end def reverse_each(node : Node = max_node, &block) : Nil while node.node? yield node.key node = node.pred end end def reverse_each(node : Node = max_node) ReverseInorderWalkIterator(T, Node).new(node) end def includes?(key : T) : Bool x = root loop do return false if x.nil_node? cmp = key <=> x.key return true if cmp == 0 x = cmp < 0 ? x.left : x.right end end def search(key : T, x : Node = root) : Node while x.node? cmp = key <=> x.key break if cmp == 0 x = cmp < 0 ? x.left : x.right end x end def le_node(key : T, x : Node = root) : Node loop do cmp = key <=> x.key y = cmp < 0 ? x.left : x.right if y.nil_node? return cmp < 0 ? x.pred : x end x = y end end def lt_node(key : T, x : Node = root) : Node loop do cmp = key <=> x.key y = cmp <= 0 ? x.left : x.right if y.nil_node? return cmp <= 0 ? x.pred : x end x = y end end def ge_node(key : T, x : Node = root) : Node loop do cmp = key <=> x.key y = cmp <= 0 ? x.left : x.right if y.nil_node? return cmp <= 0 ? x : x.succ end x = y end end def gt_node(key : T, x : Node = root) : Node loop do cmp = key <=> x.key y = cmp < 0 ? x.left : x.right if y.nil_node? return cmp < 0 ? x : x.succ end x = y end end {% for method in [:le, :lt, :ge, :gt] %} def {{method.id}}(key : T) : T? {{method.id}}_node(key).key? end def {{method.id}}!(key : T) : T {{method.id}}_node(key).key! end {% end %} end # Copied with modifications from: https://github.com/crystal-lang/crystal/blob/1.1.1/samples/red_black_tree.cr class SMultiSet::RedBlackTree(T) class Node(T) enum Color Red Black end include TreeNode(T) property key : T, color : Color property! left : Node(T), right : Node(T), parent : Node(T) def initialize(@key : T, @color : Color = :red) @left = @right = @parent = NilNode(T).new end def black? color.black? end def red? color.red? end def split(split_key : T) : {Node(T), Node(T)} if nil_node? {NilNode(T).new, NilNode(T).new} elsif split_key < key l, r = left.split(split_key) self.left = r r.parent = self {l, self} else l, r = right.split(split_key) self.right = l l.parent = self {self, r} end end end class NilNode(T) < Node(T) include TreeNilNode(T) def initialize @key = uninitialized T @left = @right = @parent = self end end include BinaryTree(T, Node(T), NilNode(T)) getter root : Node(T), size : Int32 = 0 def initialize @root = NilNode(T).new end def initialize(enumerable : Enumerable(T)) initialize enumerable.each { |x| self << x } end protected def initialize(@root : Node(T)) end private def insert_node(x : Node(T)) : Nil insert_helper(x) x.color = :red while x != root && x.parent.red? if x.parent == x.parent.parent.left y = x.parent.parent.right if !y.nil_node? && y.red? x.parent.color = :black y.color = :black x.parent.parent.color = :red x = x.parent.parent else if x == x.parent.right x = x.parent left_rotate(x) end x.parent.color = :black x.parent.parent.color = :red right_rotate(x.parent.parent) end else y = x.parent.parent.left if !y.nil_node? && y.red? x.parent.color = :black y.color = :black x.parent.parent.color = :red x = x.parent.parent else if x == x.parent.left x = x.parent right_rotate(x) end x.parent.color = :black x.parent.parent.color = :red left_rotate(x.parent.parent) end end end root.color = :black end private def delete_node(z : Node(T)) : Nil y = (z.left.nil_node? || z.right.nil_node?) ? z : z.succ x = y.left.nil_node? ? y.right : y.left x.parent = y.parent if y.parent.nil_node? @root = x else if y == y.parent.left y.parent.left = x else y.parent.right = x end end z.key = y.key if y != z if y.black? delete_fixup(x) end @size -= 1 y end def add?(key : T) : Bool insert_node(Node.new(key)) true end def delete(key : T) : Bool node = search(key) return false if node.nil_node? delete_node(node) true end def split(key : T) : {self, self} l, r = root.split(key) l.parent = NilNode(T).new r.parent = NilNode(T).new {RedBlackTree(T).new(l), RedBlackTree(T).new(r)} end def black_height(x : Node = root) height = 0 until x.nil_node? x = x.left height += 1 if x.nil_node? || x.black? end height end def to_s(io : IO) : Nil io << "SMultiSet::RedBlackTree{" each_with_index do |x, i| io << ", " if i > 0 io << x end io << '}' end def inspect(io : IO) : Nil to_s(io) end private def left_rotate(x : Node) raise "x.right is nil!" if x.right.nil_node? y = x.right x.right = y.left y.left.parent = x if !y.left.nil_node? y.parent = x.parent if x.parent.nil_node? @root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.left = x x.parent = y end private def right_rotate(x : Node) raise "x.left is nil!" if x.left.nil_node? y = x.left x.left = y.right y.right.parent = x if !y.right.nil_node? y.parent = x.parent if x.parent.nil_node? @root = y else if x == x.parent.left x.parent.left = y else x.parent.right = y end end y.right = x x.parent = y end private def insert_helper(z : Node) y = NilNode(T).new x = root while !x.nil_node? y = x x = (z.key < x.key) ? x.left : x.right end z.parent = y if y.nil_node? @root = z else z.key < y.key ? y.left = z : y.right = z end @size += 1 end private def delete_fixup(x : Node) while x != root && x.black? if x == x.parent.left w = x.parent.right if w.red? w.color = :black x.parent.color = :red left_rotate(x.parent) w = x.parent.right end if w.left.black? && w.right.black? w.color = :red x = x.parent else if w.right.black? w.left.color = :black w.color = :red right_rotate(w) w = x.parent.right end w.color = x.parent.color x.parent.color = :black w.right.color = :black left_rotate(x.parent) x = root end else w = x.parent.left if w.red? w.color = :black x.parent.color = :red right_rotate(x.parent) w = x.parent.left end if w.right.black? && w.left.black? w.color = :red x = x.parent else if w.left.black? w.right.color = :black w.color = :red left_rotate(w) w = x.parent.left end w.color = x.parent.color x.parent.color = :black w.left.color = :black right_rotate(x.parent) x = root end end end x.color = :black end end class SMultiSet::RedBlackTree::Node def verify if nil_node? left.nil_node?.should be_true right.nil_node?.should be_true end if left.node? key.should be >= left.key (red? && left.red?).should be_false left.parent.should eq self left.verify end if right.node? key.should be <= right.key (red? && right.red?).should be_false right.parent.should eq self right.verify end end end class SMultiSet::RedBlackTree def verify if root.node? root.parent.nil_node?.should be_true end root.verify end end run_smultiset_spec(SMultiSet::RedBlackTree, "SMultiSet::RedBlackTree")