반응형

인하대학교 전자공학과 데이터 구조 포인터, 어레이 과제 (pointer, array)


인하대학교 전자공학과 데이터 구조 하노이의 탑, 이진 탐색(binary search, tir, recursive)


인하대학교 전자공학과 데이터 구조 시스템 스택, 선형 리스트 (system stack, linear list)


인하대학교 전자공학과 데이터 구조 preorder, postorder, max heap


인하대학교 전자공학과 데이터 구조 dfs, bfs, 프림, 크루스칼 (prim, kruskal)


소스코드, 수도코드, 플로우차트(순서도), 분석 및 고찰, 결과창 등이 들어있는 보고서입니다.


전부 만점받은 보고서입니다. 

반응형
반응형

1. Implement the dfs and bfs algorithms using the given graph and adjacency lists (Figure 1).


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdio.h>
#include <stdlib.h>
#define SIZE 8
#define FALSE 0  //boolean 연산을 위한 상수 설정
#define TRUE 1   //boolean 연산을 위한 상수 설정
typedef struct node *pn; //node형 포인터 자료형 pn
typedef struct node{
    int vertice;
    pn link;
}node; //node 자료형 안에는 node의 주소를 나타내는 link와 정수형 변수 vertice 포함
void add(pn a);
void dfs(int v);
void bfs(int v);
void addq(int *rear,int value);
int deleteq(int *front);
 
pn graph[SIZE]; //pn형 크기 8짜리 배열 graph
int visited[SIZE]; //int형 크기 8짜리 배열 visited, 방문한 노드 삽입
int queue[SIZE]; // 사이즈 8짜리 큐
 
