힙

2023. 5. 14. 18:11·다양한 글들/자료구조와 알고리즘

8.3 힙

8.3.1 힙의 개념

  • 여러 개의 값들 중에서 가장 큰 값이나 가장 작은 값을 빠르게 찾아내도록 만들어진 자료구조
  • 부모 노드의 키 값이 자식 노드의 키 값보다 항상 큰(작은) 이진 트리를 말함
  • 힙 트리는 중복된 값을 허용함에 유리(이진 탐색 트리는 중복된 값을 허용하지 않음)
  • 힙 안의 데이터들은 느슨한 정렬 상태를 유지 -> 큰 값이 상위 레벨에 있고 작은 값이 하위 레벨에 있다는 정도
  • 힙의 목적: 삭제 연산이 수행될 때마다 가장 큰 값을 찾아 내기만 하면 되는 것이므로(가장 큰 값은 루트노드에 있음) 전체를 정렬할 필요는 없음
  • 힙의 종료: 최대 힙(max heap), 최소 힙(min heap)
  1. 최대 힙(max heap)
    부모 노드의 키 값이 자식 노드의 키 값보다 크거나 같은 완전 이진 트리: key(부모 노드) >= key(자식 노드)
  2. 최소 힙(min heap)
    부모 노드의 키 값이 자식 노드의 키 값보다 작거나 같은 완전 이진 트리: key(부모 노드) <= key(자식 노드)

8.3.2 힙의 구현

  • 힙은 완전 이진 트리이기 때문에 각각의 노드에 차례대로 번호를 부여할 수 있음
  • 이 번호를 배열의 인덱스로 생각하면 배열에 힙의 노드들을 저장할 수 있음 -> 힙을 저장하는 표준적인 자료구조는 배열임
  • 배열을 이용하여 힙을 저장하면 완전 이진 트리에서처럼 자식 노드와 부모 노드를 쉽게 알 수 있음
- 왼쪽 자식의 인덱스 = (부모 인덱스)*2
- 오른쪽 자식의 인덱스 = (부모 인덱스)*2+1

- 부모 인덱스 = (자식의 인덱스)/2
  • 힙 구조체
#define MAX_ELEMENT 200
typedef struct{
	int key;
}element;

typedef struct{
	element heap[MAX_ELEMENT];
    int heap_size;
}HeapType;

// 힙 생성
HeapType heap1;

8.3.3 삽입 연산

  1. 새로운 노드를 힙의 마지막 노드에 이어서 삽입
  2. 그 후 힙 트리의 성질이 만족되지 않은 경우, 힙 성질을 만족할 때까지 새로운 노드와 부모 노드를 교환

<알고리즘 8.3.3.1> 힙 트리에서의 삽입 알고리즘(자연어 버전)

insert(A, key)
1. 힙의 끝에 새로운 노드를 삽입
2. 삽입된 노드와 그 부모 노드의 키 값을 비교, 삽입된 노드의 키 값이 부모 노드의 키 값보다 크면 두 노드의 위치를 바꿈
3. 삽입된 노드의 키 값이 자신의 부모 노드 키 값보다 작아질 때까지 단계 2를 반복

<알고리즘 8.3.3.2> 힙 트리에서의 삽입 알고리즘(유사코드 버전)

insert_max_heap(A, key)

heap_size <- heap_size + 1;
i <- heap_size;
A[i] <- key;

while i != 1 and A[i] > A[PARENT(i)] do
	A[i] <- A[PARENT(i)];
    i <- PARENT(i);
    
1. 힙 크기를 하나 증가
2. 증가된 힙 크기 위치에 새로운 노드를 삽입
3. i가 루트 노드가 아니고 i번째 노드가 i의 부모 노드보다 크면
4. i번째 노드와 부모 노드와 교환
5. 한 레벨 위로 올라감(승진)

<프로그램 8.3.3.1> 힙 트리에서의 삽입 함수

