[알고리즘 C언어] 7.4.2 크루스칼 알고리즘 소스 코드

다음은 C언어로 작성한 크루스칼(Kruskal) 알고리즘 소스 코드입니다. 크루스칼 알고리즘은 대표적인 탐욕 알고리즘으로 그래프에서 최소신장트리를 만드는 알고리즘입니다.

//Array.h
#pragma once
typedef void * Element;
typedef struct _Array Array;
struct _Array
{
	Element *base;
	int capacity;
	int usage;
};
typedef Element *Iterator;

Array *New_Array();
void Delete_Array(Array *arr);
void Array_SetSize(Array *arr,int capacity,Element data);
void Array_PushBack(Array *arr,Element data);
void Array_Insert(Array *arr,Iterator pos,Element data);
void Array_SetAt(Array *arr,int index,Element data);
Element Array_GetAt(Array *arr,int index);
Iterator Array_Begin(Array *arr);
Iterator Array_End(Array *arr);
void Array_Erase(Array *arr,Iterator pos);
//Array.c
#include "Array.h"
#include <malloc.h>
#include <memory.h>
Array *New_Array()
{
	Array *arr = 0;
	arr = (Array *)malloc(sizeof(Array));
	arr->base = 0;
	arr->capacity = arr->usage = 0;
	return arr;
}
void Delete_Array(Array *arr)
{
	if(arr->base)
	{
		free(arr->base);
	}
	free(arr);
}
void Array_SetSize(Array *arr,int capacity,Element data)
{		
	arr->capacity = capacity;
	arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
	for(    ;arr->usage<arr->capacity; arr->usage++)
	{
		arr->base[arr->usage] = data;
	}
}
void Array_PushBack(Array *arr,Element data)
{
	Iterator at = Array_End(arr);
	Array_Insert(arr,at,data);
}
void Array_Insert(Array *arr,Iterator pos,Element data)
{
	int index = pos - arr->base;
	int mcount = arr->usage - index;
	if(arr->capacity == arr->usage)
	{
		if(arr->capacity)
		{
			arr->capacity*=2;
		}
		else
		{
			arr->capacity = 1;
		}
		arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
	}
	memcpy(arr->base+index+1,arr->base+index,sizeof(Element)*mcount);
	arr->base[index] = data;
	arr->usage++;
}
void Array_SetAt(Array *arr,int index,Element data)
{
	if((index>=0)&&(index<arr->usage))
	{
		arr->base[index] = data;
	}
}
Element Array_GetAt(Array *arr,int index)
{
	if((index>=0)&&(index<arr->usage))
	{
		return arr->base[index];
	}
	return 0;
}
Iterator Array_Begin(Array *arr)
{
	return arr->base;
}
Iterator Array_End(Array *arr)
{
	return arr->base+arr->usage;
}
void Array_Erase(Array *arr,Iterator pos)
{
	int index = pos - arr->base;
	int mcount = arr->usage - index -1;
	memcpy(pos,pos+1,sizeof(Element)*mcount);
	arr->usage--;
}
//Graph.h
#pragma once
#include "Array.h"
typedef const char * Vertex;
typedef struct _Edge Edge;
struct _Edge
{
	Vertex ep1;
	Vertex ep2;
	int weight;
};

typedef struct _Graph Graph;
struct _Graph
{
	Array *vertexs;
	Array *edges;
};

