반응형

 

 

 

 

 

 

1. 추정의 개념

1) 점추정 : 한 수치로 추정

2) 구간추정 : 구간으로 추정

 

 

ex) 직장인의 평균 근무시간에 대한 추정

점추정 : 8.5시간

구간추정 : 7.8시간부터 9.2시간 사이

 

 

 

 

 

 

 

 

2. 점추정

 

추정량 : 공식

추정값 : 공식에 따라 계산된 수치

 

표본추출오차의 크기 : E[(θ^ - θ)^2] = E[(θ^ - θ)^2]+Var(θ^)

(θ^ : 추정량, θ:모수)

-> 표본추출오차가 작으려면 위의 값들이 작아야 한다.

 

 

- 좋은 추정량의 요건 

: 불편성(E(θ^) = θ),효율성(분산이 제일 작은 추정량),일치성

 

 

 

 

3. 불편성

추정량이 E(θ^) = θ 의 조건을 만족할 때, 이 추정량은 불편성을 만족한다고 한다.

이때, θ^를 모수 θ의 '불편추정량'이라고 부른다.

 

-> E(X바) = μ, E(S^2) = σ^2,E(P^)=P이므로

추정량 X바, S^2, P^은 각각 모평균, 모분산, 모비율의 불편추정량이다.

 

 

 

불편추정량(대포1) vs 편의추정량(대포2)

-> 표본평균은 불편추정량이나, 중앙값은 편의추정량이다.

 

 

 

 

 

 

 

4. 효율성

: 불편추정량 중에서 분산이 작은 추정량을 효율적이라고 한다.

 

-> 셋 중에서 (1)이 효율성을 만족한다고 볼 수 있다.

 

 

 

 

 

 

 

 

5. 일치성

즉, n이 무한대만큼 커지면 추정량과 모수의 차이가 임의의 수 E보다 무조건 작아야 한다는 것이다.

 

 

-> X바, S^2, P^은 모두 불편성, 효율성, 일치성을 만족하므로 좋은 추정량이다.

 

 

 

 

 

6. 모평균 μ에 대한 구간추정

 

신뢰수준이 1 - α 로 정해지면 추정된 구간 [a, b]는 다음과 같은 특성을 갖는다.

P(a < θ < b) = 1 - α

 

이 때 추정된 구간 [a, b]를 신뢰구간이라고 한다.

* α : 오차율, 유의수준, 허용오차수준

 

 

 

< 신뢰구간의 일반화 >

점추정값 +- 오차한계

 

< 신뢰구간에 대한 해석 >

- 편의상 : 신뢰수준의 확률로 모평균이 신뢰구간에 있다.

- 정확한 : 다양한 표본평균에 따라 신뢰구간이 다양하게 나오는데, 이 중 모평균을 포함하는 신뢰구간의 비율이다.

 

 

 

< 모평균 μ에 대한 구간추정 공식 >

1) σ를 알기 때문에 σ를 사용하였고,Z분포를 사용할수있다.

2) σ를 모르기 때문에 S로 대신 사용하였고,

n이 30보다 클 때에는 Z분포를 사용할 수 있지만, 30보다 작으면 t분포만 사용할 수 있다.

 

 

 

 

 

 

7. t분포 구하기

 

X바 ~ (μ, σ^2/n)이면,

T = X바 - μ / (S / √n)~tn-1

(n-1은 자유도이다.)

 

t5%를 구하려면,

 

 

 

 

 

 

 

8. 모평균 μ의 신뢰구간 공식 정리

 

 

 

 

 

 

 

 

 

 

9. 모비율 p의 구간추정

 

- 모비율 p에 대한 100(1-α)% 신뢰구간(표본이 충분히 큰 경우)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

 

 

1. 모수와 통계량의 관계 분석의 목적

-> 모수와 통계량의 관계를 찾으므로써 표본으로 모집단의 평균, 분산을 추론하기 위해 (추리 통계학)

 

1) 기술 통계학 : 주어진 자료의 특성을 분석한다.

2) 추리 통계학 : 자료가 추출된 모집단의 특성을 추론한다. 주어진 자료로부터 모집단의 평균, 분산을 추론한다.

 

 

 

 

 

 

 

