木.


📌木。


これは2 D資料構造です.頂点(node)と幹線(edge)抽象データ配置形式を用いたデータ構造

  • ノード(nodes):通常、A、B、C~と表される値

  • 幹線(エッジ):ノードを接続する線

  • ルートノード(root node):一番上のノード

  • リーフノード:一番下のノード.枝がない

  • 内部ノード(内部ノード):ルートノードでもリーフノードでもない

  • 親(親)ノードと子(子)ノード:ルートに近いノードを親ノード、リーフに近いノードを子ノードと呼びます.各ノードには複数のサブノードがありますが、親ノードは1つしかありません.

  • ノードのレベル(level):ルートノードのlevel:0で、edgeからなる下位レベルまで1増加します.ルートノードからノードへのedge数、すなわちノードのlevel

  • ノードの回数(度数):サブノード(サブツリー)の数.ノードが延びるedgeの数.エンドノード(leaf)の次元数は0です.

  • ツリーの高さ(height)または深さ(depth):ツリーの高さ(height)=最大レベル(level)+1.ルートノードのレベルを1に設定すると、エンドノードのレベルはツリーの高さと同じになります.

  • 部分ツリー(サブツリー;サブツリー):あるノードに対するツリー

  • ≪バイナリ・ツリー|Binary Tree|oraolap≫:すべてのノードの回数が2未満のツリー.再定義可能->(空のツリーまたはルートノード+左サブツリー+右サブツリーの場合)

  • 飽和バイナリツリー(full binary trees):すべてのレベルでノードが埋め込まれたバイナリツリー(高さk、ノード数2 k-1のバイナリツリー)

  • 完全二叉木(complete binary trees):高さkの完全二叉木(レベルk-2のすべてのノードに2つのサブノードの飽和二叉木があり、レベルk-1は左から右に順にノードの二叉木を充填する)

  • バイナリツリーの抽象データ構造

  • 演算の定義
    size()-現在のツリーに含まれるノード数を取得します.
    depth()-現在のツリーの深さ(または高さ)を求めます.
    「ループ」(Transversal)-指定した順序でノードにアクセスして処理します.
  • バイナリツリーの実装-ノード(ノード)

    class Node:
    
        def __init__(self, item): # Node에는 Data와 Left Child, Right Child를 가리키는 정보가 있다.
        				# (양방향 연결 리스트의 prev, next와 비슷)
            self.data = item
            self.left = None
            self.right = None
    
    
        def size(self): # 재귀적으로 구할 수 있다.
        		# 전체 이진 트리 size() : 왼쪽 서브트리 size() + 오른쪽 서브트리 size() +  1(자기 자신)
            l = self.left.size() if self.left else 0
            r = self.right.size() if self.right else 0
            return l + r + 1
    
    
        def depth(self): # 재귀적으로 구할 수 있다.
        	# 전체 이진 트리 depth() : 왼쪽 서브트리 depth()와 오른쪽 서브트리 depth()중 더 큰 것 +  1(자기 자신)
            l = self.left.depth() if self.left else 0
            r = self.right.depth() if self.right else 0
            # if l > r:
            #     return l + 1
            # elif r > l:
            #     return r + 1
            return max(l, r) + 1
    
        def inorder(self): # 중위 순회 - 1. 왼쪽 서브트리 2. 자기자신 3. 오른쪽 서브트리
            traversal = []
            if self.left:
                traversal += self.left.inorder()
            traversal.append(self.data)
            if self.right:
                traversal += self.right.inorder()
            return traversal
    
    
        def preorder(self): # 전위 순회 - 1. 자기자신 2. 왼쪽 서브트리 3. 오른쪽 서브트리
            traversal = []
            traversal.append(self.data)
            if self.left:
                traversal += self.left.preorder()
            if self.right:
                traversal += self.right.preorder()
            return traversal
    
        def postorder(self): # 후위 순회 - 1. 왼쪽 서브트리 2. 오른쪽 서브트리 3. 자기자신
            traversal = []
            if self.left:
                traversal += self.left.postorder()
            if self.right:
                traversal += self.right.postorder()
            traversal.append(self.data)
            return traversal
    
    
    class BinaryTree:
    
        def __init__(self, r): # 루트 노드만 알고 있으면 그 자식 노드들의 edge로 나머지 노드들을 가르키고 있다.
            self.root = r
    
        def size(self):
            if self.root:
                return self.root.size()
            else: # 빈 트리일 경우
                return 0
    
    
        def depth(self):
            if self.root:
                return self.root.depth()
            else:
                return 0
    
        def inorder(self):
            if self.root:
                return self.root.inorder()
            else:
                return []
    
        def preorder(self):
            if self.root:
                return self.root.preorder()
            else:
                return []
    
        def postorder(self):
            if self.root:
                return self.root.postorder()
            else:
                return []
                
                
        def bft(self): # 넓이 우선 순회
            traversal = []
            q = ArrayQueue()
    
            if self.root == None:
                return traversal
            else:
                q.enqueue(self.root)
    
                while not q.isEmpty():
                    node = q.dequeue()
                    traversal.append(node.data)
    
                    if node.left and node.right:
                        q.enqueue(node.left)
                        q.enqueue(node.right)
                        continue
    
                    elif node.left:
                        q.enqueue(node.left)
                    elif node.right:
                        q.enqueue(node.right)
                return traversal        
    
    def solution(x):
        return 0

    トラバースツリー(Transversal-DFT,BFT)


    深度優先順位(depth firstループ)


  • 中位遍歴(in-order travelasl):左側のサブツリーを遍歴し、ノードx(自己)にアクセスし、右側のサブツリーを遍歴する


  • 前列ループ(pre-orderループ):ノードxにアクセスし、左側のサブツリーをループし、最後に右側のサブツリーをループします.


  • 後方ループ(post-orderループ):左サブツリーループ、右サブツリーループ、最後にノードxにアクセス

  • 幅優先ループ

  • 原則
  • より下位レベルのノード
  • に優先的にアクセスする.
  • 等級のノード間で、
    親ノードのアクセス順にアクセス
    左サブノードにアクセスする前に右サブノードにアクセス

  • 1つのノードにアクセスする場合は、後でアクセスするノードを順番に記録します.
    ->キューを使用します.再帰メソッドは使用しません.

    任意の幅優先順位アルゴリズムの実現

  • (初期化)遍歴<-空リスト、q<-空キュー
  • 空のツリー
  • でない場合、ルートノードはq(enqueue)
  • に追加される.
  • qは空ではありません
    3-1. q要素を抽出してnodeという変数にする
    3-2. アクセスノード(ノードのデータを追加)
    3-3. ノードの左、右サブノード(ある場合)をqに
  • 追加する
  • qが空のキューの場合、すべてのノードへのアクセスが完了します.ループバック
  • バイナリ検索ツリー


    すべてのノードについて、
    左側のサブツリーのすべてのデータは、現在のノードの値よりも小さくなります.
    右側のサブツリーのすべてのデータは、現在のノードの値よりも大きくなります.
    性格を満たす李金樹!重複するデータ要素の値がないと仮定します.
    アレイナビゲーションを使用するよりも、要素の追加、削除が容易ですが、スペースが大きくなります.

    バイナリナビゲーションツリーの抽象データ構造


    データ表示-各ノードは(key,value)ペアです.
  • 演算の定義
    Insert():指定したデータ要素をツリーに追加
    remove():ツリーから特定の要素を削除する
    lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()lookup()
    inorder():キー順にデータ要素をリストする
    min()、max():最小キーと最大キーを持つ要素
  • にナビゲートします.
    min():左だけ探して、もっと値がなければ、自分に戻ります.最小値(最大()と対称)
    lookup():パラメータを入力-検索するターゲットキー.戻る-見つかったノード、親ノード.それぞれが存在しない場合はNoneとして指定します

    バイナリ・ツリーから要素を削除

  • キーを使用してノードを検索します.ノード(検索(キー)、親ノード
    キーにノードがない場合は削除する必要はありません
    見つかったノードの親ノードも知っているはずです.
  • で見つかったノードを消去し、ツリーの構造を整理してバイナリ検索ツリーの性質を満たす.
  • class Node:
    
        def __init__(self, key, data):
            self.key = key
            self.data = data
            self.left = None
            self.right = None
    
    
        def insert(self, key, data):
            if key < self.key:
                if self.left:
                    self.left.insert(key, data)
                else: # 왼쪽에 값이 더이상 없으면 말단에 온 것이니 값 추가
                    self.left = Node(key, data) 
            elif key > self.key:
                if self.right:
                    self.right.insert(key, data)
                else:
                    self.right = Node(key, data)
            else:
                raise KeyError('Key %s already exists.' % key)
    
    
        def lookup(self, key, parent=None):
            if key < self.key:
                if self.left:
                    return self.left.lookup(key, self)
                else:
                    return None, None
            elif key > self.key:
                if self.right:
                    return self.right.lookup(key, self)
                else:
                    return None, None
            else:
                return self, parent
    
    
        def inorder(self):
            traversal = []
            if self.left:
                traversal += self.left.inorder()
            traversal.append(self)
            if self.right:
                traversal += self.right.inorder()
            return traversal
    
    
        def countChildren(self): # 자식 노드 세기
            count = 0
            if self.left:
                count += 1
            if self.right:
                count += 1
            return count
    
    
    class BinSearchTree:
    
        def __init__(self):
            self.root = None
    
    
        def insert(self, key, data):
            if self.root:
                self.root.insert(key, data)
            else:
                self.root = Node(key, data)
    
    
        def lookup(self, key):
            if self.root:
                return self.root.lookup(key)
            else:
                return None, None
    
    
        def remove(self, key):
            node, parent = self.lookup(key)
            if node:
                nChildren = node.countChildren()
                # The simplest case of no children
                if nChildren == 0:
                    if parent:
                        if parent.left == node:
                            parent.left = None
                        elif parent.right == node:
                            parent.right = None
                            
                    # 만약 parent 가 있으면
                    # node 가 왼쪽 자식인지 오른쪽 자식인지 판단하여
                    # parent.left 또는 parent.right 를 None 으로 하여
                    # leaf node 였던 자식을 트리에서 끊어내어 없앤다.
                    # 만약 parent 가 없으면 (node 는 root 인 경우)
                    # self.root 를 None 으로 하여 빈 트리로 만듦
                    
                    else:
                        self.root = None
                # When the node has only one child
                elif nChildren == 1:
                    # 하나 있는 자식이 왼쪽인지 오른쪽인지를 판단하여
                    # 그 자식을 어떤 변수가 가리키도록 합니다.
                    if node.left:
                        s = node.left
                    else:
                        s = node.right
                    # 만약 parent 가 있으면
                    # node 가 왼쪽 자식인지 오른쪽 자식인지 판단하여
                    # 위에서 가리킨 자식을 대신 node 의 자리에 넣습니다.
                    if parent:
                        if parent.left == node:
                            parent.left = s
                        elif parent.right == node:
                            parent.right = s
                    # 만약 parent 가 없으면 (node 는 root 인 경우)
                    # self.root 에 위에서 가리킨 자식을 대신 넣습니다.
                    else:
                        self.root = s
                        
                # When the node has both left and right children
                else:
                    parent = node
                    successor = node.right
                    
                    # parent 는 node 를 가리키고 있고,
                    # successor 는 node 의 오른쪽 자식을 가리키고 있으므로
                    # successor 로부터 왼쪽 자식의 링크를 반복하여 따라감으로써
                    # 순환문이 종료할 때 successor 는 바로 다음 키를 가진 노드를,
                    # 그리고 parent 는 그 노드의 부모 노드를 가리키도록 찾아냄
                    
                    while successor.left:
                        parent = successor
                        successor = successor.left
                        
                    # 삭제하려는 노드인 node 에 successor 의 key 와 data 를 대입
                    node.key = successor.key
                    node.data = successor.data
                    
                    # successor 가 parent 의 왼쪽 자식인지 오른쪽 자식인지를 판단하여
                    # 그에 따라 parent.left 또는 parent.right 를
                    # successor 가 가지고 있던 (없을 수도 있지만) 자식을 가리키도록 함
                    
                    if successor == parent.left:
                    # if successor.left or successor.right:
                    # 위의 while문에서 succesor의 왼쪽 자식이 없다는 것이 보장되었으니 필요 없는 코드
                        if successor.right:
                            parent.left = successor.right
                        else:
                            parent.left = None
                    elif successor == parent.right:
                        if successor.right:
                            parent.right = successor.right
                        else:
                            parent.right = None
                        
                return True
    
            else:
                return False
    
    
        def inorder(self):
            if self.root:
                return self.root.inorder()
            else:
                return []
    
    
    def solution(x):
        return 0

    バイナリナビゲーションツリーの効率が悪い


    ->自分の役割を果たすには、高さが似ていて、左右対称です.片側に傾けると、時間が長くなり、線形配列に似ています.

    パフォーマンスの向上したバイナリ・ナビゲーション・ツリー


    ->高度なバランスを保ち、O(longn)のナビゲーションの複雑さを確保します.挿入、削除操作がより複雑(AVL tree、Red-black treeリファレンスバイナリナビゲーションツリーには、構造を保持する制約があります)