// 현재 요소의 개수가 heap_size인 힙 h에 item을 삽입
// 삽입 함수
void insert_max_heap(HeapType *h, element item){
	int i;
    i = ++(h->heap_size);
    
    // 트리를 거슬러 올라가면서 부모 노드와 비교하는 과정
    // 교환이 아니고 부모노드만을 끌어 내린 다음 
    while((i != 1) && (item.key > h->heap[i/2].key){
    	h->heap[i] = h->heap[i/2];
        i/=2;
    }
    // 삽입될 위치가 확실해지면 새로운 노드는 그 위치로 이동 -> 이동 횟수를 줄일 수 있음
    h->heap[i] = item; // 새로운 노드 삽입
}

8.3.4 삭제 연산

  • 최대 힙에서 삭제는 최대값을 가진 요소를 삭제하는 것
  • 루트 노드가 삭제 되고, 삭제 후 힙 재구성이 필요함
    힙의 재구성: 힙의 성질을 만족하기 위해 위, 아래 노드를 교환하는 것

<알고리즘 8.3.4.1> 힙 트리에서의 삭제 알고리즘

delete_max_heap(A)

item <- A[i]; // 루트 노드 값을 반환을 위해 item 변수로 옮김
A[i] <- A[heap_size]; // 말단 노드를 루트 노드로 옮김
heap_size <- heap_size-1; // 힙 크기를 하나 줄임
i <- 2; // 루트의 왼쪽 자식부터 비교 시작
while i <= heap_size do // i가 힙 트리의 크기보다 작으면(즉, 힙 트리를 벗어나지 않았으면)
	if i < heap_size and A[i+1] > A[i] // 오른쪽 자식이 더 크면
    	// 두 개의 자식 노드 중 크 값의 인덱스를 largest로 옮김
    	then largest <- i+1;
        else largest <- i;
    // largest의 부모 노드가 largest보다 크면 종료
    if A[PARENT(largest)] > A[largesr]
    	then break;
    // 그렇지 않다면 largest와 largest 부모 노드를 교환
    A[PARENT(largest)] <- A[largest];
    i <- Child(largest); // 한 레벨 밑으로 내려감
    
return item; // 최댓값을 반환

<프로그램 8.3.4.1> 힙 트리에서의 삭제 함수

// 삭제 함수
element delete_max_heap(HeapType *h){
	int parent, child;
    element item, tmp;
    
    item = h->heap[1];
    tmp = h->heap[(h->heap_size)--]; // 루트로 갈 힙 트리의 마지막 노드
    parent = 1;
    child = 2;
    
    while(child <= h->heap_size){
    	// 현재 노드의 자식 노드 중 더 큰 자식 노드를 찾는다.
        if( (child < h->heap_size) && (h->heap[child].key < h->heap[child+1].key){
        	child++;
        }
        if(tmp.key >= h->heap[child]) break;
        // 한 단계 아래로 이동
        h->heap[parent] = h->heap[child];
        parent = child; // 결과적으로 마지막 노드가 있어야 하는 위치가 됨
        child *=2;
    }
    h->heap[parent] = tmp;
    
    return item;
}

전체 프로그램

<프로그램 8.3.1> 전체 프로그램

#include <stdio.h>
#define MAX_ELEMENT 200

typedef struct{
    int key;
} element;

typedef struct {
    element heap[MAX_ELEMENT];
    int heap_size;
} HeapType;

// 초기화 함수
void init(HeapType *h){
    h->heap_size = 0;
}

void insert_max_heap(HeapType*h,element item){
    // 1. 힙 트리의 마지막 노드로 삽입
    // 2. 힙의 재구성: 최대 힙의 성질을 만족하는 트리를 만들어야 함(부모 노드 > 자식 노드)
    int i = ++(h->heap_size);
    while((i!=1)&&(h->heap[i/2].key < item.key)){
        h->heap[i] = h->heap[i / 2];
        i /= 2;
    }
    h->heap[i] = item;
}

element delete_max_heap(HeapType*h){
    // 1. 힙 트리의 루트 노드를 삭제
    // 2. 힙 트리의 마지막 노드를 루트 노드 위치로 옮김
    // 3. 힙의 재구성: 최대 힙의 성질을 만족하는 트리를 만들어야 함(부모 노드 > 자식 노드)
    element item = h->heap[1];
    element tmp = h->heap[(h->heap_size)--];
    int parent = 1, child = 2;
    while ((child <= h->heap_size)){
        if((child < h->heap_size) && (h->heap[child].key < h->heap[child+1].key )){
            child++;
        }
        if(h->heap[child].key <= tmp.key){
            break;
        }
        h->heap[parent] = h ->heap[child];
        parent = child;
        child *= 2;
    }
    h->heap[parent] = tmp;
    return item;
}

// 주 함수
int main(){
    element e1 = { 10 }, e2 = { 5 }, e3 = { 30 };
    element e4, e5, e6;
    HeapType heap; // 힙 생성
    init(&heap); // 초기화
    // 삽입
    insert_max_heap(&heap, e1);
    insert_max_heap(&heap, e2);
    insert_max_heap(&heap, e3);

    // 삭제
    e4 = delete_max_heap(&heap);
    printf("< %d > ", e4.key);
    e5 = delete_max_heap(&heap);
    printf("< %d > ", e5.key);
    e6 = delete_max_heap(&heap);
    printf("< %d >\n", e6.key);
}

8.3.5 힙의 복잡도 분석

삽입 연산 - 새로운 요소는 힙 트리를 타고 올라가면서 부모 노드들과 교환하게 됨
최악의 경우: 루트 까지 올라가야 하므로 거의 트리의 높이에 해당하는 비교 연산 및 이동 연산이 필요함 -> 시간복잡도 O(logn)
삭제 연산 - 마지막 노드를 루트로 가져온 후에 자식 노드들과 비교하여 교환해야 함
최악의 경우: 가장 아래 레벨까지 내려가야 하므로 트리의 높이만큼의 시간이 걸림 -> 시간복잡도 O(logn)

Quiz

  1. 최대 힙이 아래와 같이 배열에 저장되어 있을 때, 11이 삽입된 후의 힙 트리?

인덱스123456789

데이터 12 10 8 4 6 2 5 3  

-> 11 삽입 후

인덱스123456789

데이터 12 11 8 10 6 2 5 3 4
  1. 위의 최대 힙에서 우선순위가 가장 높은 요소를 삭제했을 경우에 재구성된 힙 트리?

인덱스123456789

데이터 12 10 8 4 6 2 5 3  

-> 12 삭제 후

인덱스123456789

데이터 10 6 8 4 3 2 5    

8.4 힙의 응용

힙 정렬

시간복잡도 O(nlogn)
1. 정렬해야 할 n개의 요소들로 최대 힙을 초기화
2. 한 번에 하나씩 요소를 힙에서 꺼내서 배열의 뒤부터 저장 -> 삭제되는 요소들은 값이 감소되는 숨서로 정렬되게 됨

<프로그램 8.4.1> 힙 정렬 프로그램

// 우선순위 큐인 힙을 이용한 정렬
void heap_sort(element e[], int n){
	HeapType *h;
    init(&h);
    for(int i=0;i<n;i++){
    	insert_max_heap(&h, e[i]);
    }
    
    for(int i =(n-1);i>=0;i--){
    	e[i] = delete_max_heap(&h);
    }
}

이산 이벤트 시뮬레이션

컴퓨터 시뮬레이션: 실재하거나 이론적으로 존재하는 물리적인 시스템의 모델을 디자인하고 그 모델을 디지털 컴퓨터에서 실행하고 그 실형 결과를 분석하는 학문
시뮬레이션의 종류(시간에 따라 달라짐): 연속 시간(continuous time) 시뮬레이션, 이산 시간(discrete time) 시뮬레이션, 이산 이벤트(discrete event) 시뮬레이션
이산 이벤트 시뮬레이션: 모든 시간의 진행은 이벤트의 발생에 의해 이루어짐. 즉, 이벤트가 발생하면 시간이 진행되는 것임
ex) 아이스크림 가게 시뮬레이션: 아이스크림 가게에 손님들이 들어오고 나가는 과정을 시뮬레이션하는 것

  • 손님이 도착하는 이벤트(ARRIVAL)
  1. 손님의 숫자와 현재 남아 있는 의자를 비교하여 남아 있는 의자가 저 많으면 손님을 받음
  2. 남아 있는 의자의 수는 손님의 숫자만큼 줄어듬
  3. 만약 의자가 더 적으면 손님은 주문하지 않고 나가게 됨
  • 손님이 주문하는 이벤트(ORDER)
  1. 손님의 숫자대로 주문을 받게 됨
  2. 잠시후 손님들이 떠나는 이벤트를 발생시킴
  • 손님이 가게를 떠나는 이벤트(LEAVE)
  1. 떠나는 손님들의 숫자만큼 남아 있는 의자들의 개수를 증가시키면 됨
    -> 손님들의 숫자, 주문을 하는데 걸리는 시간, 가게에 머물러 있는 시간 등은 모두 랜덤하게 처리
    -> 먼저 발생한 이벤트를 가장 먼저 처리해야 되므로 여기서 우선순위 큐는 최소 힙을 사용해야 함

<프로그램 8.4.2> 아이스크림 가게 시뮬레이션 프로그램(최소 힙 사용)

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

#define TRUE 1
#define FALSE 0

#define ARRIVAL 1
#define ORDER 2
#define LEAVE 3

int free_seats = 10;
double profit = 0.0;

#define MAX_ELEMENT 100

typedef struct{
    int type; // 이벤트의 종류
    int key; // 이벤트가 일어난 시각
    int number; // 고객의 숫자
} element;

typedef struct{
    element heap[MAX_ELEMENT];
    int heap_size;
} HeapType;

// 초기화 함수
void init(HeapType *h){
    h->heap_size = 0;
}

int is_empty(HeapType *h){
    if(h->heap_size == 0){
        return TRUE;
    }else{
        return FALSE;
    }
}

// 삽입 함수
void insert_min_heap(HeapType *h, element item){
    int i = ++(h->heap_size);

    // 트리를 거슬러 올라가면서 부모 노드와 비교하는 과정
    while((i!=1) && (h->heap[i/2].key > item.key)){
        h->heap[i] = h->heap[i / 2];
        i /= 2;
    }
    h->heap[i] = item; // 새로운 노드 삽입
}

// 삭제 함수
element delete_min_heap(HeapType *h){
    element item = h->heap[1];
    element tmp = h->heap[(h->heap_size)--];
    int parent = 1, child = 2;

    while(child <= h->heap_size){
        // 현재 노드의 자식 노드 중 더 작은 자식 노드를 찾음
        if((child < h->heap_size) && (h->heap[child].key > h->heap[child+1].key)){
            child++;
        }
        if(h->heap[child].key >= tmp.key){
            break;
        }
        // 한단계 아래로 이동
        h->heap[parent] = h->heap[child];
        parent = child;
        child *= 2;
    }
    h->heap[parent] = tmp;
    return item;
}

// 0에서 n 사이의 정수 난수 생성 함수
int random(int n){
    return (int)(n * rand() / (double)RAND_MAX);
}

// 자리가 가능하면 빈자리 수를 사람 수만큼 감소시킴
int is_seat_available(int number){
    printf("Arrival %d people\n", number);
    if(free_seats >= number){
        free_seats -= number;
        return TRUE;
    }else{
        printf("Leave because there are no seats\n");
        return FALSE;
    }
}

// 주문을 받으면 순익을 나타내는 변수를 증가시팀
void order(int scoops){
    printf("Order %d ice cream\n", scoops);
    profit += 0.35 * scoops;
}

// 고객이 떠나면 빈자리 수를 증가시킴
void leave(int number){
    printf("Leave %d people\n", number);
    free_seats += number;
}

// 이벤트를 처리함
void process_event(HeapType *h, element e){

    element new_evenet;
    printf("Current time=%d\n", e.key);
    switch(e.type){
        case ARRIVAL:
            // 자리가 가능하다면 주문 이벤트를 만듦
            if(is_seat_available(e.number)){
                new_evenet.type = ORDER;
                new_evenet.key = e.key + 1 + random(4); // 랜덤 시간 뒤에 주문 
                new_evenet.number = e.number;
                insert_min_heap(h, new_evenet);
            }
            break;
        case ORDER:
            // 사람 수만큼 주문을 받음
            for (int i = 0; i < e.number;i++){
                order(1 + random(3));
            }
            // 매장을 떠나는 이벤트를 생성
            new_evenet.type = LEAVE;
            new_evenet.key = e.key + 1 + random(10);
            new_evenet.number = e.number;
            insert_min_heap(h, new_evenet);
            break;
        case LEAVE:
            // 고객이 떠나면 빈자리 수를 증가
            leave(e.number);
            break;
    }
}

int main(){
    element event;
    HeapType heap;
    unsigned int t = 0;

    init(&heap);

    // 처음에 몇 개의 초기 이벤트를 생성
    while(t<5){
        t += random(6);
        event.type = ARRIVAL;
        event.key = t;
        event.number = 1 + random(4);
        insert_min_heap(&heap, event);
    }

    //시뮬레이션 수행
    while(!is_empty(&heap)){
        event = delete_min_heap(&heap);
        process_event(&heap, event);
    }

    printf("Total profit is %f\n", profit);
    return 0;
}

허프만 코드

  • 이진 트리는 각 글자의 빈도가 알려져 있는 메시지의 내용을 압축하는데 사용될 수 있음 -> 허프만 코딩 트리
  • 빈도수(frequencies): 각 숫자들은 영문 텍스트에서 해당 글자가 나타나는 횟수
  • 빈도수를 이용해서 데이터를 압축할 때 각 글자들을 나타내는 최소 길이의 엔코딩 비트열을 만들 수 있음 -> 각 글자의 빈도수에 따라서 가장 많이 등장하는 글자에는 짧은 비트열을 사용하고 잘 나오지 않는 글자에는 긴 비트열을 사용하여 전체의 크기를 줄이는 것임

각각의 글자를 어떤 비트 코드로 표현했는지를 알려주는 테이블이 있을 때

글자비트코드빈도수비트수

e 00 15 30
t 01 12 24
n 10 8 16
i 110 6 18
s 111 4 12
합계     88

해결해야 될 문제
1. 압축해야 할 텍스트가 주어졌을 때 어떻게 그러한 비트 코드를 자동으로 생성할 것인지
2. 압축된 텍스트가 주어져 있을 떄 어떻게 복원할 것인지
ex) teen의 경우, 가변 코드를 사용하여 코딩하면 01000010이 됨
첫 번째 글자의 경우, 하나의 글자가 4비트까지 가능하므로 0, 01, 010, 0100 중의 하나, 코드 테이블을 보면 0, 010, 0100인 코드는 없기 때문에 01이 분명함
-> 이러한 해독이 가능한 이유: 모든 코드가 다른 코드의 첫 부분이 아니기 때문, 따라서 코딩된 비트열을 왼쪽에서 오른쪽으로 조사해보면 정확히 하나의 코드만 일치하는 것을 알 수 있음 => 이러한 특수한 코드(허프만 코드(Huffman codes)를 만들기 위해서 이진 트리를 사용할 수 있음

허프만 코드가 생성되는 방법
1. 빈도수에 따라 5개의 글자를 나열(s(4), i(6), n(8), t(12), e(15))
2. 여기서 가장 작은 빈도수를 가진 글자 2개(s(4), i(6))을 추출하여 이 들을 단말 노드로 하여 이진 트리를 구성, 루트 노드의 값은 각 자식 노드의 값을 합한 값


3. 위의 과정으로 이진 트리가 구성되면 왼쪽 간선은 1, 오른쪽 간선은 0 비트를 나타냄


-> 각 글자에 대한 허프만 코드는 단순히 루트 노드에서 단말 노드까지의 경로에 있는 간선의 라벨 값을 읽으면 됨
ex) 빈도수 6에 해당하는 글자인 i의 코드는 110이 됨