2. 확률적 추출과 비확률적 추출

 

1) 전수조사 : 모집단 전체를 조사

2) 표본조사 : 모집단의 일부인 표본만을 대상으로 자료를 수집

-> 경제성, 자료수집 시간 단축, 정확성, 전수조사가 불가능할 때, 민감한 정보일 때

 

- 1 확률적 추출 : 개별 개체가 선택될 확률이 정해져 있는 경우 

ex) 단순무작위추출, 체계적 추출, 층화추출, 군집추출

- 2 비확률적 추출 : 개별 개체가 선택될 확률이 정해져 있지 않거나, 일부 개체가 선택될 가능성이 전혀 없는 경우

ex) 판단추출, 할당추출, 편의추출

 

 

 

 

3. 표본과 모수의 통계적 관계 : 평균과 분산

 

< 복원추출 가정 >

1) 표본평균들의 평균 = 모평균

2) 표본평균들의 분산 = 모분산 / n ( -> n은 추출한 개수 )

** 표본평균의 표준편차 보다는 표본평균의 표준오차 라고 부른다.

 

< 예시 >

모집단이 {10, 20, 30} 이고 n = 2, 복원추출한다고 가정하자

 

 

표본평균의 표본분포 )

 

표본평균들의 평균 = 10 x 1/9 + 15 x 2/9 + … + 30 x 1/9 = 20

표본평균들의 분산 = (10 - 20)^2 x 1/9 + (15 - 20)^2 x 2/9 + … + (30 - 20)^2 x 1/9 = 100/3 

모평균 = (10 + 20 + 30) / 3 = 20

모분산 = (10 - 20)^2 x 1/3 + (20 - 20)^2 x 1/3 + (30 - 20)^2 x 1/3 = 200/3

 

따라서, 모분산(200/3)을 n(2)로 나누면 표본평균들의 분산(100/3)의 관계가 있다.

모평균(20)은 표본평균들의 평균과(20) 동일하다.

 

 

 

 

 

 

 

 

3. 표본과 모수의 통계적 관계 : 표본추출오차

 

1) 표본추출오차 = 통계량 - 모수

통계량은 표본추출을 통해 추론한 모집단의 값이다.

예를 들어, 표본평균들의 평균으로 모평균을 추론할 때, 추론한 값(통계량)과 모평균의가 표본추출오차이다.

 

 

 

2) 평균의 경우

표본추출오차 = E[(표본평균의 평균 - 모평균)^2] 으로 구할 수 있다.

(+, - 를 상쇄를 방지하기 위해 제곱한다.)

 

E[(표본평균의 평균 - 모평균)^2]  = var(X바) = σ^2 / n

제곱근을 취하면, 

E[(표본평균의 평균 - 모평균)^2] = σ / n

 

 

 

 

즉, n이 커질수록, σ가 작을수록 표본추출오차가 작아진다.

 

 

 

 

 

 

 

 

3. 표본과 모수의 통계적 관계 : X바의 분포

 

1) X가 정규분포를 따를 때,

 

 

-> 모집단이 정규분포를 따르면, 표본평균은 표본크기와 상관없이 정규분포에 따른다.

 

 

2) X가 정규분포를 따르지 않을 때,

 

- 모집단의 크기는 일정하고, 표본의 크기가 다를 때,

 

 

- 표본의 크기는 일정하나, 모집단의 크기가 다를 때,

 

 

- > 모집단이 정규분포를 따르지 않을 때, 

모집단의 크기가 크고 표본크기가 크면 정규분포와 유사하다.

 

 

 

 

 

 

 

3) 중심극한정리

: 무한모집단에서 표본크기가 클수록 표본평균의 분포는 정규분포에 수렴한다.

 

 

ex) 

 

-> n이 30보다 크면 정규분포에 가깝다고 볼 수 있다.

 

 

정리하자면,

1) 모집단이 정규분포를 따르거나

2) 모집단이 정규분포를 따르지 않더라도, 모집단이 크고 표본크기가 30 이상이면

X바가 정규분포에 근사하다.

 

 

 

 

 

 

 

 

4. 표본평균의 구간확률 구하기

 

