반응형

🔑 Database

5. DB에서 인덱스를 사용하는 이유는 무엇인지 설명하시오.

👉🏻 DBMS의 인덱스는 검색 속도를 높이기 위한 기술입니다. 인덱스는 정렬된 상태를 유지하기 때문에 원하는 값을 탐색하는데는 빠르지만 새로운 값을 추가(INSERT), 삭제(DELETE), 수정(UPDATE)하는 경우에는 쿼리문 실행 속도가 느려집니다. 즉, DBMS에서 인덱스는 데이터의 저장 성능을 희생하고 그 대신 데이터의 읽기 속도를 높이는 기능이라고 할 수 있습니다. 

인덱스를 사용하면 좋은 경우에는 WHERE절에서 자주 사용되는 Column, 외래키가 자주 사용되는 Column, JOIN에 자주 사용되는 Column이 있습니다. 반면 인덱스 사용을 피해야 하는 경우는 Data 중복도가 높은 Column, DML이 자주 일어나는 Column이 있습니다.

Clustered Index

👉🏻 순서대로 정렬되어 있어서 값을 찾을 때 해당 부분에서만 찾으면 됨

👉🏻 정렬되어 있기 때문에 삽입 시에 오래걸림

👉🏻 한 테이블 당 하나만, PK와 비슷

👉🏻 범위 검색에 좋음

👉🏻  존재하는 PK 사이에 삽입할 시 매우 오래걸림

* Auto-increment

Non-Clustered Index

👉🏻 인덱스와 간접 참조되어 있음

👉🏻  정렬되지 않았기 때문에 삽입 시 오래 걸리지 않음, 해시 테이블 사용하여 빠름

👉🏻 한 테이블에 여러 개

👉🏻 삽입 시 추가 작업 필요(인덱스 생성)

👉🏻 카디널리티가 높아질수록 쓰면 좋음

* 카디널리티는 전체 행에 대한 특정 컬럼의 중복 수치를 나타내는 지표, 카디널리티가 높을수록 중복 수치가 낮아짐


출처: https://wooaoe.tistory.com/47?category=822650 [개발개발 울었다]

반응형
반응형

 

 

 

1) 최소 신장트리의 이해

신장트리란?

  • Spanning Tree, 또는 신장 트리 라고 불리움
  • 원래의 그래프의 모든 노드가 연결되어 있으면서 트리의 속성을 만족하는 그래프
  • 신장 트리의 조건
    • 본래의 그래프의 모든 노드를 포함해야 함
    • 모든 노드가 서로 연결
    • 트리의 속성을 만족시킴 (사이클이 존재하지 않음)

 

최소 신장트리란?

  • Minimum Spanning Tree, MST 라고 불리움
  • 가능한 Spanning Tree 중에서, 간선의 가중치 합이 최소인 Spanning Tree를 지칭함

 

최소 신장트리 알고리즘

  • 그래프에서 최소 신장 트리를 찾을 수 있는 알고리즘이 존재함
  • 대표적인 최소 신장 트리 알고리즘
    • Kruskal’s algorithm (크루스칼 알고리즘)
    • Prim's algorithm (프림 알고리즘)

 

 

2) 크루스칼 알고리즘

  • 모든 정점을 독립적인 집합으로 만든다.
  • 모든 간선을 비용을 기준으로 정렬하고, 비용이 작은 간선부터 양 끝의 두 정점을 비교한다.
  • 두 정점의 최상위 정점을 확인하고, 서로 다른 집합일 경우 두 정점을 연결한다. (최소 신장 트리는 사이클이 없으므로, 사이클이 생기지 않도록 하는 것임)
  • 탐욕 알고리즘을 기초로 하고 있음

 

 

 

3) 프림 알고리즘

  • 시작 정점을 선택한 후, 정점에 인접한 간선중 최소 간선으로 연결된 정점을 선택하고, 해당 정점에서 다시 최소 간선으로 연결된 정점을 선택하는 방식으로 최소 신장 트리를 확장해가는 방식
  • 크루스칼 알고리즘과 프림 알고리즘 비교
    • 둘다, 탐욕 알고리즘을 기초로 하고 있음 (당장 눈 앞의 최소 비용을 선택해서, 결과적으로 최적의 솔루션을 찾음)
    • Kruskal's algorithm은 전체 간선중에서, 가장 가중치가 작은 간선부터 선택하면서 MST를 구함
    • Prim's algorithm은 특정 정점에서 시작, 해당 정점에 연결된 가장 가중치가 작은 간선을 선택, 간선으로 연결된 정점들에 연결된 간선 중에서 가장 가중치가 작은 간선을 택하는 방식으로 MST를 구함

 

 

 

 

 

반응형
반응형

 

 

[ 정렬의 종류 ]

재귀를 이용하지 않는 정렬