<프로그램 8.4.3> 허프만 코드 프로그램(최소 힙 사용)

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

#define MAX_ELEMENT 100

// 우선순위는 트리의 weight 값에 의해 결정됨
typedef struct TreeNode{
    int weight;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

typedef struct{
    TreeNode* ptree; // 트리를 가리키는 포인터
    int key; // 그 트리의 weight 값을 key 값으로 가짐
} element;

typedef struct{
    element heap[MAX_ELEMENT];
    int heap_size;
}HeapType;

// 초기화 함수
void init(HeapType *h){
    h->heap_size = 0;
}

// 삽입 함수
void insert_min_heap(HeapType*h,element item){
    int i = (h->heap_size)++;

    while((i!=1) && (item.key > h->heap[i/2].key)){
        h->heap[i] = h->heap[i / 2];
        i /= 2;
    }
    h->heap[i] = item;
}

// 삭제 함수
element delete_min_heap(HeapType *h){
    element item = h->heap[1];
    element tmp = h->heap[(h->heap_size)--];
    int parent = 1, child = 2;

    while(child <= h->heap_size){
        if((child < h->heap_size) && (h->heap[child].key > h->heap[child+1].key)){
            child++;
        }
        if(tmp.key <= h->heap[child].key){
            break;
        }
        h->heap[parent] = h->heap[child];
        parent = child;
        child *= 2;
    }
    h->heap[parent] = tmp;
    return item;
}

// 이진 트리 생성 함수 
// 매개변수로 받은 포인터들을 왼쪽 자식과 오른쪽 자식으로 하는 루트 노드를 만들어서 반환
TreeNode *make_tree(TreeNode*left, TreeNode *right){
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    if(node == NULL){
        fprintf(stderr, "memory allocate error\n");
        exit(1);
    }
    node->left = left;
    node->right = right;
    return node;
}

// 이진 트리 제거 함수
void destory_tree(TreeNode *root){
    if(root == NULL)
        return;
    destory_tree(root->left);
    destory_tree(root->right);
    free(root);
}

// 허프만 코드 생성 함수
void huffman_tree(int freq[], int n){
    TreeNode *node, *x;
    HeapType heap;
    element e, e1, e2;
    init(&heap);
    
    // 빈도수에 따라 각 글자들의 트리를 생성
    for (int i = 0; i < n;i++){
        node = make_tree(NULL, NULL);
        e.key = node->weight = freq[i];
        e.ptree = node;
        insert_min_heap(&heap, e);
    }

    for (int i = 1; i < n;i++){
        // 최솟값을 가지는 두 개의 노드를 삭제
        e1 = delete_min_heap(&heap);
        e2 = delete_min_heap(&heap);

        // 두 개의 노드를 합침
        x = make_tree(e1.ptree, e2.ptree);
        e.key = x->weight = e1.key + e2.key;
        e.ptree = x;
        insert_min_heap(&heap, e);
    }
    e = delete_min_heap(&heap); // 최종 트리
    destory_tree(e.ptree);
}

int main(){
    int freq[] = { 15, 12, 8, 6, 4 };
    huffman_tree(freq, sizeof(freq) / sizeof(int));
}
저작자표시

'다양한 글들 > 자료구조와 알고리즘' 카테고리의 다른 글

그래프 II  (1) 2023.05.14
그래프 I  (0) 2023.05.14
우선순위 큐  (0) 2023.05.14
2. 균형 이진 탐색 트리  (0) 2023.05.11
3. 이진 탐색 트리  (0) 2023.04.27
'다양한 글들/자료구조와 알고리즘' 카테고리의 다른 글
  • 그래프 II
  • 그래프 I
  • 우선순위 큐
  • 2. 균형 이진 탐색 트리
smile blog
smile blog
건국대 첨단바이오공학부 & 컴퓨터공학부 BT & IT 기술로 희망을 꿈 꿉니당
  • smile blog
    스마일 블로그
    smile blog
  • 전체
    오늘
    어제
    • 분류 전체보기 (816) N
      • 일상 생각들 (2)
      • 학과에 대해 (4) N
        • 첨단바이오공학부 (4) N
        • 컴퓨터공학부 (0)
      • -------- 프로젝트 -------- (0)
      • [DS] 토이 프로젝트 (1)
      • [Web, Game, XR] 토이 프로젝트 (11)
      • 경진대회 (1)
      • -------- 진로 -------- (0)
      • 생물정보학자 (18)
        • 데이터 과학이란? (0)
        • 되는 방법 (8)
        • 책 추천 (2)
        • 인강 (1)
        • 대학 (2)
        • 회사 (1)
        • 학원 (2)
        • 학회 (2)
      • 디지털 헬스케어 (72)
        • 방법 (8)
        • 생각들 (10)
        • 공부법 (4)
        • 책 추천 (2)
        • 학원 (2)
        • 참고 (2)
        • 대학 (3)
        • 회사 (3)
        • 인강 (2)
        • 게임 엔진들 (1)
        • 게임 프로그래머 개론 (2)
        • 게임 프로그래머 취업 전략 가이드 (7)
        • 취업 서류 (1)
        • 애정하는 게임들 (4)
        • XR 테크니컬 아티스트 (9)
        • 영화, 애니메이션 테크니컬 디렉터 (12)
      • -------- 기초 학문 -------- (0)
      • 생명과학 이야기 (2)
        • 대학 강의 (2)
      • 화학 이야기 (0)
      • 컴퓨터과학 이야기 (0)
      • 통계학 이야기 (0)
      • 수학 이야기 (1)
        • 공학 수학 (1)
      • 영어 이야기 (1)
      • 심리학 이야기 (7)
        • 현대인과 정신건강 (7)
      • -------- 컴퓨터 언어 -------- (0)
      • Python (3)
        • 나도코딩의 파이썬 입문 (1)
        • 파이썬 관련 정보 (1)
      • SQL (0)
      • C 언어 (32)
        • 혼자 공부하는 C언어 요약 (1)
        • [책 정리] 혼자 공부하는 C언어 (31)
      • C++ (33)
        • 명품 C++ 프로그래밍 요약 (1)
        • [책 정리] 명품 C++ 프로그래밍 (27)
        • C++ STL (0)
        • 뇌를 자극하는 C++ STL (5)
      • -------- 생명과학 -------- (0)
      • 생화학 (5)
        • 대학 강의 (5)
      • 분자세포생물학 (3)
        • 대학 강의 (3)
      • 유전자치료공학 (2)
        • 대학 강의 (2)
      • 생명정보학 (5)
        • 대학 강의 (5)
      • 약리학 (2)
        • 대학 강의 (2)
      • -------- 컴퓨터과학 -------- (0)
      • 자료구조와 알고리즘 (8)
        • 자료구조와 알고리즘의 정의 (3)
        • [책 정리] C언어로 쉽게 풀어쓴 자료구조 요약 (1)
        • [인강] 자료구조와 알고리즘 (2)
        • 코딩 테스트 대비하기! (1)
      • 컴퓨터 회로 (0)
      • 컴퓨터 구조 (43)
        • 컴퓨터 구조와 운영체제 요약 (1)
        • ---------------------------------------- (0)
        • [전공 책 정리] 컴퓨터 구조 및 설계 (1)
        • Ch1. 컴퓨터 추상화 및 관련 기술 (8)
        • Ch2. 명령어 : 컴퓨터 언어 (11)
        • Ch3. 컴퓨터 연산 (8)
        • Ch4. 프로세서 (11)
        • Ch5. 메모리 계층구조 (3)
        • Ch6. 병렬 프로세서 : 클라이언트에서 클라우드까지 (0)
      • 시스템 프로그래밍 (15)
        • [책 정리] 시스템 프로그래밍 유닉스 & 리눅스 (0)
        • [인강] 리눅스 시스템 프로그래밍 (2)
        • 리눅스에서 코딩이란? (8)
        • 대학교 강의 정리 (5)
      • 운영체제 (0)
      • 컴퓨터 네트워크 (37)
        • 모두의 네트워크 요약 (1)
        • [책 정리] 모두의 네트워크 (10)
        • ---------------------------------------- (0)
        • [전공 책 정리] 컴퓨터 네트워킹 하향식 접근 8판 (1)
        • Ch1. 컴퓨터 네트워크와 인터넷 (7)
        • Ch2. 애플리케이션 계층 (7)
        • Ch3. 트랜스포트 계층 (8)
        • Ch4. 네트워크 계층 : 데이터 평면 (3)
        • Ch5. 네트워크 계층 : 제어 평면 (0)
        • Ch6. 링크 계층과 근거리 네트워크 (0)
        • Ch7. 무선 및 이동 네트워크 (0)
        • Ch8. 컴퓨터 네트워크 보안 (0)
      • 데이터베이스 (1)
      • -------- 데이터과학 -------- (0)
      • 데이터 사이언스 (8)
        • 인강 (8)
      • 데이터 분석 (2)
        • 인강 (2)
      • 머신러닝 (2)
        • 대학 수업 (2)
      • 인공지능 (11)
        • 대학교 강의 정리 (10)
        • 인공지능 관련 정보 (1)
      • -------- +a -------- (0)
      • Visual Studio Community (7)
        • 설치법 (1)
        • 단축키 (1)
        • 오류 (5)
      • Visual Studio Code (0)
      • 노션 (1)
      • 깃허브 (7)
        • 깃허브 사용법 (5)
        • 유니티, 언리얼 & 깃허브 (1)
        • 깃허브 주의사항 (1)
      • 챗GPT 활용법 (0)
      • 기타 feat. 프로그래밍 (7)
        • 프로그래머로 살아남기 (5)
        • 코딩 vs 프로그래밍 (1)
        • 애플 비전 프로 (1)
      • 메타버스 (5)
      • -------- 예술 -------- (0)
      • 음악 (1)
      • 미술 (0)
      • -------- XR -------- (0)
      • 유니티 이야기 (23)
        • 레트로의 유니티 게임 프로그래밍 에센스 요약 (4)
        • 유니티 관련 정보 (1)
        • 유니티 디버깅 (13)
        • 유니티 인강 (3)
        • 대학교 게임 프로그래밍 강의 (2)
      • 언리얼 이야기 (0)
        • 인생 언리얼 교과서 요약 (0)
      • 컴퓨터 그래픽스 (6)
        • OpenGL (6)
      • 가상현실 & 증강현실 (4)
        • 유니티 vr (4)
      • HCI 와 UI UX (7)
        • [책 정리] HCI 개론 (6)
      • -------- Design -------- (0)
      • 캐릭터 (1)
        • 모델링 (0)
        • 리깅 (1)
      • 포토샵 (3)
      • 3ds Max (7)
      • Maya (9)
        • 블로그 (1)
        • 인강 (6)
        • 대학교 (2)
      • Blender (14)
        • 책 (1)
        • 인강 (7)
        • 기타 (3)
        • 대학교 (3)
      • 아트 작업물들 (2)
      • 에셋 사이트 (1)
      • -------- 건강관리 -------- (0)
      • 건강관리 ft. 정현 (12)
        • 목 디스크 (2)
        • 눈 관리 (2)
        • 일상생활 습관 (6)
        • 일상생활 꿀팁 (2)
        • 사무직 꿀팁 (0)
      • 헬스의 정석 ft. 정현 (28)
        • 헬스와 건강 (8)
        • 헬스 구체화 정보 (6)
        • 헬스 유튜버 (1)
        • 헬스 서적 (1)
        • 도전 바디프로필! (11)
        • 헬스장 패션 (1)
      • -------- etc -------- (0)
      • 진로 관련 잡다한 글들 (34)
        • 진도율 (9)
        • 진로 관련 글들 (15)
        • 학교 강의 관련 글들 (10)
      • 인생 꿀 Tip (23)
        • 컴퓨터 초기 설정 (9)
        • 원격 데스크톱 (1)
        • 노트북 발열 (1)
        • 전자기기 (2)
        • 중고기기 팔기 (1)
        • 아이패드 필기 어플 (1)
        • 에어팟 (1)
        • 커피 (1)
        • 맥북 (1)
        • lg 그램 (1)
        • 검색엔진에서 내 티스토리 검색 (1)
        • hELLO 다크 모드 없애기 (1)
        • 인터넷 연결 문제 (1)
        • 키보드 문제 해결 (1)
      • 유튜브 (3)
      • 청춘 그리고 추억 (1)
      • 인생 계획표 (2)
        • 2024년 2학기 (1)
        • 2024년 여름방학 (0)
        • 2024년 1학기 (0)
        • 2023년 겨울방학 (1)
      • 다양한 글들 (98)
        • C++ STL (6)
        • Win32 API (24)
        • PushPush 게임 (13)
        • 컴퓨터구조 (1)
        • 자료구조와 알고리즘 (50)
        • 게임의 정의 (3)
        • 영상 회사 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Dream
    • 코딩을 시작한 이유
    • 나를 소개합니다!
    • 블로그 공부법
    • IT & 가치 있는 일들
  • 인기 글

  • 태그

    스택
    심리학
    생물정보학
    유니티
    C++ STL
    배열
    AI
    인공지능
    unity
    자료구조
    데이터사이언스
    명령어
    의생명공학
    생명공학
    건국대
    C언어
    연산자
    블렌더
    알고리즘
    컴퓨터구조
    리눅스 터미널
    데이터과학
    함수
    리눅스
    코드잇
    첨단바이오공학부
    의생명공학과
    C++
    컴퓨터 네트워크
    포인터
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
smile blog
힙
상단으로

티스토리툴바