X바가 정규분포에 근사하면,

X바 ~ N(μ, σ / n) 일 때,  Z = X바 - μ / (σ / n) ~ N(0, 1) 을 활용한다.

 

 

 

 

 

5. 표본분산과 모수의 통계적 관계

 

 

모집단이 {10, 20, 30}으로 구성된다고 가정하자.

n = 2, 비복원 추출 가정

 

 

S^2 (표본분산)의 표본분포 )

 

E(S^2) = 0 x 3/9 + 50 x 4/9 + 200 x 2/9 = 600 / 9 = 200 / 3

즉, E(S^2) = σ^2 이다.

모집단이 정규분포를 따른다면, 카이제곱 분포를 활용할 수 있다. V = (n - 1) S^2 / σ^2 ~ X^n-1 

 

 

카이제곱분포는 비대칭 모양을 이루고, 오른쪽으로 긴 꼬리를 가지며 항상 양수값만을 갖는 특징이 있다.

카이제곱분포의 모양은 자유도에 따라 달라지는데, 이 자유도는 표본의 크기 n에서 1을 뺀 것과 같다.

자유도가 커질수록 카이제곱분포의 모양이 정규분포에 가까워진다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6. 표본비율과 모수의 통계적 관계

 

ex) 모집단이 {R, B, B}로 구성되어 있다고 가정하자.

n=2, 복원추출을 가정한다.

 

 

p^(X/n)의 표본분포 )

 

 

E(P^) = 0 x 4/9 + 1/2 x 4/9 + 1 x 1/9 = 6/18 = 1/3

Var(P^) = (0-1/3)^2 x 4/9 + (1/2 - 1/3)^2 x 4/9 + (1-1/3)^2 x 1/9 = 1/9

 

즉,

E(P^) = p

Var(P^) = p(1-p)/n

 

 

E(X) = np

Var(X) = np(1-p)

으로 정리할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

1. 순차 탐색

: 정렬되지 않은 배열을 처음부터 마지막까지 하나씩 검사한다.

 

1) 시간 복잡도

- 평균 비교 횟수

if 탐색 성공 : (n+1)/2

if 탐색 실패 : n번 비교

따라서 시간복잡도는 O(n)이다.

 

 

2) 코드

 

 

 

 

 

 

 

2. 개선된 순차 탐색

: 리스트 끝에 탐색 키를 저장한다.

(* 탐색 키 : 찾는 값 )

 

 

 

1) 코드

 

 

 

 

 

 

 

3. 이진 탐색(binary search)

 

1) 동작 방식

: 정렬된 배열의 중앙에 있는 값을 조사하여 찾고자 하는 항목이 왼쪽 또는 오른쪽 부분에 배열에 있는지 알아내어

탐색의 범위를 반으로 줄여 가며 탐색을 진행한다.

 

 

 

 

 

 

2) 코드

 

 

3) 시간 복잡도

: log2(N)

 

 

 

 

 

 

4. 색인 순차탐색

: 인덱스 테이블을 사용하여 탐색의 효율을 증대시킨다.

-> 주 자료 리스트와 인덱스 테이블은 모두 정렬되어 있어야 한다.

 

 

 

1) 시간 복잡도

O( (m+n)/m )

 

 

 

 

 

 

5. 보간 탐색

: 사전이나 전화번호부를 탐색하는 방법이다.

 

1) 작동 방식

: 탐색 키가 존재할 위치를 예측하여 탐색한다.

이진 탐색과 유사하나, 리스트를 불균등 분할하여 탐색한다.

 

2) 시간 복잡도

O(log(n))

 

3) 탐색 위치

 

 

 

 

 

 

4) 코드

 

 

 

 

 

 

 

 

 

 

 

6. 균형 이진탐색트리

 

- 이진탐색 vs 이진탐색트리 

1) 이진탐색 : 배열 사용하므로 삽입 / 삭제가 매우 비효율

2) 이진탐색트리 : 트리를 사용하므로 삽입 / 삭제가 매우 빠르다.

 

 

 

3) 시간 복잡도

- 균형 트리 : O(logn)

- 불균형 트리 : O(n), 순차탐색과 동일하다.

 

 

 

 

 

 

 

