본문 바로가기
2022-2/자료구조

5장 - Heaps

by 철없는민물장어 2022. 11. 4.
728x90
반응형
Heap
  • 최대 트리(max tree): 트리의 모든 노드에 대해 부모 데이터 값>자식 데이터 값
  • 최대 힙(max heap): 최대 트리이면서 완전 이진 트리

 

  • 최소 트리(min tree): 트리의 모든 노드에 대해 부모 데이터 값<자식 데이터 값
  • 최소 힙(min heap): 최소 트리이면서 완전 이진 트리

 

우선 순위 큐(Priority Queues)

선입 선출이 아니라 우선순위의 순서대로 삭제되는 큐

 

우선순위 큐의 다양한 구현 방법들과 삽입,삭제시 시간복잡도

구현 방법 삽입 삭제
순서 없는 배열 O(1) O(n)
순서 없는 연결 리스트 O(1) O(n)
정렬된 배열 O(n) O(1)
정렬된 연결 리스트 O(n) O(1)
최대 힙 O(log2n) O(log2n)

(숫자2는 로그의 밑임)


Max Heap 구현하기

Max Heap은 배열로 구현하는 것이 효과적이다.

완전 이진 트리이므로 인덱스를 사용하여 접근하는 것이 용이하기 때문임.

 

자료구조 선언

#define MAX_ELEMENTS 200
#define HEAP_FULL(n) (n==MAX_ELEMENTS-1)
#define HEAP_EMPTY(n) (!n)

typedef struct {
	int key;
}element;
element heap[MAX_ELEMENTS];
int n = 0;

 

insert
void insert_max_heap(element item, int* n) {
	int i;
	if (HEAP_FULL(*n)) {
		fprintf(stderr, "THE HEAP IS FULL. \n");
		exit(1);
	}
	i = ++(*n);
	while ((i != 1) && (item.key > heap[i / 2].key)) {
		heap[i] = heap[i / 2];
	}
	heap[i] = item;
	
}

배열의 끝에 새로운 노드를 추가한다.==> ++(*n)

추가된 위치부터 parent노드를 한 단계씩 조사한다. 부모보다 값이 크다면 자리를 바꾸고, 부모보다 값이 작아지거나 root가 될 때까지 반복한다.

delete
element delete_max_heap(int* n) {
	int parent, child;
	element item, temp;

	if (HEAP_EMPTY(*n)) {
		fprintf(stderr, "THE HEAP IS EMPTY.\n");
		exit(1);
	}
	item = heap[1];//현재 루트의 값을 옮겨놓음
	temp = heap[(*n)--]; //제일 마지막 원소를 비교 대상으로 temp에 넣음
	parent = 1; child = 2;
	while (child <= *n) {
		if ((child < *n) && (heap[child].key < heap[child + 1].key))//두 개의 자식 중 큰 쪽과 비교
			child++;
		if (temp.key >= heap[child].key) break;//자식보다 값이 클 때 반복종료
		heap[parent] = heap[child];
		parent = child;
		child *= 2;

	}
	heap[parent] = temp;
	return item;

}

루트노드의 값을 빼내고, 제일 마지막 노드를 넣는다. 

자식보다 값이 클 때까지 한 칸씩 내린다.


이진 검색 트리

Heap에서 특정 데이터를 갖는 노드를 검색할 때, 시간복잡도는 O(n)이 된다.

이진 검색 트리는 트리 내에서 특정 데이터를 효율적으로 찾도록 한다.

  • 모든 노드는 유일한 키 값을 가진다.
  • 왼쪽 서브트리에 저장된 키 값<Root node 키 값 < 오른쪽 서브트리에 저장된 키 값
  • 왼쪽/오른쪽 서브트리도 이진 검색 트리이다.

 

이진 검색 트리에서 검색 연산
  • if (key==root->key) return (root)
  • if (key < root->key) search(root->left_child)
  • if (key > root->key) search(root->right_child)

이진 검색 트리는 완전이진트리가 아니므로 배열이 아닌 연결리스트로 구현하게 된다.

 

#include <stdio.h>
#include <stdlib.h>

struct node {
	int data;
	struct node* left_child;
	struct node* right_child;
};

노드는 left_child,right_child, data로 구성됨

 

recursive search
struct node* search(struct node* root, int key) {
	//key를 포함하고 있는 노드의 포인터를 return. 없는경우 NULL리턴
	if (!root) return NULL;
	if (key == root->data) return root;
	if (key < root->data)
		return search(root->left_child, key);
	return search(root->right_child, key);
}
iterative search
struct node* iterSearch(struct node* tree, int key) {
	while (tree != NULL) {
		if (key == tree->data) return tree;
		if (key < tree->data)
			tree = tree->left_child;
		else
			tree = tree->right_child;

	}
	return NULL;
}

재귀가 아닌 반복문으로 구현도 가능하다.

 

 

이진 검색 트리에 노드 추가하기

검색 알고리즘을 수행 후, 알고리즘이 종료되는 곳에 새로운 노드를 추가하면 된다.

struct node* modified_search(struct node* root, int key) {
	for (struct node* ptr = root; ptr != NULL;) {
		if (ptr->data == key)//기존에 존재하는 키를 입력하면 NULL리턴
			return NULL;
		if (key < ptr->data) {
			if (ptr->left_child == NULL) return ptr;//새 노드를 넣을 자리
			else ptr = ptr->left_child;//한칸더 내려감
		}
		else {
			if (ptr->right_child == NULL) return ptr;
			else ptr = ptr->right_child;
		}
	}
	return NULL;//root가 NULL인 경우
}

void insert_node(struct node** root, int num) {
	struct node* ptr, *parent = modified_search(*root, num);

	if (parent || !(*root)) {
		ptr = (struct node*)malloc(sizeof(struct node));//num을 키값으로하는 노드생성
		ptr->data = num;
		ptr->left_child = ptr->right_child = NULL;

		if (*root)//root!=NULL일 때, 부모노드와 새로 생성한 노드를 연결시킴
			if (num < parent->data)
				parent->left_child = ptr;
			else
				parent->right_child = ptr;
		else *root = ptr; //트리가 empty인 경우 root로 등록
	}
}

modify_search(struct node* root, int key)는 새 노드가 들어갈 위치를 찾아, 그 위치의 부모노드를 반환하는 함수이다.

insert_node(struct node** root,int num)는 num값을 키값으로 갖는 새 노드를 만들어 적절한 위치에 해당노드를 삽입한다.

 

이진 검색 트리에서 노드 삭제

리프노드인 경우: 간단히 해당노드 삭제 

child가 하나인 노드: 삭제된 자리에 child node를 위치

두 개의 children을 갖는 노드: 왼쪽 서브트리에서 가장 큰 노드나, 오른쪽 서브트리에서 가장 작은 노드를 삭제된 자리에 위치시킴

 

이진검색트리를 inorder traversal하면 크기순으로 찍힌다.

이진검색트리는 O(log2n) 시간복잡도임

728x90
반응형

'2022-2 > 자료구조' 카테고리의 다른 글

5장 - Forests/Find-Union  (0) 2022.11.14
5장 - Threaded Binary Tree/Selection Tree  (0) 2022.11.07
5장 TREES  (0) 2022.10.30
동치 알고리즘  (0) 2022.10.20
4장 - 이중 연결 리스트  (0) 2022.10.20

댓글