공부하자

Data Structure - 알고리즘이란, 그래프, 하노이 알고리즘 본문

Programming/Data Structure & Algorithm

Data Structure - 알고리즘이란, 그래프, 하노이 알고리즘

공부를 하자 2017. 12. 21. 22:49

@markdown

# Data Structure


## 알고리즘


문제를 해결하기 위한 방법 또는 **절차**


### 알고리즘의 조건


* 명확성

* 수행 가능성

* 유한성

* 0개 이상의 입력

* 1개 이상의 출력


---


#### 명확성


코드가 명확하게 어떻게 돌아가는지 알 수 있어야 한다.


---


#### 수행 가능성


코드가 실제로 수행 가능해야 한다.


---


#### 유한성


무한루프가 돌지 않아야 한다.


---


#### 0개 이상의 입력


최소한 **0개 이상의 입력**이 존재해야한다.



---


#### 1개 이상의 출력


최소한 **1개 이상의 출력**이 존재해야한다.


---


## 그래프


* Kruskal

* Prim

* Sollin

* DFS (깊이 우선탐색)

* BFS (너비 우선탐색)


----


#### Kruskal


그래프에서 **가중치가 가장 작은 순서대로 선택**하는 방법


#### Prim


**노드의 간선 중에서 작은 것부터 선택**하는 방법


#### Sollin


**남는 노드 없이 간선**을 연결하는 방법


---


#### Kruscal, Prim, Sollin


* 신장트리는 모두 같다

    * 가중치의 합이 같다

* 순서는 다르다


---


#### DFS (깊이 우선탐색)


* 스택 사용

* 백트래킹 발생

* 미로 탐색


```c

#include <stdio.h>


int arr[6][6];

char visited[2][6]={'A','B','C','D','E','F',

'F','F','F','F','F','F'};

void dfs(int v);

int main()

{

int i,j,n;

for(i=0;i<6;i++)

for(j=0;j<6;j++)

scanf("%d",&arr[i][j]); // 0과 1만 입력받아야 정상 작동

printf("\nStart node => ");

scanf("%d",&n);

dfs(n);

}


void dfs(int v)

{

int j;

if(visited[1][v] == 'F')

{

visited[1][v] = 'T';

printf("%c ",visited[0][v]);

}

for(j=0;j<6;j++)

if(arr[v][j] == 1 && visited[1][j] == 'F')

dfs(j);

return;

}

```


|   |a|b|c|d|e|f|

|:-:|:-:|:-:|:-:|:-:|:-:|:-:|

|**a**|0|1|0|0|1|1|

|**b**|1|0|1|1|0|0|

|**c**|0|1|0|1|0|0|

|**d**|0|1|1|0|0|0|

|**e**|1|0|0|0|0|1|

|**f**|1|0|0|0|1|0|


(입력 시에 사용해도 좋을 DFS 표이다.)


#### BFS (너비 우선 탐색)


* 큐 사용

* 백트래킹이 발생하지 않음

* 최단거리 탐지에 사용


필요로 하는 최소의 큐 크기는 **n-1** 이다.


---

#### DFS, BFS


알파벳 순서대로 오름차순 (↑), 내림차순 (↓)에 따라 탐색을 실행한다.


---


### 시간 복잡도


**O(n)** 과 같이 표현하며 프로그램에서 **시간 복잡도가 가장 큰 것만** 표기한다.


* 이중 for문 : O(n²)

```c

for(i=0;i<n;i++)

    for(j=0;j<n;j++)

        sum += i;

```


* 단일 for문 : O(n)

```c

for(i=0;i<n;i++)

    sum += i;

```


* 분할 정복 : O(logn)

    * 정렬

    * 하노이 알고리즘

    * 트리 구조


* 단일 (또는 다중) 계산 : O(1)

<br>-> 연산은 빠른 속도로 진행되기 때문에 모든 연산을 1로 보아도 된다.


```c

sum = n*(n+1)/2;

```


위의 코드가 for문 내에서 돌아간다고 치면 for문이 한번 돌 때 연산은 한 번만 진행되기 때문에 시간 복잡도는 O(n)이 아닌 O(1) 이다.


---

### Hanoi


#### 조건


1. 큰 원판 위에 작은 원판만 올 수 있다.

2. **한 번에 하나의 원판만** 이동할 수 있다.


|원판 개수|이동 횟수|

|:-:|:-:|

|1|1|

|2|3|

|3|7|

|...|...|

|n|2ⁿ-1|


하노이 원판 이동 횟수


= 완전이진트리의 최대 노드 개수


= 포화 이진트리의 노드 개수


```c

#include <stdio.h>


int hanoi(int x);


int main()

{

int n;

scanf("%d",&n);

printf("%d ",hanoi(n));

return 0;

}


int hanoi(int x)

{

if(x==1) return 1;

return hanoi(x-1)+1+hanoi(x-1);

}

```

```c

#include <stdio.h>


void hanoi(int x, char sc, char mc, char dc);


int main()

{

int n;

scanf("%d",&n);

hanoi(n,'A','B','C');

return 0;

}


void hanoi(int x, char sc, char mc, char dc)

{

if(x==0) return;

hanoi(x-1,sc,dc,mc);

printf("%d : %c -> %c\n", x, sc, dc);

hanoi(x-1,mc,sc,dc);

}

```


```c

if(x==1) return 1;

```

```c

if(x==0) return;

```

위의 `if`문들은 알고리즘 조건 중에서 **유한성**을 만족시켜주는 조건문이다.


---


### Red Black Tree


* 모든 노드는 **Red** 노드 혹은 **Black** 노드 이다.

* 루트노드는 항상 **Black** 노드

* 리프노드는 항상 **Black** 노드

* **Red** 노드의 자식노드는 항상 **Black** 노드

* 어떤 노드로부터 모든 리프노드까지 경로는 **Black** 노드 개수가 동일하다

Comments