7. AVL 트리

: 모든 노드의 왼쪽과 오른쪽 서브트리의 높이 차이가 1 이하인 이진탐색트리이다.

- 트리가 비균형 상태이면 스스로 노드를 재배치하여 균형 상태로 유지시킨다.

 

 

1) 개념

균형 인수 : (왼쪽 서브트리 높이 - 오른쪽 서브트리 높이)

모든 노드의 균형 인수가 +-1 이하이면 AVL 트리이다.

 

 

2) 시간복잡도

O(logn) : 균형 트리이므로

 

 

 

 

3) 삽입 연산 시,

 

 

 

 

 

 

Ex 1) LL

 

 

 

 

Ex 2) LR

 

 

 

 

Ex 3) RL

 

 

 

 

Ex 4) RR

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

 

1. 최단 경로 

: 정점 u와 정점 v가 연결되는 경로 중에서 간선들의 가중치 합이 최소가 되는 경로이다.

 

MST와 최단 경로의 차이

MST는 각 정점에 한 번씩 도달해야 하고, 총 비용은 가능한 모든 조합 중 최소여야 한다.

반면, 최단 경로는 가능한 최저 비용으로 시작 정점에서 목표 정점까지 도달하는 것이다.

 

알고리즘 -> 다익스트라, 플로이드

 

 

 

 

 

 

 

 

 

2. 다익스트라 알고리즘 - 최단경로

 

 

1) 동작 방식

 

 

 

 

 

 

2) 핵심 코드

 

void shortest_path(GraphType* g, int start)
{
    int i, u, w;
    
    for (i = 0; i<g->n; i++) /* 초기화 */
    {
        distance[i] = g->weight[start][i];
        found[i] = FALSE;
        previous[i] = start;
    }
    
    found[start] = TRUE;    /* 시작 정점 방문 표시 */
    distance[start] = 0;
    
    for (i = 0; i<g->n-1; i++) {
        
        u = choose(distance, g->n, found);
        found[u] = TRUE;
        
        print_path(start, u);
        
        printf("<%d>\n", distance[u]);

        for (w = 0; w<g->n; w++){
            if (!found[w]){
                if (distance[u] + g->weight[u][w] < distance[w]){
                    distance[w] = distance[u] + g->weight[u][w];
                    previous[w] = u;
                }
            }
        }
    }
}

 

if (distance[u] + g->weight[u][w] < distance[w]){

                    distance[w] = distance[u] + g->weight[u][w];

                    previous[w] = u;

}

: (u까지의 거리와 u에서 w까지의 거리를 더한 것)이 (w까지의 총 거리)보다 적으면

(w까지의 총 거리)를 (u까지의 거리와 u에서 w까지의 거리를 더한 것)으로 변경한다.

 

 

 

 

3) 전체 코드

 

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

#define TRUE 1
#define FALSE 0
#define MAX_VERTICES    100
#define INF    1000000    /* 무한대 (연결이 없는 경우) */

typedef struct GraphType {
    int n;    // 정점의 개수
    int weight[MAX_VERTICES][MAX_VERTICES];
} GraphType;

int distance[MAX_VERTICES];/* 시작정점으로부터의 최단경로 거리 */
int found[MAX_VERTICES];        /* 방문한 정점 표시 */
int previous[MAX_VERTICES];
                                
int choose(int distance[], int n, int found[])      // 아직 방문하지 않은 노드들 중 가장 거리가 짧은 노드 선택
{
    int i, min, minpos;
    min = INT_MAX;
    minpos = -1;
    for (i = 0; i<n; i++)
        if (distance[i]< min && !found[i]) {
            min = distance[i];
            minpos = i;
        }
    return minpos;
}

void print_status(GraphType* g)
{
//    static int step=1;
    
//    printf("STEP %d: ", step++);
//    printf("distance: ");
    
    for (int i = 0; i < g->n; i++) {
        
        if (distance[i] == INF)
            printf(" * ");
        else
            printf("%2d ", distance[i]);
    }
    
    printf("\n");
    printf("        found:    ");
    
    for (int i = 0; i<g->n; i++)
        printf("%2d ", found[i]);
    printf("\n\n");
}