1) Selection Sort(선택정렬)

2) Bubble Sort(버블정렬)

3) Insertion Sort(삽입정렬)

 

재귀를 이용하는 정렬

4) Merge Sort

5) Quick Sort

 

 

 

 

 

1. Selection Sort

가장 큰 값을 찾아 맨 오른쪽으로 보낸다.

 

 

ex) 학생의 성적을 정렬하는 프로그램

학생은 학번, 영어, 수학, 국어 성적을 가지고 있음

국어 성적을 기준으로 내림차순 정렬 (selection sort)

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

struct Student {
    int stu_id;
    int eng;
    int math;
    int korean;
};

struct Student* selectSort(struct Student *arr_std, int n){
    
    int i, j, max, maxId;
    struct Student tmp;
    
    for(j=0; j<n-1; j++){
        max = arr_std[0].eng;
        maxId = 0;
        for(i=0; i<n-j; i++){
            if(arr_std[i].eng > max){
                max = arr_std[i].eng;
                maxId = i;
            }
        }
        tmp = arr_std[n-1-j];
        arr_std[n-1-j] = arr_std[maxId];
        arr_std[maxId] = tmp;
    }
    
    return arr_std;
}

int main(void) {
    
    int n, i;
    scanf("%d", &n);

    struct Student *arr_std = (struct Student *)malloc(sizeof(struct Student) * n);

    int stu_id_first = 20210001;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr_std[i].stu_id = stu_id_first + i;
        arr_std[i].eng = rand() % 101;
        arr_std[i].math = rand() % 101;
        arr_std[i].korean = rand() % 101;
    }
    
    arr_std = selectSort(arr_std, n);
    
    for(i=0; i<n; i++){
        printf("%d %d %d %d\n", arr_std[i].stu_id, arr_std[i].eng, arr_std[i].math, arr_std[i].korean);
    }
    
    return 0;
}

 

 

 

 

2. Bubble Sort

두 개 중에 큰 값을 오른쪽에 배치한다.

 

 

 

 

 

 

3. Insertion Sort (삽입정렬)

왼쪽부터 한 숫자씩 선택하면서 자리를 찾고 바꾼다.

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

int* insertSort(int *arr, int n){
    int i,j,tmp;
    
    for(i=1; i<n; i++){
        for(j=0; j<i; j++){
            if(arr[j] > arr[i]){
                tmp = arr[j];
                arr[j] = arr[i];
                arr[i] = tmp;
                continue;
            }
        }
    }
    return arr;
}

int main(void) {
    
    int i,n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    srand((unsigned)time(NULL));
    
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 100;
        printf("%d ",arr[i]);
    }
    printf("\n");
 
    arr = insertSort(arr, n);
    
    for(i=0; i<n; i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
    return 0;
}

 

 

 

 

4. Quick Sort

평균 수행시간 : nlogn

최악 수행시간 : n^2

 

 

1) j는 0부터 n-1까지 돈다.

2) 값이 젤 오른쪽 값보다(pivot) 작으면 i와 j 위치의 값을 서로 바꿔준다. i++

3) j loop가 끝나면 i와 pivot 자리의 값을 바꾼다.

 

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

int partition(int *arr, int s, int e){
    
    int i, j, tmp;
    
    i = s;
    for(j=s; j<e; j++){
        if(arr[j] < arr[e]){
            tmp = arr[j];
            arr[j] = arr[i];
            arr[i] = tmp;
            i++;
        }
    }
    
    tmp = arr[e];
    arr[e] = arr[i];
    arr[i] = tmp;
    
    return i;
}


void quickSort(int *arr, int p, int r){
    int q;
    
    if(p < r){
        q = partition(arr, p, r);
        quickSort(arr, q+1, r);
        quickSort(arr, p, q-1);
    }
}

int main(void) {
    
    int n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    
    int i;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand()%100;
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    quickSort(arr, 0, n-1);
    
    
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    return 0;
}

 

 

 

 

 

 

 

5. Merge Sort

1) 반으로 반으로 끝까지 나눈다.

2) 나눠진 두 그룹을 합치면서 정렬한다.

3) 나눴던 것들을 계속 합치면서 정렬한다.

 

합할 때는 i = s, j = q + 1, t = s 로 시작해서 

arr[i] 와 arr[j] 중에 더 작은 것을 새로운 배열에 넣는다. 이 때 새로운 배열의 인덱스는 t이다.

 

 

 

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

void merge(int *arr, int s, int q, int e, int n){
    int *new_arr = (int *)malloc(sizeof(int) * n);
    
    int i = s, j = q+1, k = s;
    
    while(i <= q && j <= e){
        if(arr[i] > arr[j]){
            new_arr[k++] = arr[j++];
        } else {
            new_arr[k++] = arr[i++];
        }
    }
    
    while(i <= q){
        new_arr[k++] = arr[i++];
    }
    while(j <= e){
        new_arr[k++] = arr[j++];
    }
    
    for(i=s; i<=e; i++){
        arr[i] = new_arr[i];
    }
}