int main(void)
{
pn cup; //pn형 변수 cup (포인터) 임시 저장소
int i;
for(i=0;i<SIZE;i++//graph 배열의 원소 초기화
{
    graph[i]=0;
}
add(&graph[0],1);    add(&graph[0],2);
add(&graph[1],0);    add(&graph[1],3);    add(&graph[1],4);
add(&graph[2],0);    add(&graph[2],5);    add(&graph[2],6);
add(&graph[3],1);    add(&graph[3],7);
add(&graph[4],1);    add(&graph[4],7);
add(&graph[5],2);    add(&graph[5],7);
add(&graph[6],2);    add(&graph[6],7);
add(&graph[7],3);    add(&graph[7],4);    add(&graph[7],5);    add(&graph[7],6); 
//주어진 그림대로 그래프 초기화 하는 과정
for(i=0;i<SIZE;i++){
cup=graph[i]; //graph[i]를 cup에 대입
printf("graph[%d]    ",i);
while(cup){ //cup이 0이 아니면(각 노드는 링크드 리스트로 구성되어 있어 마지막 노드는 0을 가리킴)
printf("%d ",cup->vertice); //cup->vertice 출력
cup=cup->link; //cup에 cup->link 대입
}
printf("\n"); //개행문자 출력
}
printf("DFS : ");dfs(0); printf("\n"); //dfs 실행
for(i=0;i<SIZE;i++)
{visited[i]=FALSE;} //visited된 노드들 초기화 (bfs 를 하려면 초기화 시켜줘야함)
printf("BFS : ");bfs(0); printf("\n"); //bfs 실행
return 0;
}
 
void add(pn *a,int value){  //그래프의 노드를 연결해주는 함수
    /*a에 해당하는 것이 노드를 가리키는 포인터, value는 추가할 값이다.
    a에 이미 연결되어 있는 메모리가 존재하면 계속 링크를 타고 가다가 링크가 0인
    메모리에 동적메모리할당 한것을 링크시켜 그곳에 value를 넣어준다
    add(&graph[0],1);    add(&graph[0],2); 예를들어 main함수에서 나온 것인데
    맨처음 graph[0]이 1을 갖는 메모리를 가리키고 1를 갖는 메모리가 2를 갖는 메모리를 가리키고
    2를 갖는 메모리의 링크는 0이다. 이런식으로 진행이 된다. 링크가 0인지 아닌지는 함수가 스스로 판단한다.*/
    pn *check=0//check를 NUL로 초기화,check는 이중포인터
    pn tmp = (pn)malloc(sizeof(node)); //tmp가 가리키는 곳에 node size 동적 메모리 할당
    check=a; //check가 가리키는 주소 = a가 가리키는 주소
    while(1){
        if((*check)==0){break;} // check가 가리키는 주소가 0이면 루프 탈출
    else if(((*check)->link)!=0){ //(*check)->link)!=0)이면 
        check=&((*check)->link); //check에 &((*check)->link) 대입
    }
    else//이외의경우
        check=&((*check)->link);  //check에 &((*check)->link) 대입하고 break
        break;}}
    *check=tmp; //check가 가리키는 주소에 tmp 대입
    (*check)->vertice=value; //value를 마지막 노드의 vertice 에 삽입
    (*check)->link=0//마지막 노드의 링크는 0
}
void dfs(int v){
    pn w; //pn형 변수 w (포인터)
    visited[v]=TRUE; //visited[v]에 1 대입
    printf("%5d",v); //5자리수로 해서 출력
    for(w=graph[v];w;w=w->link) //초기식 : w=graph[v], 조건식 : w가 존재하면(not 0) 증가식 : w에 w->link 대입
    {
        if(!visited[w->vertice]) //w가 가리키는 주소의 vertice가 방문하지 않은 노드라면
            dfs(w->vertice); //dfs 순환 호출
    }
}
void bfs(int v){
    pn w; //pn형 변수 w(포인터)
    int front=-1//front와 rear 를 -1로 설정(원형 큐)
    int rear=-1;
    printf("%5d", v); // 5의 전체 크기로 출력
    visited[v]=TRUE; //visited[v]에 true 대입(1)
    addq(&rear,v); //v를 원형 큐에 삽입
    while(front!=rear){ //front가 not rear 이면
    v=deleteq(&front); // 맨 앞 원소 delete
    for(w=graph[v];w;w=w->link){ //초기식 : w=graph[v], 조건식 : w가 존재하면(not 0) 증가식 : w에 w->link 대입
        if(!visited[w->vertice]) //w가 가리키는 주소의 vertice가 방문하지 않은 노드라면
        {
        printf("%5d", w->vertice); //w->vertice 출력
        addq(&rear,w->vertice); //w->vertice 큐에 삽입
        visited[w->vertice]=TRUE;  //visited[w->vertice]에 true 대입(1)
        }}}}
void addq(int *rear,int value){ //원형 큐에서 삽입
    *rear=(*rear)%SIZE;
    queue[++(*rear)]=value;
}
int deleteq(int *front){ //원형 큐에서 원소 삭제
    return queue[++(*front)%SIZE];
}
 
cs



2. Refine Prim’s algorithm, Kruskal’s algorithm into a C function that finds a minimum cost spanning tree.



Prim’s algorithm


Kruskal’s algorithm


graph


<Prim's Algorithm>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <stdio.h>
#include <stdlib.h>
 
typedef struct edge{ //edge 형 변수
    int left;  //int형변수 left,right,weight,u를 포함한다.
    int right;
    int weight;    
    int u;  // 어떤 집합에 속할지 정해준다. (여기서는 사용하지 않음)
}edge; 
 
void Prim(edge E[],edge T[]);
 
int Ecount=0;    //몇번째 E의 원소를 참조하고 있는가
int TVlength=1;  //노드가 들어갈 집합
int Tlength=0;   //dege T의 길이
int TV[7]={0,-1,-1,-1,-1,-1,-1}; //노드가 들어갈 집합, 몇번부터 시작하는지는 상관 없으나 0번부터 시작하라고 해서 0번만 넣고 나머지는 나올 수 없는 -1로 초기화
edge T[6];     //우리가 prim algorithm 에 의해 선택한 간선을 넣을 집합
edge E[9];    //기존에 주어진 set
 