void print_path(int start, int end)     // 뒤에서부터 출력하기 위해 재귀로 구현
{
   int u = end ;
   if(start == end) {
      printf("%d -> ", start);
      return;
   }
   else {
      print_path(start, previous[u]);
      printf("%d -> ", u);
   }
}

//
void shortest_path(GraphType* g, int start)
{
    int i, u, w;
    
    for (i = 0; i<g->n; i++) /* 초기화 */
    {
        distance[i] = g->weight[start][i];
        found[i] = FALSE;
        previous[i] = start;
    }
    
    found[start] = TRUE;    /* 시작 정점 방문 표시 */
    distance[start] = 0;
    
    for (i = 0; i<g->n-1; i++) {
        
        u = choose(distance, g->n, found);
        found[u] = TRUE;
        
        print_path(start, u);
        
        printf("<%d>\n", distance[u]);

        for (w = 0; w<g->n; w++){
            if (!found[w]){
                if (distance[u] + g->weight[u][w] < distance[w]){
                    distance[w] = distance[u] + g->weight[u][w];
                    previous[w] = u;
                }
            }
        }
    }
}

// 그래프 초기화
void graph_init(GraphType *g)
{
     // 구현
    g->n = 0;
    for(int i=0; i<MAX_VERTICES; i++){
        for(int j=0; j<MAX_VERTICES; j++){
            if(i == j){
                g->weight[i][j] = 0;
            } else {
                g->weight[i][j] = INF;
            }
        }
    }
}

void insert_edge(GraphType *g, int start, int end, int key)
{
    if( start >= g->n || end >= g->n ){
        fprintf(stderr,"그래프 : 정점 번호 오류");
        return;
    }
     
     // ƒ⁄µÂ ª¿‘
    g->weight[start][end] = key;
    g->weight[end][start] = key;
}

/*  */
void read_graph(GraphType *g, char *filename)
{
     // 구현
    int number, u, v, key;
   
    FILE *fp;
    fp = fopen(filename, "rt");
   
    if (fp == NULL)
    {
        printf("file %s open error!\n", filename);
        return;
    }
   
    fscanf(fp, "%d\n", &number);
    g->n = number;
    
    // 구현: while (fscanf(fp, "%d\n", &n) != EOF) {...} 을 사용한다.
    while(fscanf(fp, "%d\n", &u) != EOF && fscanf(fp, "%d\n", &v) != EOF && fscanf(fp, "%d\n", &key) != EOF){
       
        insert_edge(g, u, v, key);
    }

    fclose(fp);
}


int main(void)
{
    GraphType g;
    
    graph_init(&g);
    read_graph(&g, "input.txt");
    
    shortest_path(&g, 4);
    
    return 0;
}

 

 

 

 

 

 

4) 시작 정점부터 경로를 출력하기 위해 previous[u]라는 배열을 하나 더 선언하였다.

previous[u] = u 전의 노드이다.

 

void print_path(int start, int end)     // 뒤에서부터 출력하기 위해 재귀로 구현
{
   int u = end ;
   if(start == end) {
      printf("%d -> ", start);
      return;
   }
   else {
      print_path(start, previous[u]);
      printf("%d -> ", u);
   }
}

//
void shortest_path(GraphType* g, int start)
{
    int i, u, w;
    
    for (i = 0; i<g->n; i++) /* 초기화 */
    {
        distance[i] = g->weight[start][i];
        found[i] = FALSE;
        previous[i] = start;
    }
    
    found[start] = TRUE;    /* 시작 정점 방문 표시 */
    distance[start] = 0;
    
    for (i = 0; i<g->n-1; i++) {
        
        u = choose(distance, g->n, found);
        found[u] = TRUE;
        
        print_path(start, u);
        
        printf("<%d>\n", distance[u]);

        for (w = 0; w<g->n; w++){
            if (!found[w]){
                if (distance[u] + g->weight[u][w] < distance[w]){
                    distance[w] = distance[u] + g->weight[u][w];
                    previous[w] = u;
                }
            }
        }
    }
}

 

: 처음에 previous 배열을 모두 start로 초기화시켜준다.