void mergeSort(int *arr, int s, int e, int n){
    int q;
    if (s < e){
        q = (s + e) / 2;
        mergeSort(arr, s, q, n);
        mergeSort(arr, q+1, e, n);
        merge(arr, s, q, e, n);
    }
}

int main(void) {
    int n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    int i;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand()%100;
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    mergeSort(arr, 0, n-1, n);
    
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    
    return 0;
}

 

 

* 퀵 소트는 먼저 정렬을 하고 나서 나눠가는 방식인데 비해, 머지 소트는 먼저 나누고 정렬을 해 나간다.

 

반응형
반응형

 

 

 

1. 개념

- 정적 할당 : 변수 선언을 통해 필요한 메모리 할당

- 동적 할당 : 실행 중에 운영체제로부터 할당 받음 (by Heap)

 

2. 사용법

malloc() / free()

* stdlib.h 을 include 해야 함

 

 

1) 기본 타입 메모리

int *pInt = (int *)malloc(sizeof(int));
char *pChar = (char *)malloc(sizeof(char));

 

 

2) 배열 타입 메모리

int *p = (int *)malloc(sizeof(int) * 5);

 

 

 

 

3. 예시 문제

1) 임의의 정수 n개를 입력받아 n개의 난수를 만들어(0~999) 이를 오름차순을 정렬하는 프로그램

(동적할당 + 선택정렬)


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

int main(void) {
    
    int n, i;
    
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 1000;
        printf("%d ", arr[i]);
    }
    printf("\n\n");
    
    
    // selection sort
    int j, k, max, maxIdx, tmp;
    
    for(k=0; k<n-1; k++){
        max = arr[0];
        maxIdx = 0;
        for(j=0; j<n-k; j++){
            if(max < arr[j]){
                max = arr[j];
                maxIdx = j;
            }
        }
        
        // 젤 뒤로 보내기
        tmp = arr[n-1-k];
        arr[n-1-k] = arr[maxIdx];
        arr[maxIdx] = tmp;
    }
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    
    return 0;
}

 

 

(동적할당 + 버블정렬)

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

int main(void) {
    
    int n, i;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 1000;
        printf("%d ",arr[i]);
    }
    printf("\n");
    
    // bubble sort
    int j, k, tmp;
    
    for(k=0; k<n-1; k++){
        for(j=0; j<n-1-k; j++){
            if(arr[j] > arr[j+1]){
                tmp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = tmp;
            }
        }
    }
    
    for(i=0; i<n; i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
    
    return 0;
}

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

1. 개념 정리

조합 : 순서가 상관없음

순열 : 순서가 상관있음

중복 : 같은 아이템을 여러 번 뽑을 수 있는지 (중복조합 / 중복순열)

 

 

 

2. 문제 해결 방법

- k : 앞으로 뽑아야 할 크기

- Trivial Case : k가 0일 때

- Recursive Case (if k > 0) : 앞으로 K 개를 더 뽑아야 하므로 일단 1개를 뽑고 같은 함수를 이용해 k-1개를 더 뽑는다.

 

 

3. 예시

1) 공뽑기 : A, B, C, D, E, F,G가 적혀 있는 공 7개에서 3개를 뽑는 경우를 구하라

=> 순서가 상관없고 중복이 없으므로 "조합" 문제이다.


#include <stdio.h>

void pick(int n, int* bucket, int bucketSize, int k, char* balls){
    int i, lastIndex,smallest, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%c ", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    if(bucketSize == k){
        smallest = 0;
    } else {
        smallest = bucket[lastIndex] + 1;
    }
    
    for(item=smallest; item<n; item++){
        bucket[lastIndex+1] = item;
        pick(n, bucket, bucketSize, k-1, balls);
    }
}

int main(void) {
    
    int n = 7;
    char balls[7] = {'A','B','C','D','E','F','G'};
    int bucket[3];
    
    pick(n, bucket, 3, 3, balls);
    
    
    return 0;
}

 

 

 

 

2) 배우들 중 n명을 뽑아서 최우수, 우수상을 수여하기로 한다. 1명은 단 하나의 상만 받을 수 있다.

배우는 공유, 김수현, 송중기, 지성, 현빈 5명 중에서 선택한다고 하자. 어떤 경우가 가능한가?

=> 순서가 중요하고, 중복이 허용되지 않으므로 "순열" 문제이다.

 


#include <stdio.h>

int isIn(int* bucket, int size, int num){
    int i;
    for(i=0; i<size; i++){
        if(bucket[i] == num)
            return 1;
    }
    return 0;
}