Graph *New_Graph();
void Delete_Graph(Graph *graph);
int Graph_AddVertex(Graph *graph,Vertex pt);
int Graph_AddEdge(Graph *graph,Vertex ep1, Vertex ep2, int weight);
int Graph_ExistVertex(Graph *graph,Vertex pt);
int Graph_ExistEdge(Graph *graph,Vertex ep1, Vertex ep2);
void Graph_View(Graph *graph);
void Graph_ViewVertexs(Graph *graph);
void Graph_ViewEdges(Graph *graph);
void Graph_FindNeighvor(Graph *graph,Vertex ep, Array *neighvor);
int Graph_GetWeight(Graph *graph,Vertex ep1, Vertex ep2);
int Graph_GetVtCnt(Graph *graph);
Vertex Graph_GetFront(Graph *graph);
int Edge_Include(Edge *edge,Vertex pt);
//Graph.c
#include "Graph.h"
#include <malloc.h>
#include <string.h>
#include <stdio.h>
Edge *New_Edge(Vertex ep1, Vertex ep2, int weight)
{
	Edge *edge = 0;
	edge = (Edge *)malloc(sizeof(Edge));
	edge->ep1 = ep1;
	edge->ep2 = ep2;
	edge->weight = weight;
	return edge;
}
Vertex Edge_AnOther(Edge *edge,Vertex pt)
{
	if(strcmp(edge->ep1,pt)==0)
	{
		return edge->ep2;
	}
	if(strcmp(edge->ep2,pt)==0)
	{
		return edge->ep1;
	}
	return "";
}
int Edge_Include(Edge *edge,Vertex pt)
{
	return (strcmp(edge->ep1,pt)==0)||(strcmp(edge->ep2,pt)==0);
}
Graph *New_Graph()
{
	Graph *graph = 0;
	graph = (Graph *)malloc(sizeof(Graph));
	graph->vertexs = New_Array();
	graph->edges = New_Array();
	return graph;
}
void Delete_Graph(Graph *graph)
{
	Iterator seek = 0, end = 0;
	Edge *edge = 0;
	seek = Array_Begin(graph->edges);
	end = Array_End(graph->edges);
	for(seek = seek; seek != end; ++seek)
	{
		edge = (Edge *)(*seek);
		free(edge);
	}
	Delete_Array(graph->vertexs);
	Delete_Array(graph->edges);
	free(graph);
}
int Graph_AddVertex(Graph *graph,Vertex pt)
{
	if(Graph_ExistVertex(graph,pt))
	{
		return 0;
	}
	Array_PushBack(graph->vertexs,(Element)pt);
	return 1;
}
int Graph_AddEdge(Graph *graph,Vertex ep1, Vertex ep2, int weight)
{
	if(Graph_ExistVertex(graph,ep1) && Graph_ExistVertex(graph,ep2))
	{
		Edge *edge = 0;
		if(Graph_ExistEdge(graph,ep1,ep2))
		{
			return 0;
		}
		edge = New_Edge(ep1,ep2,weight);
		Array_PushBack(graph->edges,edge);
		return 1;
	}
	return 0;
}
int Graph_ExistVertex(Graph *graph,Vertex pt)
{
	Iterator seek = 0, end = 0;
	Vertex stored_pt = 0;
	seek = Array_Begin(graph->vertexs);
	end = Array_End(graph->vertexs);
	for(seek = seek; seek != end; ++seek)
	{
		stored_pt = (Vertex)(*seek);
		if(strcmp(stored_pt,pt)==0)
		{
			return 1;
		}
	}
	return 0;
}
int Graph_ExistEdge(Graph *graph,Vertex ep1, Vertex ep2)
{
	Iterator seek = 0, end = 0;
	Edge *stored_eg = 0;
	seek = Array_Begin(graph->edges);
	end = Array_End(graph->edges);
	for(seek = seek; seek != end; ++seek)
	{
		stored_eg = (Edge *)(*seek);
		if(Edge_Include(stored_eg,ep1)&&Edge_Include(stored_eg,ep2))
		{
			return 1;
		}
	}
	return 0;	
}
void Graph_View(Graph *graph)
{
	Graph_ViewVertexs(graph);
	Graph_ViewEdges(graph);
}
void Graph_ViewVertexs(Graph *graph)
{
	Iterator seek = 0, end = 0;
	Vertex pt = 0;
	printf("정점 개수:%d\n",graph->vertexs->usage);
	seek = Array_Begin(graph->vertexs);
	end = Array_End(graph->vertexs);
	for(seek = seek; seek != end; ++seek)
	{
		pt = (Vertex)(*seek);
		printf("%s\n",pt);
	}	
}
void Graph_ViewEdges(Graph *graph)
{
	Iterator seek = 0, end = 0;
	Edge *edge = 0;
	printf("간선 개수:%d\n",graph->edges->usage);
	seek = Array_Begin(graph->edges);
	end = Array_End(graph->edges);
	for(seek = seek; seek != end; ++seek)
	{
		edge = (Edge *)(*seek);
		printf("(%s ,%s):%d\n",edge->ep1,edge->ep2,edge->weight);
	}	
}
void Graph_FindNeighvor(Graph *graph,Vertex ep, Array *neighvor)
{
	Iterator seek = 0, end = 0;
	Edge *edge = 0;
	
	seek = Array_Begin(graph->edges);
	end = Array_End(graph->edges);
	for(seek = seek; seek != end; ++seek)
	{
		edge = (Edge *)(*seek);
		if(Edge_Include(edge,ep))
		{
			Vertex opt;
			opt = Edge_AnOther(edge,ep);
			Array_PushBack(neighvor,(Element)opt);
		}
	}	
}
int Graph_GetWeight(Graph *graph,Vertex ep1, Vertex ep2)
{
	Iterator seek = 0, end = 0;
	Edge *edge = 0;
	
	seek = Array_Begin(graph->edges);
	end = Array_End(graph->edges);
	for(seek = seek; seek != end; ++seek)
	{
		edge = (Edge *)(*seek);
		if(Edge_Include(edge,ep1)&&Edge_Include(edge,ep2))
		{
			return edge->weight;
		}
	}	
	return -1;
}
int Graph_GetVtCnt(Graph *graph)
{
    return graph->vertexs->usage;
}
Vertex Graph_GetFront(Graph *graph)
{
    Iterator front = Array_Begin(graph->vertexs);
    return (Vertex)front;
}
//Kruskal.h
#pragma once
#include "Graph.h"
Graph *Kruskal(Graph *origin);
//Kruskal.c
#include "Kruskal.h"
#include "Graph.h"
#include <stdio.h>
void SelectVertex(Graph *mstree,Graph *origin);
Array *MakeSortedEdges(Array *edges);
void SelectEdge(Array *graphs,Array *sorted_edges);
Graph *Kruskal(Graph *origin)
{
    Array *sorted_edges=0;
    Array *graphs=0;
    int vt_cnt_mone = 0;
    int ed_cnt=0;

    graphs = New_Array();
    sorted_edges = MakeSortedEdges(origin->edges);
    vt_cnt_mone = Graph_GetVtCnt(origin)-1;
    while(ed_cnt<vt_cnt_mone)
    {
        SelectEdge(graphs,sorted_edges);
        ed_cnt++;
    }
    return (Graph *)(*Array_Begin(graphs));
}