: 그리고 노드를 하나씩 정해갈 때마다 previous[u]값을 설정한다.

: print_path에서 재귀를 통해 뒤에서부터 출력한다.

 

 

 

 

5) 시간 복잡도

: O(n^2)

 

 

 

 

 

 

 

3. 플로이드 알고리즘 - 최단경로

 

1) 작동 방식

: 모든 정점 사이의 최단 경로를 찾는다.

:  (i 에서 j로 가는 거리)와 (i -> k + k ->j 로 가는 거리) 중에 더 짧은 경로로 간다.

 

 

 

2) 전체 코드

 

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

#define TRUE 1
#define FALSE 0
#define MAX_VERTICES	100	
#define INF	1000000	/* 무한대 (연결이 없는 경우) */

typedef struct GraphType {
	int n;	// 정점의 개수
	int weight[MAX_VERTICES][MAX_VERTICES];
} GraphType;

int A[MAX_VERTICES][MAX_VERTICES];

void printA(GraphType *g)
{
	int i, j;
	printf("===============================\n");
	for (i = 0; i<g->n; i++) {
		for (j = 0; j<g->n; j++) {
			if (A[i][j] == INF)
				printf("  * ");
			else printf("%3d ", A[i][j]);
		}
		printf("\n");
	}
	printf("===============================\n");
}

void floyd(GraphType* g)
{

	int i, j, k;
	for (i = 0; i<g->n; i++)
		for (j = 0; j<g->n; j++)
			A[i][j] = g->weight[i][j];
	printA(g);

	for (k = 0; k<g->n; k++) {
		for (i = 0; i<g->n; i++)
			for (j = 0; j<g->n; j++)
				if (A[i][k] + A[k][j] < A[i][j])
					A[i][j] = A[i][k] + A[k][j];
		printA(g);
	}
}

int main(void)
{
	GraphType g = { 7,
	{{ 0,  7,  INF, INF,   3,  10, INF },
	{ 7,  0,    4,  10,   2,   6, INF },
	{ INF,  4,    0,   2, INF, INF, INF },
	{ INF, 10,    2,   0,  11,   9,   4 },
	{ 3,  2,  INF,  11,   0, INF,   5 },
	{ 10,  6,  INF,   9, INF,   0, INF },
	{ INF, INF, INF,   4,   5, INF,   0 } }
	};
	floyd(&g);
	return 0;
}

 

 

 

 

 

 

 

3) 시간 복잡도

O(n^3)

 

- 다익스트라 알고리즘도 모든 정점부터 시작하는 최단 경로를 구하려면 O(n^2)을 n번 반복해야 하기 때문에

시간복잡도가 O(n^3)가 된다.

 

 

 

 

 

 

 

 

 

 

4. 위상 정렬

: 방향이 있는 그래프에서 선행 순서를 위배하지 않으면서도 모든 정점을 방문하는 알고리즘이다.

 

 

1) 동작 방식

: 선수 노드가 없는 노드를 선택한다.

: 선택한 노드의 선행 관계를 삭제한다.

: 선택되지 않은 노드들 중 선수 노드가 없는 노드를 다시 선택한다.

x 모든 정점이 선택될 때까지 반복

 

 

 

 

 

 

 

2) 전체 코드

 

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_VERTICES 50

typedef struct GraphNode
{
	int vertex;
	struct GraphNode *link;
} GraphNode;

typedef struct GraphType {
	int n;	// 정점의 개수
	GraphNode *adj_list[MAX_VERTICES];
} GraphType;

// 그래프 초기화 
void graph_init(GraphType *g)
{
	int v;
	g->n = 0;
	for (v = 0; v<MAX_VERTICES; v++)
		g->adj_list[v] = NULL;
}
// 정점 삽입 연산
void insert_vertex(GraphType *g, int v)
{
	if (((g->n) + 1) > MAX_VERTICES) {
		fprintf(stderr, "그래프: 정점의 개수 초과");
		return;
	}
	g->n++;
}
// 간선 삽입 연산, v를 u의 인접 리스트에 삽입한다.
void insert_edge(GraphType *g, int u, int v)
{
	GraphNode *node;
	if (u >= g->n || v >= g->n) {
		fprintf(stderr, "그래프: 정점 번호 오류");
		return;
	}
	node = (GraphNode *)malloc(sizeof(GraphNode));
	node->vertex = v;
	node->link = g->adj_list[u];
	g->adj_list[u] = node;
}

