LoginSignup
3
1

More than 5 years have passed since last update.

赤黒木+graphivizによる可視化

Posted at

アルゴリズムイントロダクションに載ってる赤黒木を実装C#で実装してみました。
C#よくわかっていません。

RBTree.rb
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace ConsoleApplication
//namespace RBTree
{
    enum Color
    {
        RED,
        BLACK
    }



    class Node
    {
        internal Node p;
        internal Node left;
        internal Node right;
        public int key;
        public Color color;

        public Node(int key_)
        {
            this.key   = key_;
            this.p     = null;
            this.left  = null;
            this.right = null;
            this.color = Color.BLACK;
        }

        public void setColor(Color c)
        {
            if (c == Color.BLACK)
            {

                // Console.WriteLine("{0} [style = filled, fillcolor = #CCCCCC];", this.key);
            }
            else
            {
                // Console.WriteLine("{0} [style = filled,  fillcolor = #CC9999];", this.key);
            }

            this.color = c;
        }

    }


    class RBTree
    {
        public Node root;
        public Node nil;

        public RBTree()
        {
            this.nil = null;
        }

        public void leftRotate(Node x)
        {
            Node y = x.right;
            // βの付け替え
            x.right = y.left;
            if (y.left != nil)
            {
                y.left.p = x;
            }
            //yの親とのリンク
            y.p = x.p;
            if (x.p == nil)
            {
                root = y;
            }
            else if (x == x.p.left)
            {
                x.p.left = y;
            }
            else
            {
                x.p.right = y;
            }
            y.left = x;
            x.p = y;
        }
        public void rightRotate(Node y)
        {
            Node x = y.left;
            // βの付け替え
            y.left = x.right;            
            if (x.right != nil)
            {
                x.right.p = y;            
            }
            //yの親とのリンク           
            x.p = y.p;
            if (y.p == null)
            {
                root = x;
            }
            else if (y == y.p.left)
            {
                y.p.left = x;
            }
            else
            {
                y.p.right = x;
            }
            x.right = y;
            y.p = x;
        }

        public void insert(Node z)
        {
           Node y = nil;
           Node x = root;

            while (x != nil)
            {
                y = x;
                if (z.key < x.key)
                {
                    x = x.left;
                }
                else
                {
                    x = x.right;
                }
            }


            z.p = y;
            if (y == nil) {
                root = z;
            }
            else if (z.key < y.key)
            {
                y.left = z;
            }
            else
            {
                y.right = z;
            }
            z.left = nil;
            z.right = nil;
            z.color = Color.RED;
            insertFixup(z);
        }

        public void insertFixup(Node z)
        {
            while (z.p.color == Color.RED)
            {


                if (z.p == z.p.p.left)
                {
                    Node y = z.p.p.right;
                    if (y.color == Color.RED)
                    {
                        z.p.color = Color.BLACK;
                        y.color = Color.BLACK;
                        z.p.p.color = Color.RED;
                        z = z.p.p;
                        Console.WriteLine("case 1");
                        printGraphivz();
                    }
                    else{ 
                        if (z == z.p.right)
                        {
                            z = z.p;
                            this.leftRotate(z);
                            Console.WriteLine("case 2");
                            printGraphivz();
                        }
                        z.p.color = Color.BLACK;
                        z.p.p.color = Color.RED;
                        rightRotate(z.p.p);
                        Console.WriteLine("case 3");
                        printGraphivz();
                    }
                }
                else
                {
                    Node y = z.p.p.left;
                    if (y.color == Color.RED)
                    {
                        z.p.color = Color.BLACK;
                        y.color = Color.BLACK;
                        z.p.p.color = Color.RED;
                        z = z.p.p;
                        Console.WriteLine("case 1");
                        printGraphivz();
                    }
                    else {
                        if (z == z.p.left)
                        {
                            z = z.p;
                            this.leftRotate(z);
                            Console.WriteLine("case 2");
                            printGraphivz();
                        }
                        z.p.color = Color.BLACK;
                        z.p.p.color = Color.RED;
                        rightRotate(z.p.p);
                        Console.WriteLine("case 3");
                        printGraphivz();
                    }
                }
            }
            root.color = Color.BLACK;
            printGraphivz();
        }
        public Node minimum(Node x)
        {
            while (x.left != nil)
            {
                x = x.left; 
            }
            return x; 
        }
        public Node successor(Node x)
        {
            if (x.right != nil) {
                return minimum(x.right);
            }
            Node y = x.p;
            while (y != nil && x == y.right) {
                x = y;
                y = y.p  ;
            }
            return y;           
        } 

        public Node delete(Node z)
        {

            Node y;
            if (z.left  == nil || z.right == nil)
            {
                y = z;  
            }
            else {
                y =  successor(z);
            }
            Node x;
            if (y.left != nil) {
                x=y.left;
            }
            else {
                x = y.right;    

            }
            if (x != nil) {
                x.p = y.p;  
            }
            if (y.p == nil) {
                root = x;
            }
            else if (y == y.p.left) {
                y.p.left = x;
            }
            else {
                y.p.right = x;
            }
            if (y != z) {
                z.key = y.key;
            }
            return y;
        } 

        public void print()
        {
            Action<Node> loop = null;
            loop = (Node x) =>
            {
                if (x != nil)
                {
                    loop(x.left);
                    Console.WriteLine("{0}", x.key);
                    loop(x.right);
                }
            };
            loop(root);
        }

        private string str(Color color)
        {
            if (color == Color.RED)
            {
                return "#CC9999";
            }
            else
            {
                return "#CCCCCC";
            }
        }

        public void printGraphivz()
        {
            Action<Node> loop = null;
            loop = (Node x) =>
            {
                if (x != nil)
                {
                    Console.WriteLine("{0} [style = filled, fillcolor = \"{1}\"];", x.key, str(x.color));
                    if (x.left != nil)
                    {
                        Console.WriteLine("{0}->{1}[label = left];", x.key, x.left.key);
                    }
                    loop(x.left);
                    loop(x.right);
                    if (x.right != nil)
                    {
                        Console.WriteLine("{0}->{1}[label = right];", x.key, x.right.key);
                    }
                    if (x.p != nil)
                    {
                        Console.WriteLine("{0}->{1}[label = p];", x.key, x.p.key);
                    }
                }
            };

            string filename = (DateTime.Now).ToString("ddHHmmssfff");
            StreamWriter sw = new StreamWriter(String.Format("{0}.dot",filename), true, System.Text.Encoding.GetEncoding("utf-8")); // 文字コード
            Console.SetOut(sw);

            Console.WriteLine("strict digraph rbtrees{0} ",(DateTime.Now).ToString("ssfff"));
            Console.WriteLine("{");     
            loop(root);
            Console.WriteLine("}");

            sw.Dispose(); 
            System.IO.StreamWriter standard = new System.IO.StreamWriter(Console.OpenStandardOutput());
            standard.AutoFlush = true;
            Console.SetOut(standard);
            System.Diagnostics.Process.Start("dot", string.Format("-Tpng {0}.dot -o {0}.png",filename,filename));

        }
    }

    class Program
    {

        void test3()
        {
            Node n = new Node(15);
            RBTree t = new RBTree();
            t.root = n;
            t.root.left = new Node(5);
            t.root.left.p = t.root;

            t.root.left.left = new Node(3);
            t.root.left.left.p = t.root.left;

            t.root.left.right = new Node(12);
            t.root.left.right.p = t.root.left;

            t.root.left.right.right = new Node(13);
            t.root.left.right.right.p = t.root.left.right;



            t.root.left.right.left= new Node(10);
            t.root.left.right.left.p = t.root.left.right;

            t.root.left.right.left.left = new Node(6);
            t.root.left.right.left.left.p = t.root.left.right.left;

            t.root.left.right.left.left.right = new Node(7);
            t.root.left.right.left.left.right.p = t.root.left.right.left.left;


            t.root.right = new Node(16);
            t.root.right.p = t.root;

            t.root.right.right = new Node(20);
            t.root.right.right.p = t.root.right;

            t.root.right.right.left = new Node(18);
            t.root.right.right.left.p = t.root.right.right;

            t.root.right.right.right = new Node(23);
            t.root.right.right.right.p = t.root.right.right;

            t.printGraphivz();
            //t.delete (t.root.left.right.right);
            //t.delete(t.root.right);
            t.delete(t.root.left);
            t.printGraphivz();
        }

        void test2()
        {
            Node n = new Node(11);
            RBTree t = new RBTree();
            t.root = n;
            t.root.setColor(Color.BLACK);

            t.root.left = new Node(2);
            t.root.left.p = t.root;
            t.root.left.setColor(Color.RED);

            t.root.left.left = new Node(1);
            t.root.left.left.p = t.root.left;
            t.root.left.left.setColor(Color.BLACK);

            t.root.left.right = new Node(7);
            t.root.left.right.p = t.root.left;
            t.root.left.right.setColor(Color.BLACK);

            t.root.left.right.left = new Node(5);
            t.root.left.right.left.p = t.root.left.right;
            t.root.left.right.left.setColor(Color.RED);

            t.root.left.right.left.left = new Node(4);
            t.root.left.right.left.left.p = t.root.left.right.left;
            t.root.left.right.left.left.setColor(Color.RED);

            t.root.left.right.right = new Node(8);
            t.root.left.right.right.p = t.root.left.right;
            t.root.left.right.right.setColor(Color.RED);

            t.root.right = new Node(14);
            t.root.right.p = t.root;
            t.root.right.setColor(Color.BLACK);

            t.root.right.right = new Node(15);
            t.root.right.right.p = t.root.right;
            t.root.right.right.setColor(Color.RED);


            t.printGraphivz();
            t.insertFixup(t.root.left.right.left.left);


            //Node n2 = new Node(4);
            //n2.setColor(Color.RED);
            //t.insert(n2);

            //t.printGraphivz();

        }

        public void test1() 
        {
            Node n = new Node(7);
            RBTree t = new RBTree();
            t.root = n;

            t.root.left = new Node(4);
            t.root.left.p = t.root;

            t.root.left.left = new Node(3);
            t.root.left.left.p = t.root.left;
            //Console.WriteLine("{0}->{1}[label = p];", t.root.left.left.p.key, t.root.left.key);

            t.root.left.left.left = new Node(2);
            t.root.left.left.left.p = t.root.left.left;


            t.root.left.right = new Node(6);
            t.root.left.right.p = t.root.left;

            t.root.right = new Node(11);
            t.root.right.p = t.root;

            t.root.right.left = new Node(9);
            t.root.right.left.p = t.root.right;

            t.root.right.right = new Node(18);
            t.root.right.right.p = t.root.right;

            t.root.right.right.left = new Node(14);
            t.root.right.right.left.p = t.root.right.right;

            t.root.right.right.left.left = new Node(12);
            t.root.right.right.left.left.p = t.root.right.right.left;



            t.root.right.right.left.right = new Node(17);
            t.root.right.right.left.right.p = t.root.right.right.left;

            t.root.right.right.right = new Node(19);
            t.root.right.right.right.p = t.root.right.right;

            t.root.right.right.right.right = new Node(22);
            t.root.right.right.right.right.p = t.root.right.right.right;

            t.root.right.right.right.right.left = new Node(20);
            t.root.right.right.right.right.left.p = t.root.right.right.right.right;
            //Console.WriteLine("}");

            t.printGraphivz();

            //t.print();
            t.leftRotate(t.root.right);
            t.printGraphivz();
            t.rightRotate(t.root.right);
            t.printGraphivz();
            //t.print();
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.test3();
        }

    }
}
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1