void pick(int n, int* bucket, int bucketSize, int k, char balls[][10]){
    int i, lastIndex, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%10s", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    for(item=0; item<n; item++){
        if(!isIn(bucket, lastIndex+1, item)){
            bucket[lastIndex+1] = item;
            pick(n, bucket, bucketSize, k-1, balls);
        }
    }
}

int main(void) {
    
    int n = 5;
    char actors[5][10] = {"공유", "김수현", "송중기","지성", "현빈"};
    
    
    int bucket[2];
    
    pick(n, bucket, 2, 2, actors);
    
    
    return 0;
}

 

 

 

3) 4진법으로 만들 수 있는 n자리 수를 모두 나열하는 프로그램 작성하시오

입력 : 3  (3자리 수)

출력 : 000, 001, ..., 333 으로 나오면 된다.

=> 순서가 중요하고, 중복이 가능하므로 "중복순열" 문제이다. 

#include <stdio.h>

void pick(int n, int* bucket, int bucketSize, int k, int* balls){
    int i, lastIndex, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%d", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    for(item=0; item<n; item++){

        bucket[lastIndex+1] = item;
        pick(n, bucket, bucketSize, k-1, balls);
    
    }
}

int main(void) {
    
    int n = 4;
    int num[4] = {0,1,2,3};
    
    int bucket[3];
    
    pick(n, bucket, 3, 3, num);
    
    
    return 0;
}

 

 

 

4) 1부터 n까지의 연속되어 있는 수와 +/-를 이용해서 만들 수 있는 모든 수식을 그 결과와 함께 나열하시오

- 입력 : 2

- 출력:

 + 1 + 2 = 3

+ 1 -2 = -1

-1 + 2 = 1

-1 -2 = -3

 

=> 1과 2는 그대로 있고, +와 -를 이용해 중복순열을 처리하는 문제이다.

#include <stdio.h>

int charToInt(char x, int sum, int n){
    if(x == '+'){
        sum += n;
    } else {
        sum -= n;
    }
    return sum;
}

void func(int n, char bucket[2], int bucketSize, int k, char *balls){
    
    int i, j;
    int balls_idx = bucketSize - k;
    
    if(k == 0){
        int sum = 0;
        for(j=0; j<bucketSize; j++){
           
            printf("%c", balls[j]);
            printf("%d", j+1);
            sum = charToInt(balls[j], sum, j+1);
            
        }
        printf("=%d\n", sum);
        return;
    }
    
    for(i=0; i<bucketSize; i++){
        balls[balls_idx] = bucket[i];
        func(n, bucket, bucketSize, k-1, balls);
    }
}

int main(void) {
    
    char bucket[2] = {'+','-'};
    
    char answer[2];
    
    int n;
    
    scanf("%d", &n);
    
    func(n, bucket, 2, n, answer);
    
    
    return 0;
}

 

 

 

 

 

5) 1000,5000,10000원 짜리 지폐로 입력값을 만들 수 있는 모든 방법을 출력하시오

입력 : 6000

출력 :

- 1000 1000 1000 1000 1000 1000

- 5000 1000

 

=> 순서가 중요하지 않고, 중복을 허용하므로 "중복조합"이다. 

#include <stdio.h>

int sumBalls(int *balls, int ballSize){
    int i, sum = 0;
    for(i=0; i<ballSize; i++){
        sum += balls[i];
    }
    return sum;
}

void func(int input, int *bucket, int bucketSize, int k, int *balls, int ballSize){
    int i, j;
    
    int sum_balls;
    sum_balls = sumBalls(balls, ballSize);
    
    if(sum_balls == input){
        for(j=0; j<ballSize; j++){
            printf("%d ", balls[j]);
        }
        printf("\n");
        return;
    } else if(sum_balls > input){
        return;
    }
    
    for(i=k; i<bucketSize; i++){
        balls[ballSize] = bucket[i];
        func(input, bucket, bucketSize, i, balls, ballSize+1);
    }
    
}

int main(void) {
    
    int moneys[3] = {1000,5000,10000};
    int answer[1000];
    int input;
    
    scanf("%d", &input);
    
    func(input, moneys, 3, 0,  answer, 0);
    
    return 0;
}

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

1. 순환 이란?

: 알고리즘이나 함수가 수행 도중에 자기 자신을 다시 호출하여 문제를 해결하는 기법

순환하는 부분 / 순환을 멈추는 부분으로 구성

 

2. 팩토리얼

 

 

3. 피보나치 수열

 

* 이렇게 구현할 경우, 같은 항을 여러 번 호출하게 되므로 비효율적이다.

-> 이미 계산한 항의 경우 값이 있으면 재귀 호출을 하지 않고 배열의 값을 반환하는 식으로 작성하는 것이 좋다.

 

 

4. 하노이 탑 문제

 

 

 

 

 

 

 

반응형

+ Recent posts