#define MAX_STACK_SIZE 100
typedef int element;
typedef struct {
	element stack[MAX_STACK_SIZE];
	int top;
} StackType;

// 스택 초기화 함수
void init(StackType *s)
{
	s->top = -1;
}
// 공백 상태 검출 함수
int is_empty(StackType *s)
{
	return (s->top == -1);
}
// 포화 상태 검출 함수
int is_full(StackType *s)
{
	return (s->top == (MAX_STACK_SIZE - 1));
}
// 삽입함수
void push(StackType *s, element item)
{
	if (is_full(s)) {
		fprintf(stderr, "스택 포화 에러\n");
		return;
	}
	else s->stack[++(s->top)] = item;
}
// 삭제함수
element pop(StackType *s)
{
	if (is_empty(s)) {
		fprintf(stderr, "스택 공백 에러\n");
		exit(1);
	}
	else return s->stack[(s->top)--];
}

// 위상정렬을 수행한다.
int topo_sort(GraphType *g)
{
	int i;
	StackType s;
	GraphNode *node;

	// 모든 정점의 진입 차수를 계산
	int *in_degree = (int *)malloc(g->n * sizeof(int));
	for (i = 0; i < g->n; i++)			// 초기화
		in_degree[i] = 0;
	for (i = 0; i < g->n; i++) {
		GraphNode *node = g->adj_list[i];//정점 i에서 나오는 간선들
		while (node != NULL) {
			in_degree[node->vertex]++;
			node = node->link;
		}
	}
	// 진입 차수가 0인 정점을 스택에 삽입
	init(&s);
	for (i = 0; i < g->n; i++) {
		if (in_degree[i] == 0) push(&s, i);
	}
	// 위상 순서를 생성 
	while (!is_empty(&s)) {
		int w;
		w = pop(&s);
		printf("정점 %d ->", w);		//정점 출력
		node = g->adj_list[w];	//각 정점의 진입 차수를 변경
		while (node != NULL) {
			int u = node->vertex;
			in_degree[u]--;			//진입 차수를 감소
			if (in_degree[u] == 0) push(&s, u);
			node = node->link;   // 다음 정점
		}
	}
	free(in_degree);
	printf("\n");
	return (i == g->n);	// 반환값이 1이면 성공, 0이면 실패
}
//	
int main(void)
{
	GraphType g;

	graph_init(&g);
	insert_vertex(&g, 0);
	insert_vertex(&g, 1);
	insert_vertex(&g, 2);
	insert_vertex(&g, 3);
	insert_vertex(&g, 4);
	insert_vertex(&g, 5);

	//정점 0의 인접 리스트 생성
	insert_edge(&g, 0, 2);
	insert_edge(&g, 0, 3);
	//정점 1의 인접 리스트 생성
	insert_edge(&g, 1, 3);
	insert_edge(&g, 1, 4);
	//정점 2의 인접 리스트 생성
	insert_edge(&g, 2, 3);
	insert_edge(&g, 2, 5);
	//정점 3의 인접 리스트 생성
	insert_edge(&g, 3, 5);
	//정점 4의 인접 리스트 생성
	insert_edge(&g, 4, 5);
	//위상 정렬 
	topo_sort(&g);
	// 동적 메모리 반환 코드 생략
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

 

 

1. 동시성 제어 기법

1) 잠금 -> 대부분 이 방법 사용

: 트랜잭션의 실행 순서를 강제로 제어한다.

 

2) 타임스탬프

: 최대한 병행 수행을 보장하나,

: 직렬 가능한 스케줄에 위배될 가능성이 있으면 실행 취소한다.

 

 

 

 

2. 잠금

: 하나의 트랜잭션을 수행하는 동안 특정 데이터 항목에 대해 다른 트랜잭션이 동시에 접근하지 못하도록 하는 기법이다.

 

 

 

 

 

1) 공유 잠금 (S-lock)

 

2) 배타 잠금 (X-lock)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

 

 

 

