Data Structures and Algorithms (4)


Data Structure and Algorithms (4)


1.ツリー(Tree)


  • ≪構造|Structure|oraolap≫:ツリー・ノードとブランチを使用してデータ構造をループなしに構成

  • 使用:バイナリツリー/ブラウズ(検索)アルゴリズムの実装

  • 用語node , root node , level , parent node , child node , leaf node , sibling/brother node , depth

  • 種類
    1)バイナリツリー:最大2ブランチ
    2)バイナリプローブツリー(BST):バイナリツリーであり、左ノードと右ノードはそれぞれ親ノードより小さいか大きい.

  • 時間の複雑さ
    深さ依存
    O(h) = O(logn)

  • 短所
    1列のツリーでは、不要なナビゲーション時間が発生します.
    この問題を解決するには、ツリーソートアルゴリズムが必要です.

  • delete



  • コード#コード#
    class Node:
        def __init__(self, value):
            self.value = value
            self.left = None
            self.right = None
    ㅤ
    class NodeMgmt:
        def __init__(self, head):
            self.head = head
    ㅤ
        def insert(self, value):
            cur_node = self.head
    ㅤ
            while True:
                if value < cur_node.value:
                    if cur_node.left != None:
                        cur_node = cur_node.left
                    else:
                        cur_node.left = Node(value)
                        break
                else:
                    if cur_node.right != None:
                        cur_node = cur_node.right
                    else:
                        cur_node.right = Node(value)
                        break
    ㅤ
        def search(self, value):
            cur_node = self.head
            while cur_node:
                if cur_node.value == value:
                    return True
                elif value < cur_node.value:
                    cur_node = cur_node.left
                else:
                    cur_node = cur_node.right
            return False
    ㅤ
        def delete(self, value):
            search = False
            cur_node = self.head
      ㅤ      parent = self.head
    ㅤ
            # 해당 노드의 유무확인 및 삭제할 노드 업데이트
        ㅤ    while cur_node:
                if cur_node.value == value:
                    search = True
                    break
                elif value < cur_node.value:
                    parent = cur_node
                    cur_node = cur_node.left
                else:
          ㅤ          parent = cur_node
                    cur_node = cur_node.right
    ㅤ
            if search == False:
                return False
    ㅤ
            # case1 : 삭제할 노드가 leaf 노드인 경우
            if cur_node.left == None and cur_node.right == None:
                if value < parent.value:
                    parent.left = None
                else:
                    parent.right = None
            ㅤ    del cur_node
    ㅤ
            # case2 : 삭제할 노드의 자식노드가 한 개인 경우
            elif cur_node.left != None and cur_node.right == None:
                if value < parent.value:
                    parent.left = cur_node.left
                else:
                    parent.right = cur_node.left
            elif cur_node.left == None and cur_node.right != None:
                if value < parent.value:
                    parent.left = cur_node.right
                else:
                    parent.right = cur_node.right
    ㅤ
            # case3 : 삭제할 노드의 자식노드가 두 개인 경우
            elif cur_node.left != None and cur_node.right != None:
                # case3-1 :
                if value < parent.value:
                    change_node = cur_node.right
                    change_node_parent = cur_node.right
                    while change_node.left != None:
                        change_node_parent = change_node
                        change_node = change_node.left
                    if change_node.right != None:
                        change_node_parent.left = change_node.right
                    else:
                        change_node_parent.left = None
                    parent.left = change_node
                    change_node.right = cur_node.right
                    change_node.left = cur_node.left
                # case3-2 :
               else:
              ㅤ      change_node = cur_node.right
                    change_node_parent = cur_node.right
                    while change_node.left != None:
                        change_node_parent = change_node
                        change_node = change_node.left
                    if change_node.right != None:
                        change_node_parent.left = change_node.right
               ㅤ     else:
                        change_node_parent.left = None
                 ㅤ   parent.right = change_node
                    change_node.right = cur_node.right
                    change_node.left = cur_node.left
    ㅤ
    --------------------------------------------------------------------
    head = Node(1)
    BST = NodeMgmt(head)
    BST.insert(2)
    print(BST.search(2))
    --------------------------------------------------------------------
    import random
    ㅤ
    BST_num = set()
    while len(BST_num) != 100:
       ㅤ BST_num.add(random.randint(0, 999))
    ㅤ
    head = Node(500)
    BST = NodeMgmt(head)
    for num in BST_num:
        if BST.search(num) == False:
            print('search failed')
    ㅤ
    delete_num = set()
    BST_num = list(BST_num)
    while len(delete_num) != 10:
        delete_num.add(BST_num[random.randint(0, 99)])
    ㅤ
    for del_num in delete_num:
        if BST.delete(del_num) == False:
            print('delete failed', del_num)

    2.お尻


  • 構造:Max/Min Heap->ルートディレクトリの最大/最小値

  • 目的:データから最小値と最大値をすばやく取得するバイナリツリー

  • なぜお尻を使うのですか?
    1)配列にデータを入れ、最大値/最小値を検索します.
    *配列にデータを入れて検索し、O(n)/HIPにデータを入れ、O(logn)にデータを入れる
    2)最大値または最小値(優先順位キューなど)の迅速な検索が必要なデータ構造およびアルゴリズムの実装

  • バイナリ探索木VSお尻
    1)共通点:バイナリツリー
    2)違い:バイナリプローブツリー-左右比較サイズ/hip-最大値のみ
  • コード#コード#
    class Heap:
        def __init__(self, data):
            self.heap = list()
            self.heap.append(None)
            self.heap.append(data)
    ㅤㅤ
        def move_up(self, insert_idx):
            if insert_idx <= 1:
                return False
            parent_idx = insert_idx // 2
            if self.heap[insert_idx] > self.heap[parent_idx]:
                return True
            else:
                return False
    ㅤㅤ
        def move_down(self, pop_idx):
            left_child_pop_idx = pop_idx * 2
            right_child_pop_idx = pop_idx * 2 + 1
    ㅤ
            # case1 왼쪽 자식노드 없을때
            if left_child_pop_idx >= len(self.heap):
                return False
    ㅤ
            # case2 오른쪽 자식노드만 없을때
            elif right_child_pop_idx >= len(self.heap):
                if self.heap[pop_idx] < self.heap[left_child_pop_idx]: 
                #아직 max_heapify 이루어지지 않음
                    return True
                else:
                    return False
    ㅤ
            # case3 오른쪽 왼쪽 다 있을때
            else:
                if self.heap[left_child_pop_idx] > self.heap[right_child_pop_idx]:
                    if self.heap[pop_idx] < self.heap[left_child_pop_idx]:
                        return True
                    else:
                        return False
                else:
                    if self.heap[pop_idx] < self.heap[right_child_pop_idx]:
                        return True
                    else:
                        return False
    ㅤ
        def insert(self, data):
            if len(self.heap) == 0:
                self.heap.apppend(None)
                self.heap.append(data)
                return True
    ㅤ
            self.heap.append(data)
    ㅤ
            insert_idx = len(self.heap) - 1
    ㅤ
            while self.move_up(insert_idx):
                parent_idx = insert_idx // 2
                self.heap[insert_idx], self.heap[parent_idx] = \
                    self.heap[parent_idx], self.heap[insert_idx]
                insert_idx = parent_idx
            return True
    ㅤ
        def pop(self):
            if len(self.heap) <= 1:
                return None
    ㅤ
            return_data = self.heap[1]
            self.heap[1] = self.heap[-1]
            del self.heap[-1]
            poped_idx = 1
    ㅤ
            while self.move_down(poped_idx):
                left_child_pop_idx = poped_idx * 2
                right_child_pop_idx = poped_idx * 2 + 1
    ㅤ
                # case2 오른쪽 자식노드만 없을때
                if right_child_pop_idx >= len(self.heap):
                    if self.heap[poped_idx] < self.heap[left_child_pop_idx]:
                        self.heap[poped_idx], self.heap[left_child_pop_idx] = \
      ㅤ                      self.heap[left_child_pop_idx], self.heap[poped_idx]
                        poped_idx = left_child_pop_idx
    ㅤ
                # case3 오른쪽 왼쪽 다 있을때
                else:
                    if self.heap[left_child_pop_idx] > self.heap[right_child_pop_idx]:
                        if self.heap[poped_idx] < self.heap[left_child_pop_idx]:
                            self.heap[poped_idx], self.heap[left_child_pop_idx] = \
                                self.heap[left_child_pop_idx], self.heap[poped_idx]
                            poped_idx = left_child_pop_idx
                    else:
                        if self.heap[poped_idx] < self.heap[right_child_pop_idx]:
                            self.heap[poped_idx], self.heap[right_child_pop_idx] = \
                                self.heap[right_child_pop_idx], self.heap[poped_idx]
                            poped_idx = right_child_pop_idx
    ㅤ
            return return_data
    ㅤ
    --------------------------------------------------------
    heap = Heap(1)
    ㅤ
    for i in range(2,99):
        heap.insert((i))
    ㅤ
    print(heap.heap)
    ㅤ
    for i in range(2,99):
        print(heap.pop())
        print(heap.heap)
    본 게시글은 fastcampus 이준희강사 수업을 듣고 개인적으로 정리한 내용임을 밝힘.