int main(void)
{
    int i;    
    for(i=0;i<20;i++){
    T[i].left=-1;    T[i].right=-1;    T[i].u=-1;    T[i].weight=-1;}
    E[0].left=5;    E[0].right=0;    E[0].weight=10;    E[0].u=-1;
    E[1].left=0;    E[1].right=1;    E[1].weight=28;    E[1].u=-1;
    E[2].left=1;    E[2].right=2;    E[2].weight=16;    E[2].u=-1;
    E[3].left=2;    E[3].right=3;    E[3].weight=12;    E[3].u=-1;
    E[4].left=6;    E[4].right=3;    E[4].weight=18;    E[4].u=-1;
    E[5].left=4;    E[5].right=3;    E[5].weight=22;    E[5].u=-1;
    E[6].left=4;    E[6].right=6;    E[6].weight=24;    E[6].u=-1;
    E[7].left=5;    E[7].right=4;    E[7].weight=25;    E[7].u=-1;
    E[8].left=6;    E[8].right=1;    E[8].weight=14;    E[8].u=-1//책에 나와있는대로 초기화
    Prim(E,TV); //Prim 알고리즘 실행
    for(i=0;i<6;i++)
    {printf("%d %d %d %d\n",T[i].left,T[i].right,T[i].u,T[i].weight);} //확인을 위해 출력
    return 0;
}
void Prim(edge E[],int TV[]){
    int i=0int j; int k;int count=0int flag=0
    int tmpisl=-1; edge tmpedge;
    while(Tlength<6){
        /*for(u=0;u<TVlength;u++)
        {printf("%d",TV[u]);}
        printf("\n");*/
        tmpisl=-1;  tmpedge.left=-1; tmpedge.right=-1; tmpedge.u=-1; tmpedge.weight=100//tmp 각 원소 초기화 weight는 무조건 모든 간선 weight보다 크게
            for(j=0;j<9;j++){ //j는 0부터 9보다 작을 때까지
                count=0;  //count=0으로 초기화
                for(k=0;k<TVlength;k++)  //k=0부터 TVlength 보다 작을 때까지
                {if((TV[k]==E[j].left)) //TV[k]가  E[j].left와 같으면
                count++;} //count ++;
                for(k=0;k<TVlength;k++){ //k=0부터 TVlength 보다 작을 때까지
                if((TV[k]==E[j].right)) //TV[k]가  E[j].right와 같으면
                count++;} //count ++;
                printf("i=%d j=%d k=%d count=%d TLength=%d TVLength=%d\n",i,j,k,count,Tlength,TVlength);
                if(count==1){ //즉 E[j](간선)에 노드 TV[k]가 들어있으면 만약 count==2면 cycle 이라서 안됨
                    if(E[j].weight<tmpedge.weight) //E[j].weight<tmpedge.weight 면(작은걸 택해야 하니까)
                    {
                    tmpedge.left=E[j].left;
                    tmpedge.right=E[j].right;
                    tmpedge.u=E[j].u;
                    tmpedge.weight=E[j].weight; //tmp에 E[j]의 요소 대입
                    flag=0//flag에 0 대입
                    for(k=0;k<TVlength;k++){ //k=0부터 TVlength 아래까지
                        if(E[j].left==TV[k]) //E[j].left==TV[k]면 루프탈출
                            break;
                        else flag++//아니면 flag++
                    }
                    if(flag==TVlength) //flag가 TVlength면
                        tmpisl=E[j].left; //tmpisl 에 E[j].left대입
                    flag=0//flag 0으로 초기화
                    for(k=0;k<TVlength;k++){ //k=0부터 k<TVlength 까지
                        if(E[j].right==TV[k])  //E[j].right==TV[k]면 루프탈출
                            break;
                        else flag++;  //아니면 flag++
                    }
                    if(flag==TVlength) //flag==TVlength면
                        tmpisl=E[j].right; // tmpisl에 E[j].right대입;
                    /*TV에 없는걸 tempisl에넣어야함*/}
                }
            }
        TV[TVlength]=tmpisl; //TV에 tmpisl 대입
        TVlength++;  //TVlength 증가
        T[Tlength].left=tmpedge.left;
        T[Tlength].right=tmpedge.right;
        T[Tlength].u=tmpedge.u;
        T[Tlength].weight=tmpedge.weight; //tmp에있는 요소 T[Tlength]에 대입
        Tlength++//Tlength 증가
        i++//i증가
    }
        
}
cs




