library_for_python

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Kazun1998/library_for_python

:heavy_check_mark: Binary_Tree/Red_and_Black_Tree.py

Verified with

Code

"""
Reference
http://fujimura2.fiw-web.net/java/mutter/tree/red-black-tree.html
"""

class Red_and_Black_Node:
    def __init__(self, key, value,color=1):
        self.key=key
        self.value=value
        self.left=None
        self.right=None
        self.__color=color # 0 ならば黒, 1 ならば赤
        self.size=1

    def get_color(self):
        return self.__color

    def set_black(self):
        self.__color=0

    def set_red(self):
        self.__color=1

    def is_black(self):
        return self.__color==0

    def is_red(self):
        return self.__color==1

    def __str__(self):
        return "key: {}, value: {}, color: {}".format(self.key, self.value, "Red" if self.__color else "Black")

    def __repr__(self):
        return "[Red and Black Node]: "+str(self)

class Red_and_Black_Tree:
    def __init__(self):
        self.root=None

    def __len__(self):
        return self.get_size(self.root)

    def insert(self, key, value=None):
        if not self.root:
            # Case 0 : new node is root
            self.root=Red_and_Black_Node(key, value, 0)
            return

        history=[]
        node=self.root
        while node:
            history.append(node)
            if key==node.key:
                node.value=value
                return
            elif key<node.key:
                node=node.left
            else:
                node=node.right

        P=history[-1]
        N=Red_and_Black_Node(key, value)

        if N.key<P.key:
            P.left=N
        else:
            P.right=N

        active=True

        while True:
            if not active:
                self.set_size(N)
                if not history:
                    return

                N=history.pop()
                continue

            # Case 0 : N is root
            if self.is_root(N):
                N.set_black()
                self.set_size(N)
                return

            P=history[-1]
            # Case I
            if self.is_black(P):
                active=False
                self.set_size(N)
                history.pop()
                N=P
                continue

            # N,P is red. Then, exists G (parent of P) and G is red.
            G=history[-2]
            if P.key<G.key:
                U=G.right
            else:
                U=G.left

            # Case II
            if self.is_red(U):
                G.set_red()
                P.set_black()
                U.set_black()
                history.pop(); history.pop()
                self.set_size(N); self.set_size(P)
                N=G
                continue

            # Case III-LR
            if P.key<N.key<G.key:
                self.left_rotation(P,G)
                history.pop()
                history.append(N)
                N,P=P,N

            # Case III-RL
            if G.key<N.key<P.key:
                self.right_rotation(P,G)
                history.pop()
                history.append(N)
                N,P=P,N

            # Case IV-LL:
            if N.key<P.key<G.key:
                if len(history)>=3:
                    Z=history[-3]
                else:
                    Z=None
                self.right_rotation(G,Z)
                P.set_black()
                G.set_red()

                active=False
                self.set_size(N)
                N=history.pop()
                continue

            # Case IV-RR:
            if G.key<P.key<N.key:
                if len(history)>=3:
                    Z=history[-3]
                else:
                    Z=None
                self.left_rotation(G,Z)
                P.set_black()
                G.set_red()

                active=False
                self.set_size(N)
                N=history.pop()
                continue

    def delete(self, key):
        node=self.root

        history=[]
        while node:
            history.append(node)
            if node.key==key:
                break
            elif key<node.key:
                node=node.left
            else:
                node=node.right
        else:
            return

        history.pop()

        K=node
        if K.right:
            history.append(K)
            T=K.right
            while T.left:
                history.append(T)
                T=T.left
            K.key=T.key
            K.value=T.value
        else:
            T=K

        P=history[-1] if history else None

        if (P is None) and (T.left is None) and (T.right is None):
            self.root=None
            return

        if T.left is None:
            N=T.right
        else:
            N=T.left

        if (P is None) or (T.key<P.key):
            direction=0
        else:
            direction=1

        self.child_set(N,P,T.key)

        if self.is_red(T):
            for X in history[::-1]:
                self.set_size(X)
            return

        if self.is_red(N):
            N.set_black()
            for X in history[::-1]:
                self.set_size(X)
            return

        active=True
        while True:
            if not active:
                self.set_size(N)

                if not history:
                    return

                N=history.pop()
                continue

            # Case I : N is root.
            if self.is_root(N):
                self.set_size(N)
                return

            P=history[-1]
            if N:
                # (初回以外は必ずこっちの分岐になる)
                if N.key<P.key:
                    direction=0
                    S=P.right
                else:
                    direction=1
                    S=P.left
            else:
                if direction==1:
                    S=P.left
                else:
                    S=P.right

            L=S.left; R=S.right

            if len(history)>=2:
                G=history[-2]
            else:
                G=None

            # Case II : S is red.
            if self.is_red(S):
                P.set_red(); S.set_black()
                history.pop()
                history.append(S); history.append(P)

                if direction==0:
                    self.left_rotation(P,G)
                    S=L
                else:
                    self.right_rotation(P,G)
                    S=R
                G=history[-2] if len(history)>=2 else None
                L=S.left; R=S.right

            # Case III :
            if self.is_black(P) and self.is_black(L) and self.is_black(R):
                S.set_red()

                self.set_size(N)
                N=history.pop()
                continue

            # Case IV :
            if self.is_red(P) and self.is_black(L) and self.is_black(R):
                P.set_black()
                S.set_red()

                active=False
                self.set_size(N)
                N=history.pop()
                continue

            # Case V
            if self.is_red(L) and self.is_black(R) and direction==0:
                self.right_rotation(S,P)
                self.set_size(S); self.set_size(L)
                S.set_red(); L.set_black()
                S=L

            if self.is_black(L) and self.is_red(R) and direction==1:
                self.left_rotation(S,P)
                self.set_size(S); self.set_size(R)
                S.set_red(); R.set_black()
                S=R

            L=S.left; R=S.right

            # Case VI :
            if self.is_red(R) and direction==0:
                self.left_rotation(P,G)
                self.swap_color(P,S)
                R.set_black()
                history.pop()
                history.append(S); history.append(P)

                active=False
                self.set_size(N)
                N=history.pop()
                continue

            if self.is_red(L) and direction==1:
                self.right_rotation(P,G)
                self.swap_color(P,S)
                L.set_black()
                history.pop()
                history.append(S); history.append(P)

                active=False
                self.set_size(N)
                N=history.pop()
                continue

    def child_set(self, X, Y, key):
        """ Y の子に X を設定する (Y が None ならば, X を根にする) """

        if Y is None:
            self.root=X
        else:
            if key<Y.key:
                Y.left=X
            else:
                Y.right=X
        return

    def right_rotation(self, node, parent):
        X=node.left
        Y=X.right

        if parent is None:
            self.root=X
        else:
            if X.key<parent.key:
                parent.left=X
            else:
                parent.right=X

        X.right=node
        node.left=Y

        self.set_size(node)
        self.set_size(X)

    def left_rotation(self, node, parent):
        X=node.right
        Y=X.left

        if parent is None:
            self.root=X
        else:
            if X.key<parent.key:
                parent.left=X
            else:
                parent.right=X

        X.left=node
        node.right=Y

        self.set_size(node)
        self.set_size(X)

    def get_size(self, X):
        return X.size if X else 0

    def set_size(self, X):
        if X:
            X.size=1+self.get_size(X.left)+self.get_size(X.right)

    def is_black(self, node):
        return (not node) or node.is_black()

    def is_red(self, node):
        return node and node.is_red()

    def is_root(self, node):
        if self.root:
            return node and node.key==self.root.key
        else:
            return node is None

    def swap_color(self, X, Y):
        cx=0 if X.is_black() else 1
        cy=0 if Y.is_black() else 1

        if cy==0:
            X.set_black()
        else:
            X.set_red()

        if cx==0:
            Y.set_black()
        else:
            Y.set_red()

    def get_left(self, X):
        return X.left if X else None

    def get_right(self, X):
        return X.right if X else None

    def next(self, key, equal=True, default=None):
        """ key 以上で最小のキーを探す. """

        if self.root is None:
            return default

        flag=0
        x=default
        node=self.root
        while node:
            if key==node.key and equal:
                return key
            if key<node.key:
                if flag:
                    x=min(x, node.key)
                else:
                    x=node.key
                    flag=1
                node=node.left
            else:
                node=node.right
        return x

    def previous(self, key, equal=True, default=None):
        """ key 以下で最大のキーを探す. """

        if self.root is None:
            return default

        flag=0
        x=default
        node=self.root
        while node:
            if key==node.key and equal:
                return key
            if node.key<key:
                if flag:
                    x=max(x, node.key)
                else:
                    x=node.key
                    flag=1
                node=node.right
            else:
                node=node.left
        return x

    def kth_element(self, k):
        """ k (0-indexed) 番目に小さいキー (k<0 のときは (-k)-1 番目に大きいキー (リストのインデックスと同様))"""

        if k<0:
            k+=len(self)

        assert 0<=k<len(self)

        N=self.root
        while True:
            t=self.get_size(N.left)
            if t==k:
                return N.key
            elif k<t:
                N=N.left
            else:
                k-=t+1
                N=N.right

    def __setitem__(self, key, value):
        self.insert(key, value)

    def __getitem__(self, key):
        node=self.root
        while node:
            if key==node.key:
                return node.value
            if key<node.key:
                node=node.left
            else:
                node=node.right
        raise KeyError(key)

    def get(self, key, default=None):
        node=self.root
        while node:
            if key==node.key:
                return node.value
            if key<node.key:
                node=node.left
            else:
                node=node.right
        return default

    def __contains__(self, key):
        node=self.root
        while node:
            if key==node.key:
                return True
            if key<node.key:
                node=node.left
            else:
                node=node.right
        return False

    def get_min(self, default=None):
        if self.root is None:
            return default

        N=self.root
        while N.left:
            N=N.left
        return N.key

    def get_max(self, default=None):
        if self.root is None:
            return default

        N=self.root
        while N.right:
            N=N.right
        return N.key

    def pop_min(self):
        key=self.get_min()
        if key is not None:
            self.delete(key)
        return key

    def pop_max(self):
        key=self.get_max()
        if key is not None:
            self.delete(key)
        return key
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
    bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
                   ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/python.py", line 96, in bundle
    raise NotImplementedError
NotImplementedError
Back to top page