1. 동시성 제어

: 다중 사용자 DBMS에서 필요하다.

: 동시에 실행되는 트랜잭션들 간에 간섭이 발생하여 일관성이 깨지지 않도록 트랜잭션 실행 순서를 제어하는 기법이다.

 

 

 

2. 트랜잭션에서의 연산

1) read(x)

: 이름이 x인 데이터베이스 항목을 트랜잭션의 지역변수 x로 읽어들인다.

x는 테이블, 레코드, 필드 등

 

2) write(x)

: 지역변수 x에 저장된 값을 데이터베이스 항목 x에 저장한다.

** write 연산 수행 시 그 결과가 디스크에 저장될 수도 있고 그렇지 않을 수도 있다.

 

대부분의 dbms는 성능 향상을 위해 메모리 buffer를 사용한다.

 

 

 

 

 

 

3. 동시성 제어가 필요한 이유

: 트랜잭션들에 정의된 명령들 간 끼어들기가 가능하다.(interleaving)

 

- 스케줄

: 끼어들기 방식에 의해 실행되는 순서

: 스케줄은 전적으로 운영체제의 권한이다.

: 사용자는 어떠한 스케줄로 트랜잭션들이 실행되는지 미리 예측하기 어렵다.

 

- 끼어들기 방식의 문제점

: 서로간의 간섭에 의해서 잘못된 데이터를 생성할 수 있다.

: 갱신 분실, 연쇄 복귀, 불일치 분석 현상이 발생가능하다.

 

 

 

 

4. 갱신 분실

T1이 read를 수행하고 write 하기 전에 T2가 read를 다시 수행하면 x값이 overwrite 되어서 사라진다.

 

 

 

 

5. 연쇄 복귀

: T3가 복귀(rollback)하면 T4에서 한 수행도 복귀되어야 한다.

but T4가 이미 완료된 이후라면 복귀 불가능하다.(지속성 위배)

완료되지 않은 트랜잭션의 쓰기 연산에 의해 갱신된 데이터를 다른 트랜잭션이 읽었기 때문에 (dirty read)

 

 

 

 

 

 

 

 

 

6. 불일치 분석

 

 

 

 

 

7. 끼어들기로 인한 문제점 해결방안

 

1) 트랜잭션들을 하나씩 순차적으로 실행한다.

2) 직렬 스케줄 생성 -> 시스템 성능 저하 발생

3) 직렬 가능한 스케줄 생성 -> 끼어들기를 최대한 허용하면서 직렬 스케줄과 동일한 결과를 갖도록 실행 순서를 제어한다.

 

 

 

6. 직렬 스케줄

: 각 트랜잭션의 연산들이 끼어들기 방식으로 실행되지 않고, 순차적으로 실행되는 스케줄이다.

 

 

 

 

 

7. 직렬 가능한 스케줄

: 직렬 스케줄과 실행 결과가 동일한 스케줄이다.

 

- 직렬 가능한 스케줄인지 판단하는 방법

: 스케줄에 나타난 연산들의 순서를 바꿔 직렬 스케줄을 만들 수 있으면 직렬 가능한 스케줄이다.

 

 

ex) C1와 C2의 실행 순서를 바꿔 직렬 스케줄로 만들 수 있들 수 있으면 직렬 가능 스케줄

 

 

- C1, C2의 실행 순서를 바꿀  수 있는 경우

 

: C1과 C2가 서로 다른 데이터 항목에 대한 연산일 경우 -> 교환 가능하다.

: C1과 C2가 같은 데이터 항목이지만,

C1과 C2가 모두 read 연산일 경우, -> 교환 가능하다.

C1과 C2 중 하나라도 write 연산일 경우, -> 교환 불가능하다.

 

 

 

 

 

 

1) 직렬 스케줄로 변환 가능한 경우

 

 

 

 

2) 직렬 스케줄로 변환 불가능한 경우

 

: 직렬 스케줄로 바꾸기 위해서는 (1)과 (4)의 순서를 바꾸거나 (2)와 (3)의 순서를 바꿔야 하는데,

같은 데이터이고 write 가 들어가기 때문에 바꿀 수 없다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts