2018년 6월 16일 토요일

그래프 ( Graph )

■ 설명

그래프는 노드 그리고 노드간 서로룰 잇는 간선(Edge)으로 이루어진 자료구조이다. 간선이 방향성을 가지느냐 아니냐에 따라 방향 그래프 혹은 무방향 그래프로 나뉘며 간선에 가중치가 있을 경우에는 가중 그래프(Weighted Graph)라 한다.

■ 구현 ( 설계 )

AddNode( key )
AddEdge( key_from, key_to )
DeleteNode( key )
DeleteEdge( key_from, to )

FindAdjacentNodes( key )

그래프의 노드를 추가하고 노드간 간선을 설정하여 인접 노드(Adjacent Node)들을 얻을수있는 무방향 그래프를 만들어보자.

■ 구현 ( 헤더 )

[Graph.h]

#pragma once
#include <list>
using namespace std;
typedef unsigned int SIZE;
typedef unsigned int KEY;
class Graph
{
private:
    KEY** nodeList = nullptr;
    bool** edgeList = nullptr;
    SIZE size = 0;
    SIZE capacity = 0;
private: 
    KEY* CreateNode(const KEY& key);
    bool FreeNode(const KEY& key);
private:
    bool CheckNodeExist(const KEY& key) const;
public:
    inline const SIZE& GetSize() const { return this->size; }
    void FindAdjacentNodes(const KEY& key, list<KEY>* nodes) const;
public:
    bool AddNode(const KEY& key);
    bool AddEdge(const KEY& key1, const KEY& key2);
    bool DeleteNode(const KEY& key);
    bool DeleteEdge(const KEY& key1, const KEY& key2);
private:
    Graph();
public:    
    ~Graph();
public:
    static Graph* Create(const SIZE& capacity);
    void Release();
};
순전히 블로그에 올릴용으로 만드는거라 자료를 많이 다룰일은없어 간선을 2차원 동적배열로 관리하기로했다. nodeList 도 더블 포인터인데 , nodeList는 2차원 동적배열로 쓸것이 아니라 1차원 포인터 배열로  쓸것이다.( 널값 여부로 해당 node가 존재하는지를 판단하기 위해 ) 

■ 구현 ( 코드 )

[Graph.cpp]

#include <memory.h>
#include "Graph.h"
KEY * Graph::CreateNode(const KEY & key)
{
    KEY* pkey = new KEY(key);
    this->size++;
    return pkey;
}
bool Graph::FreeNode(const KEY & key)
{
    if (!CheckNodeExist(key))
        return false;
    delete this->nodeList[key];
    this->nodeList[key] = nullptr;
    this->size--;
    return true;
}
bool Graph::CheckNodeExist(const KEY & key) const
{
    if (key >= this->capacity)
        return false;
    if (!this->nodeList[key])
        return false;
    return true;
}
void Graph::FindAdjacentNodes(const KEY& key, list<KEY>* nodes) const
{
    if (!CheckNodeExist(key))
        return;
    for (int i = 0; i < this->capacity; ++i)
    {
        if (this->edgeList[key][i])
        {
            nodes->push_back(i);
        }
    }
}
bool Graph::AddNode(const KEY & key)
{
    if (CheckNodeExist(key))
        return false;
    this->nodeList[key] = CreateNode(key);
    return true;
}
bool Graph::AddEdge(const KEY & key1, const KEY & key2)
{
    if (key1 == key2)
        return false;
    if (!CheckNodeExist(key1) || !CheckNodeExist(key2))
        return false;
    this->edgeList[key1][key2] = true;
    this->edgeList[key2][key1] = true;
    return true;
}
bool Graph::DeleteNode(const KEY & key)
{
    if (!CheckNodeExist(key))
        return false;
    for (SIZE i = 0; i < this->capacity; ++i)
    {
        DeleteEdge(key, i);
        DeleteEdge(i, key);
    }
    FreeNode(key);
    return true;
}
bool Graph::DeleteEdge(const KEY & key1, const KEY & key2)
{
    if (key1 == key2)
        return false;
    if (!CheckNodeExist(key1) || !CheckNodeExist(key2))
        return false;
    this->edgeList[key1][key2] = false;
    this->edgeList[key2][key1] = false;
    return true;
}
Graph::Graph()
{
}
Graph::~Graph()
{
}
Graph * Graph::Create(const SIZE & capacity)
{
    Graph* graph = new Graph;
    graph->Release();
    graph->nodeList = new KEY*[capacity];
    memset(graph->nodeList, 0, sizeof(KEY*)*capacity);
    graph->edgeList = new bool*[capacity];
    for (SIZE i = 0; i < capacity; ++i)
    {
        graph->edgeList[i] = new bool[capacity];
        memset(graph->edgeList[i], 0, sizeof(bool)*capacity);
    }
    graph->capacity = capacity;
    return graph;
}
void Graph::Release()
{
    if (this->nodeList)
    {
        for (SIZE i = 0; i < this->capacity; ++i)
        {
            delete this->nodeList[i];
        }
        delete[] this->nodeList;
        this->nodeList = nullptr;
    }
    if (this->edgeList)
    {
        for (SIZE i = 0; i < this->capacity; ++i)
        {
            delete[] this->edgeList[i];
        }
        delete[] this->edgeList;
        this->edgeList = nullptr;
    }
    this->capacity = 0;
}
소스 코드는 매우 간단하다. 주의해서 볼것은 무방향 이기때문에 간선 추가 및 삭제시 양뱡향에 대한 처리를 해주고 있다는 점이다.

■ 실행 결과

[Main.cpp]

#include <iostream>
#include "Graph.h"
using namespace std;
int main()
{
    Graph* graph = Graph::Create(10);
    graph->AddNode(0);
    graph->AddNode(1);
    graph->AddNode(2);
    graph->AddNode(3);
    graph->AddEdge(0, 1);
    graph->AddEdge(0, 2);
    graph->AddEdge(0, 3);
    graph->DeleteEdge(0, 1);
    list<KEY> nodes;
    graph->FindAdjacentNodes(0, &nodes);
    while(nodes.size())
    {
        cout << "0 node's adjacent node : " << nodes.front() << endl;
        nodes.pop_front();
    }
    graph->DeleteNode(0);
    graph->DeleteNode(1);
    cout << "Graph's size : " << graph->GetSize() << endl;
    
    graph->Release();
    delete graph;
    graph = nullptr;
    return 0;
}

■ 소스 코드



댓글 없음:

댓글 쓰기