void AddEdge(Array *sorted_edge,Edge *edge);
Array *MakeSortedEdges(Array *edges)
{
    Array *sorted_edges = New_Array();
    Iterator seek = 0, end = 0;
    Edge *edge = 0;
    seek = Array_Begin(edges);
    end = Array_End(edges);
    
    for(seek = seek; seek != end; ++seek)
    {
        edge =  (Edge *)(*seek);
        AddEdge(sorted_edges,edge);
    }
    return sorted_edges;
}
void AddEdge(Array *sorted_edges,Edge *edge)
{
    Iterator seek = 0, end = 0;
    Edge *stored_edge = 0;
    seek = Array_Begin(sorted_edges);
    end = Array_End(sorted_edges);
    
    for(seek = seek; seek != end; ++seek)
    {
        stored_edge =  (Edge *)(*seek);
        if(edge->weight < stored_edge->weight)
        {
            break;
        }
    }
    Array_Insert(sorted_edges,seek,edge);
}

int GreedyEdge(Edge *edge,Array *graphs);
void SelectEdge(Array *graphs,Array *sorted_edges)
{    
    Edge *edge = 0;
    int i = 0;    
    for(i=0; i<sorted_edges->usage;i++)
    {        
        edge =  (Edge *)Array_GetAt(sorted_edges,i);
        if(GreedyEdge(edge,graphs))
        {
            return;
        }
        else
        {
            Array_Erase(sorted_edges,sorted_edges->base+i);
            i--;
        }
    }
}
void Merge_Graph(Graph *graph1,Graph *graph2);
int GreedyEdge(Edge *edge,Array *graphs)
{
    Graph *graph=0;
    Graph *graph2=0;
    Iterator a=0;
    Iterator seek = 0, end = 0;    

    seek = Array_Begin(graphs);
    end = Array_End(graphs);
    for(seek = seek; seek != end; ++seek)
    {        
        graph  =  (Graph *)(*seek);
        if(Graph_ExistVertex(graph,edge->ep1))
        {            
            if(Graph_ExistVertex(graph,edge->ep2))
            {
                return 0;
            }
            else
            {
                if(a==0)
                {                    
                    a=seek;
                }
                else
                {
                    Array_Erase(graphs,seek);
                    break;
                }
            }
        }
        else
        {
            if(Graph_ExistVertex(graph,edge->ep2))
            {
                if(a==0)
                {
                    a=seek;
                }
                else
                {
                    Array_Erase(graphs,seek);
                    break;
                }
            }           
        }
    }
    if(a==0)
    {
        graph2 = New_Graph();  
        Array_PushBack(graphs,graph2);
    }
    else 
    {
        graph2 = (Graph *)(*a);
        if(seek!=end)
        {   
            Merge_Graph(graph2,graph);                                                                 
        }        
    }
    printf("%s,%s : %d\n",edge->ep1,edge->ep2,edge->weight);
    Graph_AddVertex(graph2,edge->ep1);
    Graph_AddVertex(graph2,edge->ep2);
    Graph_AddEdge(graph2,edge->ep1,edge->ep2,edge->weight);
    return 1;
}
void Merge_Graph(Graph *graph1,Graph *graph2)
{
    Iterator seek = 0, end = 0;  
    Edge *ed=0;
    seek = Array_Begin(graph2->vertexs);
    end = Array_End(graph2->vertexs);
    for(seek = seek; seek != end; ++seek)
    {
        Graph_AddVertex(graph1,(Vertex)(*seek));        
    }
    seek = Array_Begin(graph2->edges);
    end = Array_End(graph2->edges);
    for(seek = seek; seek != end; ++seek)
    {
        ed = (Edge *)(*seek);
        Graph_AddEdge(graph1,ed->ep1,ed->ep2,ed->weight);
    }
}
//Program.c
#include "Kruskal.h"
Graph * InitSimulation();
int main()
{
    Graph *origin = 0;
    Graph *mstree = 0;

    origin = InitSimulation();
    mstree = Kruskal(origin);
    Graph_View(mstree);

    Delete_Graph(origin);
    Delete_Graph(mstree);
    return 0;
}
Graph * InitSimulation()
{
    Graph *graph = New_Graph();		
    Graph_AddVertex(graph,"A");
    Graph_AddVertex(graph,"B");
    Graph_AddVertex(graph,"C");
    Graph_AddVertex(graph,"D");
    Graph_AddVertex(graph,"E");
    Graph_AddVertex(graph,"F");
    Graph_AddVertex(graph,"G");
    Graph_AddVertex(graph,"H");
    
    Graph_AddEdge(graph,"A","B",5);
    Graph_AddEdge(graph,"A","D",3);
    Graph_AddEdge(graph,"A","E",4);
    Graph_AddEdge(graph,"B","D",3);
    Graph_AddEdge(graph,"B","H",2);
    Graph_AddEdge(graph,"C","D",3);
    Graph_AddEdge(graph,"C","G",4);
    Graph_AddEdge(graph,"D","H",5);
    Graph_AddEdge(graph,"D","E",3);
    Graph_AddEdge(graph,"D","F",3);
    Graph_AddEdge(graph,"E","F",2);
    Graph_AddEdge(graph,"F","G",6);
    Graph_AddEdge(graph,"G","H",3);
    
    Graph_View(graph);	
    return graph;		
}
크루스칼 알고리즘
크루스칼 알고리즘

▷ 실행 결과

정점 개수:8
A
B
C
D
E
F
G
H
간선 개수:13
(A ,B):5
(A ,D):3
(A ,E):4
(B ,D):3
(B ,H):2
(C ,D):3
(C ,G):4
(D ,H):5
(D ,E):3
(D ,F):3
(E ,F):2
(F ,G):6
(G ,H):3
B,H : 2
E,F : 2
A,D : 3
B,D : 3
C,D : 3
D,E : 3
G,H : 3
정점 개수:8
B
H
A
D
C
E
F
G
간선 개수:7
(B ,H):2
(A ,D):3
(B ,D):3
(C ,D):3
(E ,F):2
(D ,E):3
(G ,H):3