가수면

이진 힙 구현 본문

CS/CS

이진 힙 구현

니비앙 2023. 5. 29. 17:08

이진 탐색 트리와 이진 힙 비교

  • 힙은 각 노드의 값이 자식 노드보다 크거나 같음(Max Heap의 경우)
  • 이진 탐색 트리는 왼쪽 자식 노드의 값이 가장 작고, 그 다음 부모 노드, 그 다음 오른쪽 자식 노드 값이 가장 큼
  • 힙은 이진 탐색 트리의 조건인 자식 노드에서 작은 값은 왼쪽, 큰 값은 오른쪽이라는 조건은 없음
    • 힙의 왼쪽 및 오른쪽 자식 노드의 값은 오른쪽이 클 수도 있고, 왼쪽이 클 수도 있음

최대 이진 힙

왼쪽 오른쪽 구분 없이 부모 노드가 자식 노드보다 항상 큰 트리 구조

왼쪽 자식 노드 인덱스 => 2n+1

오른쪽 자식 노드 인덱스 => 2n + 2

부모 인덱스 =>  Math.floor((n - 1) / 2)

insert 매소드

class MaxBinaryHeap {
  constructor() {
    this.values = [];
  }
  insert(element) {
    this.values.push(element);
    this.bubbleUp();
  }
  bubbleUp() {
    // 맨 마지막부터 시작
    let index = this.values.length - 1;
    // insert된 요소
    const element = this.values[index];
    while (index > 0) {
      // insert된 요소의 부모 요소 찾기
      let parentindex = Math.floor((index - 1) / 2);
      let parent = this.values[parentindex];
      if (element <= parent) break;
      // 부모 노드보다 자식 노드가 크면 스위칭
      this.values[parentindex] = element;
      this.values[index] = parent;
      index = parentindex;
    }
  }
}

extractMax 매소드

class MaxBinaryHeap {
  constructor() {
    this.values = [];
  }
  extractMax() {
    // shift하지 않고 max에 end를 덮어씌우는 방식
    const max = this.values[0];
    const end = this.values.pop();
    if (this.values.length > 0) {
      this.values[0] = end;
      // end가 max로 왔으니 아래로 내리는 작업을 해줘야 함
      this.sinkDown();
    }
    return max;
  }
  sinkDown() {
    let index = 0;
    // length-1할 경우 조건문을 수정하면 됨
    const length = this.values.length;
    const element = this.values[0];
    while (true) {
      let leftChildindex = 2 * index + 1;
      let rightChildindex = 2 * index + 2;
      let leftChild, rightChild;
      let swap = null;
      // length - 1이면 <=로 수정
      if (leftChildindex < length) {
        leftChild = this.values[leftChildindex];
        if (leftChild > element) {
          swap = leftChildindex;
        }
      }
      if (rightChildindex < length) {
        rightChild = this.values[rightChildindex];
        if (
          (swap === null && rightChild > element) ||
          (swap !== null && rightChild > leftChild)
        ) {
          swap = rightChildindex;
        }
      }
      if (swap === null) return;
      this.values[index] = this.values[swap];
      this.values[swap] = element;
      index = swap;
    }
  }
}

우선 순위 힙

우선 순위 큐를 구현할 때 보통 힙을 사용하는 것일 뿐이지 우선 순위 큐는 다른 방법으로도 구현할 수 있음

최대 이진 힙에서 부등호(높은 value가 위로 오는 것에서 낮은 우선 순위가 위로 오는 것으로 바꿈)를 변경하고, 비교할 때 value가 아닌 priority(실제 구현했을 때 우선 순위로 비교할 것)를 비교하는 것으로 바꾸기만 하면 됨.

class Node {
    constructor(val, priority) {
        this.val = val;
        this.priority = priority;
    }
}

class PriorityQueue {
    constructor() {
        this.values = [];
    }
    enqueue(val, priority) {
        let newNode = new Node(val, priority);
        this.values.push(newNode);
        this.bubbleUp();
    }
    bubbleUp() {
        let idx = this.values.length - 1;
        const element = this.values[idx];
        while (idx > 0) {
            let parentIdx = Math.floor((idx - 1) / 2);
            let parent = this.values[parentIdx];
            if (element.priority >= parent.priority) return;
            this.values[parentIdx] = element;
            this.values[idx] = parent;
            idx = parentIdx;
        }
    }
    dequeue() {
        const min = this.values[0];
        const end = this.values.pop();
        if (this.values.length > 0) {
            this.values[0] = end;
            this.sinkDown();
        }
        return min;
    }
    sinkDown() {
        let idx = 0;
        const length = this.values.length;
        const element = this.values[0];
        while (true) {
            let leftChildIdx = 2 * idx + 1;
            let rightChildIdx = 2 * idx + 2;
            let leftChild, rightChild;
            let swap = null;

            if (leftChildIdx < length) {
                leftChild = this.values[leftChildIdx];
                if (leftChild.priority < element.priority) {
                    swap = leftChildIdx;
                }
            }
            if (rightChildIdx < length) {
                rightChild = this.values[rightChildIdx];
                if (
                    (swap === null && rightChild.priority < element.priority) ||
                    (swap !== null && rightChild.priority < leftChild.priority)
                ) {
                    swap = rightChildIdx;
                }
            }
            if (swap === null) break;
            this.values[idx] = this.values[swap];
            this.values[swap] = element;
            idx = swap;
        }
    }
}

 

'CS > CS' 카테고리의 다른 글

그래프 구현  (0) 2023.05.30
해시 테이블 구현  (0) 2023.05.29
트리 순회  (0) 2023.05.28
이진 검색 트리 구현  (0) 2023.05.27
스택, 큐 구현  (0) 2023.05.26
Comments