무방향 그래프
VS 방향 그래프
무방향 그래프(Undirected Graph)
방향 그래프(Directed Graph)
가중치 그래프
가중치 그래프(Weighted Graph)
연결 그래프
VS 비연결 그래프
연결 그래프(Connected Graph)
비연결 그래프(Disconnected Graph)
완전 그래프
완전그래프(Complete Graph)
< 무방향 그래프 인접 행렬 표현>
if(간선 x,y가 그래프에 존재) M[x][y] = 1;
otherwise M[x][y] = 0
#include <stdio.h>
#include <stdlib.h>
#define VERTICES 6 //vertex 개수
void printIncidence(int ** g, int v) {
if (v < 1 || v > 6 ) {
printf("-1\n");
return;
}
for (int i = 1; i <= VERTICES; i++) {
if (g[v][i] != 0) printf(" %d %d", i, g[v][i]);
}
printf("\n");
}
void makeEdge(int** g, int v1, int v2, int w) {
if (v1 < 1 || v1 > VERTICES || v2 < 1 || v2 > VERTICES) {
printf("-1\n");
return;
}
//무방향그래프
g[v1][v2] = w;
g[v2][v1] = w;
}
void makeGraph(int** g) {
for (int i = 1; i <= VERTICES; i++) {
for (int j = 1; j <= VERTICES; j++) {
g[i][j] = 0;
}
}
//간선 삽입 예시
makeEdge(g, 1, 2, 1); // 1과 2 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 3, 1); // 1과 3 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 4, 1); // 1과 4 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 6, 2); // 1과 6 사이에 가중치 2인 간선 생성
makeEdge(g, 2, 3, 1);
makeEdge(g, 3, 5, 4);
makeEdge(g, 5, 5, 4);
makeEdge(g, 5, 6, 3);
}
int main() {
char c;
int v, v2, w;
int** g = (int *)malloc(sizeof(int*) * (VERTICES + 1));
for (int i = 1; i <= VERTICES; i++) {
g[i] = (int*)malloc(sizeof(int) * (VERTICES +1 ));
}
makeGraph(g);
return;
}
다음과 같이 표현 할 수 있다.
#include <stdio.h>
#include <stdlib.h>
#define VERTICES 6 //vertex 개수
typedef struct incidence {
int weight;
int vertex;
struct incidence* next;
}incidence;
typedef struct vertex {
incidence * head;
int vertex;
}vertex;
typedef struct graph {
vertex vertexs[VERTICES + 1];
}graph;
void printIncidence(graph* g, int v) {
incidence* temp;
if (v <= 0 || v > VERTICES) {
printf("-1\n");
return;
}
temp = g->vertexs[v].head->next;
while (temp) {
printf(" %d %d", temp->vertex, temp->weight);
temp = temp->next;
}
printf("\n");
}
void printGraph(graph* g) {
incidence* temp;
for (int i = 1; i <= VERTICES; i++) {
printf("graph < %d > : ", i);
temp = g->vertexs[i].head->next;
while (temp) {
printf(" %d", temp->vertex);
temp = temp->next;
}
printf("\n");
}
printf("\n");
}
//간선 삭제 수정 삽입 모두 가능 + 정점 크기 순으로 삽입됨
void makeEdge(graph* g, int v1, int v2, int w) {
incidence* temp1,* temp2;
incidence* new1, * new2;
incidence* prev1, * prev2;
int plus = 0;
temp1 = g->vertexs[v1].head;
temp2 = g->vertexs[v2].head;
// 정점 존재하지 않을 시 종료
if (v1 <= 0 || v1 > VERTICES || v2 <= 0 || v2 > VERTICES) {
printf("-1\n");
return;
}
prev1 = g->vertexs[v1].head;
prev2 = g->vertexs[v2].head;
//삭제의 경우
if (w == 0) {
while (temp1) {
if (temp1->vertex == v2) {
prev1->next = temp1->next;
free(temp1);
break;
}
prev1 = temp1;
temp1 = temp1->next;
}
while (temp2) {
if (temp2->vertex == v1) {
prev2->next = temp2->next;
free(temp2);
break;
}
prev2 = temp2;
temp2 = temp2->next;
}
return;
}
new1 = (incidence*)malloc(sizeof(incidence));
new1->vertex = v2;
new1->weight = w;
new1->next = NULL;
new2 = (incidence*)malloc(sizeof(incidence));
new2->vertex = v1;
new2->weight = w;
new2->next = NULL;
//삽입 or 수정
while (temp1) {
//삽입
if (temp1->vertex > v2) {
break;
}
//수정 (간선 가중치 수정도 가능)
if (temp1->vertex == v2) {
temp1->weight = w;
plus = 1;
break;
}
prev1 = temp1;
temp1 = temp1->next;
}
if (plus == 0) {
prev1->next = new1;
if (temp1 != NULL) {
new1->next = temp1;
}
}
while (temp2) {
//삽입
if (temp2->vertex > v1) {
break;
}
//수정 (간선 가중치 수정도 가능)
if (temp2->vertex == v1) {
temp2->weight = w;
plus = 1;
break;
}
prev2 = temp2;
temp2 = temp2->next;
}
if (plus == 0) {
prev2->next = new2;
if (temp2 != NULL) {
new2->next = temp2;
}
}
}
void makeGraph(graph * g) {
//초기화
for (int i = 1; i <= VERTICES; i++) {
g->vertexs[i].vertex = i;
g->vertexs[i].head = (incidence*)malloc(sizeof(incidence));
g->vertexs[i].head->vertex = 0;
g->vertexs[i].head->weight = 0;
g->vertexs[i].head->next = NULL;
}
//예시
makeEdge(g, 1, 2, 1); // 1과 2 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 3, 1); // 1과 3 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 4, 1); // 1과 4 사이에 가중치 1인 간선 생성
makeEdge(g, 1, 6, 2); // 1과 6 사이에 가중치 2인 간선 생성
makeEdge(g, 2, 3, 1);
makeEdge(g, 3, 5, 4);
makeEdge(g, 5, 5, 4);
makeEdge(g, 5, 6, 3);
}
뭐가 더 효율적인가?
=> 희소 그래프
만약 정점이 1000개가 있는데 간선은 10개 뿐인 그래프가 있다고 하자. 이렇게 간선의 수가 적은 그래프를 희소 그래프(sparse graph)라고 한다. 이를 행렬로 구현하기위해서는 10개의 간선을 나타내기 위해 1000x1000행렬을 사용해야한다. 하지만 인접 리스트로 구현시 1000 + 10개의 노드만 있으면 구현이 가능하다. 따라서 인접 리스트는 희소 그래프를 표현할때 적당하다.
=> 밀집 그래프
만약 정점이 1000개가 있는데 간선이 2000개가 있는 그래프가 있다고 하자. 이렇게 간선 수가 가 많은 그래프를 밀집 그래프(dense graph)라고 한다. 이때는 인접행렬로 그래프를 구현하는 것이 더 효과적이다. 왜냐하면 행렬은 인덱스로 바로 접근이 가능하기 때문이다