<Kruskal's Algorithm>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <stdio.h>
#include <stdlib.h>
 
typedef struct edge{ //edge 형 변수
    int left;  //int형변수 left,right,weight,u를 포함한다.
    int right;
    int weight;    
    int u; // 어떤 집합에 속할지 정해준다.
}edge;
 
void Kruskal(edge E[],edge T[]);
void select_sort(edge vector[],int size);
int notcycle(edge *e,edge T[]);
int makeuni(edge *e,edge T[]);
void jointuni(edge T[]);
 
int uni=0;   //전역변수, 집합의 이름(번호)를 정함
int Ecount=0//E의 인덱스
int Tlength=0//T의 길이(T에 원소 몇개인지)
edge T[6];    //edge형 배열 T 크기 6
edge E[9];    //edge형 배열 E 크기 9
int k;
 
int main(void)
{
    int i;    
    for(i=0;i<20;i++){
    T[i].left=-1;    T[i].right=-1;    T[i].u=-1;    T[i].weight=-1;} //T 초기화 (안나올 값으로)
    E[0].left=5;    E[0].right=0;    E[0].weight=10;    E[0].u=-1;
    E[1].left=0;    E[1].right=1;    E[1].weight=28;    E[1].u=-1;
    E[2].left=1;    E[2].right=2;    E[2].weight=16;    E[2].u=-1;
    E[3].left=2;    E[3].right=3;    E[3].weight=12;    E[3].u=-1;
    E[4].left=6;    E[4].right=3;    E[4].weight=18;    E[4].u=-1;
    E[5].left=4;    E[5].right=3;    E[5].weight=22;    E[5].u=-1;
    E[6].left=4;    E[6].right=6;    E[6].weight=24;    E[6].u=-1;
    E[7].left=5;    E[7].right=4;    E[7].weight=25;    E[7].u=-1;
    E[8].left=6;    E[8].right=1;    E[8].weight=14;    E[8].u=-1;  //교과서에 나온 것처럼 초기화
    Kruskal(E,T); //Kruscal 알고리즘 실행
    for(i=0;i<6;i++)
    {printf("%d %d %d %d\n",T[i].left,T[i].right,T[i].u,T[i].weight);} //출력으로 제대로 나왔나 확인
    return 0;
}
void Kruskal(edge E[],edge T[]){
edge temp;
select_sort(E,9); //E를 가중치의 크기대로 오름차순 정렬한다.
while((Tlength<6)&&(Ecount<9)){ //Tlength가 6보다 작고 Ecount가 9보다 작으면 루프 반복
temp.left=E[Ecount].left;temp.right=E[Ecount].right;temp.weight=E[Ecount].weight;    temp.u=E[Ecount].u; //temp의 각 요소에 E[Ecount]의 요소 대입
E[Ecount].left=-1;E[Ecount].right=-1;E[Ecount].weight=-1//E의 Ecount 원소는 삭제 (-1대입)
makeuni(&temp,T); //temp의 집합을 만들어준다.
jointuni(T); //같은 집합인데 번호가 다른 집합이 있으면 합해준다. temp를 제외한 T만 해준다. (cycle 검사때문에)
for(k=0;k<Tlength;k++){
    printf("T[%d].u=%d ",k,T[k].u);
}
printf("tmp.u : %d\n",temp.u); //T의 원소의 집합 번호와 temp의 집합 번호 확인
if(notcycle(&temp,T)) //싸이클이 생기지 않으면
{
T[Tlength].left=temp.left;T[Tlength].right=temp.right;T[Tlength].weight=temp.weight;    T[Tlength].u=temp.u; //T[Tlength]의 요소에 temp의 요소 대입
Tlength++;Ecount++//Tlength와 Ecount 하나씩 증가
}
else{Ecount++;} //싸이클이 생겼으면 Ecount만 증가
}}
 
