TIL-070|バイナリ検索ツリー


🌈 バイナリ検索ツリー


  • バイナリ検索(binary search)と接続リスト(linklist)を組み合わせた資料構造.

  • バイナリ検索の効率的な検索能力を維持する利点は、頻繁に資料を入力および削除できることです.
    ✔バイナリナビゲーション
  • ナビゲーション時間複雑度O(logn),
  • 入力
  • 、削除不可
  • ✔接続リスト
  • ナビゲーション時間複雑度O(n)
  • 入力、削除の時間的複雑度O(1)

  • バイナリナビゲーションツリーの4つの条件

  • すべてのノードに一意の鍵があります.
  • 左サブツリーのキーはルートのキーより小さい.
  • 右サブツリーのキーはルートのキーより大きい.
  • 程度のサブツリーもバイナリ検索ツリーです.
  • バイナリプローブツリーを巡回する場合は中位数巡視方式を採用する.(左サブツリー-ノード-右サブツリーの順)
  • 中尉は
  • 上図を巡視し、4、10、12、15、17、19、20、26、28、30、33、35がある.
  • バイナリナビゲーションツリーの実装


    ノードの作成

    class Node:
        def __init__(self, key, value, left, right):
        	self.key = key
        	self.value = value
            self.left = left
            self.right = right
  • ノードを表すノードクラスを生成します.
  • 値は実施に影響しないが、キー値対形式を生成することにより、データ演算を容易に行うことができる.
  • バイナリナビゲーションツリーのコア演算は、検索、挿入、削除です.
  • ツリークラスの作成者

    class BST():
        def __init__(self):
            self.root = None
  • ツリーのルートを生成し、初期Null値を設定します.
  • Search

  • 本を基準にナビゲーションを開始し、検索するキー値とルート値のサイズ関係を理解し、サブノードに従います.
  •     def search(self, key):
            node = self.root # root를 기준으로 탐색
            while True:
                if node is None:
                    return -1
                if key == node.key:
                    return node.value
                elif key < node.key:
                    node = node.left
                else:
                    node = node.right
    2479172バイナリプローブツリーのプローブ演算に必要な計算の複雑さは、ツリーの高さ(ルートノード-リーフ新ノードのリーフ数の最大値に達する)である.𝑂になる.最悪の場合、リーフ先端ノードを探索するためです.このとき逐次比較演算が実行されます.

    Insert

  • を挿入する場合、最も重要なのはバイナリ検索ツリーの条件を維持することです!
  • アルゴリズムは次のとおりです.
  • 本存在するか
  • 本がない場合は作成されます.
  • 本ある場合は、ルートからナビゲートします.
  • (ルートがあると仮定)ルート-現在のノードをノードと呼びます.
  • が挿入された鍵と現在のノードの鍵を比較します.
  • キー=node:挿入に失敗し、
  • を終了
  • key < node :
  • の左側のサブノードがない場合は、その場所にノードを作成し、挿入して終了します.
  • の左側のサブノードがある場合は、現在のノードを左側のサブノードに移動し、再ナビゲートします.
  • key > node:
  • の右側のサブノードがない場合は、その上にノードを作成し、挿入および終了します.
  • の右側のサブノードがある場合は、現在のノードを右側のサブノードに移動し、再ナビゲートします.
  • 手順
  • 3を繰り返します.
  • def add(self,key,value)->bool:
        # 노드 추가하는 내부 함수
        def add_node(node, key,value)->None:
            # 탐색하고 적절한 자리에 삽입
            if key == node.key: #이미 삽입하려는 키가 있으면 false 처리
                return False
            # 삽입하려는 키가 현재 탐색 노드의 키보다 작다면
            elif key < node.key:
                # 그 탐색 노드의 왼쪽 자식이 없다면 바로 그 자리에 삽입
                if node.left is None:
                    node.left = Node(key,value,None,None)
                else:
                # 자식이 있으면 재귀함수 호출로 한번 더 들어감
                    add_node(node.left,key,value)
            # 삽입하려는 키가 현재 탐색 노드의 키보다 크거나 같다면
            else:
                # 그 탐색 노드의 오른쪽 자식이 없다면 바로 그 자리에 삽입
                if node.right is None:
                    node.right = Node(key,value,None,None)
                else:
                # 자식이 있으면 재귀함수 호출로 한번 더 들어감
                    add_node(node.right,key,value)
            return True
        # 루트가 있는 경우
        if self.root is None:
            self.root = Node(key,value,None,None)
            return True
        # 루트가 없는 경우
        else: #리턴값은 내부함수 리턴 값
            return add_node(self.root,key,value)
    

    Delete

  • バイナリ検索ツリー関連アルゴリズムの中で最も複雑です.
  • を挿入するのと同様に,まず探索を行う.削除するには、ツリーで削除するキー値の位置を知る必要があります.
  • を検索すると、削除時に次の3つのケースが発生する可能性があります.
    1)削除するノードがエンドノードである場合(サブノードがない場合)
    2)削除するノードがサブツリーが1つしかない場合(左または右の2つのサブツリーのうちの1つ)
    3)削除するノードに2つのサブツリーがある場合、
  • def remove(self, key)-> bool:
        node = self.root     # 스캔 중인 노드
        parent = None        # 스캔 중인 노드의 부모 노드
        is_left_child = True # node는 parent의 왼쪽 자식 노드인지 오른쪽 자식 노드인지 확인
    
        while True:
          if node is None:
              return False
          if key == node.key:
              break
          else:
              parent = node
              if key < node.key:
                  node = node.left
                  is_left_child = True # 왼쪽 자식 노드로 내려가니까 플래그를 True로 설정
              else:
                  node = node.right
                  is_left_child = False # 오른쪽 자식 노드로 내려가니까 플래그를 True로 설정
        
        # 키를 찾은 뒤에 자식이 없는 노드이면 or 자식이 1개 있는 노드이면
        if node.left is None: # 왼쪽 자식이 없으면
            if node is self.root: #만약 삭제 노드가 root이면, 바로 오른쪽 자식으로 대체한다.
                self.root = node.right
            # 아래의 parent는 탐색 시 찾은 노드의 바로 위 부모가 됨.(탐색 로직에서 그렇게 적용)
            # parent - node - node의 자식의 구도가 있으면 node라는 중간이 빠지기 때문에 parent의 자식과 node의 자식을 연결
    	# (node의 자식이 없으면 자연스레 None이 들어감)
    	elif is_left_child: #왼쪽 자식 노드가 있는 것이니까
                parent.left = node.right # 부모의 왼쪽 참조가 오른쪽 자식을 가리킴
            else: #오른쪽 자식 노드가 있는 것이니까
                parent.right = node.right # 부모의 오른쪽 참조가 오른쪽 자식을 가리킴
        
        elif node.right is None: # 오른쪽 자식이 없으면
            if node is self.root: 
                self.root = node.left #만약 삭제 노드가 root이면, 바로 왼쪽 자식으로 대체한다.
            elif is_left_child:
                parent.left = node.left # 부모의 왼쪽 참조가 왼쪽 자식을 가리킴
            else:
                parent.right = node.left # 부모의 오른쪽 참조가 왼쪽 자식을 가리킴
                
         else:
             parent = node
             left = node.left
             is_left_child = True
             while left.right is not None:
                 parent = left
                 left = left.right
                 is_left_child = False
             
             node.key = left.key
             node.value = left.value
             if is_left_child:
                 parent.left = left.left
             else:
                 parent.right = left.left
         return True      

    すべてのノードを昇順で出力

  • キーの昇順出力
  • を押す.
  • 中位優先探索深さ
  • def dump(self):
        def print_subtree(node):
            if node is not None:
                print(f'{node.key} {node.value}')
                print_subtree(node.left)
                print_subtree(node.right)
       
        print_subtree(self.root)

    🙆‍♂️ 整理する

  • バイナリナビゲーションツリーの概念と演算原理を理解することは難しくないが,実現はまだ困難であり,アルゴリズム問題や実戦ではどのように応用すればよいか分からない.
  • 反復練習を行い、いろいろな問題に触れるのがベストなようです!特に、insertとdeleteの復習を続けます.
  • 📝 Reference

  • https://suyeon96.tistory.com/30
  • https://velog.io/@seanlion/bstimplementation
  • https://mattlee.tistory.com/30
  • https://ratsgo.github.io/data%20structure&algorithm/2017/10/22/bst/
  • Do it! データ構造とともに学習するアルゴリズム入門