void select_sort(edge vector[],int size){ //선택정렬 알고리즘 
    int i; int j; int temp; int index;
    for(i=0;i<size;i++)
    {
        index=i;
        for(j=i+1;j<size;j++)
        {
            if((vector[j].weight)<vector[index].weight){
            index=j;}
        }
        temp=vector[index].weight;
        vector[index].weight=vector[i].weight;
        vector[i].weight=temp;
        temp=vector[index].left;
        vector[index].left=vector[i].left;
        vector[i].left=temp;
        temp=vector[index].right;
        vector[index].right=vector[i].right;
        vector[i].right=temp;
    }
}
int notcycle(edge *e,edge T[]){ //간선이 cycle 형성 하는지 리턴값이 판별 1이면 notcycle, 0이면 cycle
    int check=0;
    int i;
    if(Tlength==0)  //Tlength가 0이면 1반환 
        return 1;
    for(i=0;i<Tlength;i++){ //i=0부터 Tlength 이전까지 반복
        if(e->u==T[i].u){ //e->u 와 T[i].u 가같으면 (집합이 같으면)
            if((e->left==T[i].left)||(e->left==T[i].right)||(e->right==T[i].left)||(e->right==T[i].right)){ //e의 left가 t의 left나 right와 같거나, e의 right가 t의 left나 right와 같거나
            check++;
            printf("Tlength=%d i=%d check=%d\n\n",Tlength,i,check);} //check 증가식
            if(check==2//즉 같은 집합 내에서 
            {return 0;}
        }}
    return 1;
}
int makeuni(edge *e,edge T[]){ //집합을 만드는 함수
    int i; int check=0;
    if(Tlength==0//Tlength가 0이면
    {e->u=uni++return e->u;} //e->u에 uni 대입하고 증가, e->u 리턴
    else{
        for(i=0;i<Tlength;i++)
        {
        if((e->left==T[i].left)||(e->left==T[i].right)||(e->right==T[i].left)||(e->right==T[i].right)) //e의 left가 t의 left나 right와 같거나, e의 right가 t의 left나 right와 같거나
        {check=1;    //check에 1 대입
        e->u=T[i].u; return e->u; //e->u 에 T[i].u 대입 (즉 둘은 같은 집합이됨) e->u 리턴
        break;}
        }
        if(check==0){ //check가 0이면
        e->u=uni++return e->u; //e->u에 uni대입하고 uni 증가시킴, e->u 리턴 (새로운집합)
        }}}
void jointuni(edge T[]){ //집합을 합치는 함수
    int i;
    for(i=0;i<Tlength;i++){ //i=0부터 Tlength 보다 작을때까지 반복
        if((T[i+1].left==T[i].left)||(T[i+1].left==T[i].right)||(T[i+1].right==T[i].left)||(T[i+1].right==T[i].right)){ //T[i+1]의 left가 T[i]의 left나 right와 같거나, T[i+1]의 right가 T[i]의 left나 right와 같거나,
            if(T[i+1].u<T[i].u)   //T[i+1].u가 T[i].u보다 작으면
                T[i].u=T[i+1].u; //T[i+1].u를 T[i].u에 대입
            else
                T[i+1].u=T[i].u; //작은 쪽으로 집합 번호를 매긴다.
        }}}
cs





반응형

+ Recent posts