Skip to content

Commit

Permalink
Merge pull request #3 from deunlee/Study
Browse files Browse the repository at this point in the history
Add Graph and some refactoring
  • Loading branch information
deunlee committed May 30, 2020
2 parents e355fdd + 474e11b commit 97f8ad5
Show file tree
Hide file tree
Showing 22 changed files with 785 additions and 52 deletions.
10 changes: 10 additions & 0 deletions Data-Structure.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Deque", "Deque\Deque.vcxpro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LinkedList", "LinkedList\LinkedList.vcxproj", "{57412A8E-41D0-474D-B912-9AAB3EBDA451}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Graph", "Graph\Graph.vcxproj", "{6051C310-D82F-405A-A84D-64C9FD818FFE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -61,6 +63,14 @@ Global
{57412A8E-41D0-474D-B912-9AAB3EBDA451}.Release|x64.Build.0 = Release|x64
{57412A8E-41D0-474D-B912-9AAB3EBDA451}.Release|x86.ActiveCfg = Release|Win32
{57412A8E-41D0-474D-B912-9AAB3EBDA451}.Release|x86.Build.0 = Release|Win32
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Debug|x64.ActiveCfg = Debug|x64
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Debug|x64.Build.0 = Debug|x64
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Debug|x86.ActiveCfg = Debug|Win32
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Debug|x86.Build.0 = Debug|Win32
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Release|x64.ActiveCfg = Release|x64
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Release|x64.Build.0 = Release|x64
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Release|x86.ActiveCfg = Release|Win32
{6051C310-D82F-405A-A84D-64C9FD818FFE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
25 changes: 15 additions & 10 deletions Deque/Deque.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#ifndef __DEUN_DEQUE_CPP__
#define __DEUN_DEQUE_CPP__

#include "Deque.h"

namespace Deun {
Expand All @@ -8,7 +11,7 @@ namespace Deun {

if (!elements) {
this->size = 0;
throw DequeError::DEQUE_ALLOCATION_FAILED;
throw DequeError::MEMORY_ALLOCATION_FAILED;
}
}

Expand All @@ -35,7 +38,7 @@ namespace Deun {
// front : 채워진 상태 (단, count가 0이면 비워져 있음)
// rear : 비어있는 상태 (단, count가 size면 채워져 있음)

// front와 rear중 하나는 채워진 상태가, 나머지 하나는 비어있는 상태가 되도록 해야 함
// front와 rear 중 하나는 채워진 상태가, 나머지 하나는 비어있는 상태가 되도록 해야 함
// Deque을 Stack으로 사용하는 경우에는 둘 다 채워져 있거나 둘 다 비어있어도 되지만,
// Deque을 Queue로 사용하는 경우 맨 처음에 들어간 원소가 맨 처음으로 나오지 않게 됨

Expand All @@ -45,8 +48,8 @@ namespace Deun {
}

count++;
front = (size - 1 + front) % size; // 사실 안전한 방법은 아님
//front = (front - 1 + size) % size; // 이건 더 위험함 (front는 unsigned)
front = (size - 1 + front) % size; // 안전한 방법은 아님
//front = (front - 1 + size) % size; // 이건 더 위험함 (front는 unsigned임)
elements[front] = element;
return true;
}
Expand All @@ -65,7 +68,7 @@ namespace Deun {

int Deque::popFront() {
if (isEmpty()) {
throw DequeError::DEQUE_IS_EMPTY;
throw DequeError::ELEMENT_NOT_FOUND;
}

// 큐의 dequeue()와 동일
Expand All @@ -77,7 +80,7 @@ namespace Deun {

int Deque::popRear() {
if (isEmpty()) {
throw DequeError::DEQUE_IS_EMPTY;
throw DequeError::ELEMENT_NOT_FOUND;
}

count--;
Expand All @@ -87,28 +90,28 @@ namespace Deun {

int Deque::peekFront() {
if (isEmpty()) {
throw DequeError::DEQUE_IS_EMPTY;
throw DequeError::ELEMENT_NOT_FOUND;
}

return elements[front];
}

int Deque::peekRear() {
if (isEmpty()) {
throw DequeError::DEQUE_IS_EMPTY;
throw DequeError::ELEMENT_NOT_FOUND;
}

return elements[(size - 1 + rear) % size];
}

// for debug
void Deque::clear() {
count = front = rear = 0;

for (unsigned int i = 0; i < size; i++) {
elements[i] = 0;
}
}

// for debug
void Deque::print() {
using namespace std;

Expand All @@ -125,3 +128,5 @@ namespace Deun {
cout << endl;
}
}

#endif
27 changes: 13 additions & 14 deletions Deque/Deque.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#ifndef __DEUN_DEQUE__
#define __DEUN_DEQUE__
#ifndef __DEUN_DEQUE_H__
#define __DEUN_DEQUE_H__

#include <iostream>
#include <new>

namespace Deun {
enum class DequeError {
DEQUE_ALLOCATION_FAILED,
DEQUE_IS_EMPTY,
MEMORY_ALLOCATION_FAILED = 1000,
ELEMENT_NOT_FOUND,
};

// 배열 기반 원형 덱
Expand All @@ -20,7 +20,7 @@ namespace Deun {
unsigned int rear; // 원소를 삽입할 자리

public:
Deque(unsigned int size = 100);
Deque(unsigned int size = 1000);
~Deque();

bool isEmpty();
Expand All @@ -29,16 +29,15 @@ namespace Deun {
unsigned int getSize(); // 전체 크기 반환
unsigned int getCount(); // 채워진 원소의 개수 반환

bool pushFront(int element); // 맨 앞에 원소 삽입 (성공 = true, 실패 = false)
bool pushRear(int element); // 맨 뒤에 원소 삽입 (성공 = true, 실패 = false)
int popFront(); // 맨 앞 원소 반환 및 삭제 (실패 = throw)
int popRear(); // 맨 뒤 원소 반환 및 삭제 (실패 = throw)
int peekFront(); // 맨 앞 원소 반환 (실패 = throw)
int peekRear(); // 맨 뒤 원소 반환 (실패 = throw)
bool pushFront(int element); // 맨 앞에 원소 삽입 (성공 = true, 실패 = false)
bool pushRear(int element); // 맨 뒤에 원소 삽입 (성공 = true, 실패 = false)
int popFront(); // 맨 앞 원소 반환 및 삭제 (실패 = throw)
int popRear(); // 맨 뒤 원소 반환 및 삭제 (실패 = throw)
int peekFront(); // 맨 앞 원소 반환 (실패 = throw)
int peekRear(); // 맨 뒤 원소 반환 (실패 = throw)

// for debug
void clear();
void print();
void clear(); // O(n)
void print(); // O(n)
};
}

Expand Down
124 changes: 124 additions & 0 deletions Graph/AdjacencyList.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#ifndef __DEUN_GRAPH_ADJ_LIST_CPP__
#define __DEUN_GRAPH_ADJ_LIST_CPP__

#include "AdjacencyList.h"

namespace Deun {
AdjacencyList::AdjacencyList(int vSize) {
if (vSize <= 0) {
this->vSize = 0;
throw AdjacencyListError::MEMORY_ALLOCATION_FAILED;
}

this->vSize = vSize;
vCount = 0;
list = new (std::nothrow) ALNode*[vSize]; // 포인터 배열

if (!list) {
this->vSize = 0;
throw AdjacencyListError::MEMORY_ALLOCATION_FAILED;
}

for (int i = 0; i < vSize; i++) {
list[i] = nullptr;
}
}

AdjacencyList::~AdjacencyList() {
clear();
delete[] list;
}

int AdjacencyList::insertVertex() {
if (vCount < vSize) {
return vCount++;
}
throw AdjacencyListError::TOO_MANY_VERTICES;
}

bool AdjacencyList::insertEdge(int from, int to, bool undirected) {
if (from < 0 || from >= vCount || to < 0 || to >= vCount) {
return false;
}

if (from == to && undirected) { // 두 번 삽입되는 현상 방지
undirected = false;
}

ALNode* newNode = new (std::nothrow) ALNode[(undirected ? 2 : 1)];
if (!newNode) {
return false;
}

newNode[0].vertex = to;
newNode[0].next = list[from];
list[from] = &newNode[0];

if (undirected) { // 무방향 그래프 (from -> to와 to -> from 모두 삽입)
newNode[1].vertex = from;
newNode[1].next = list[to];
list[to] = &newNode[1];
}

return true;
}

bool AdjacencyList::hasVertex(int v) {
if (v >= 0 && v < vCount) {
return true;
}
return false;
}

bool AdjacencyList::hasEdge(int from, int to) {
if (from < 0 || from >= vCount || to < 0 || to >= vCount) {
return false;
}

ALNode* p = list[from];
while (p) {
if (p->vertex == to) {
return true;
}
p = p->next;
}
return false;
}

void AdjacencyList::clear() {
vCount = 0;
for (int i = 0; i < vSize; i++) {
ALNode* p = list[i];
ALNode* removed;
while (p) { // 연결된 노드 전부 삭제
removed = p;
p = p->next;
delete removed;
}
list[i] = nullptr;
}
}

void AdjacencyList::print() {
using namespace std;

cout << "AdjacencyList(vSize=" << vSize << ", vCount=" << vCount << ")" << endl;

if (vCount) {
for (int i = 0; i < vCount; i++) {
ALNode* p = list[i];
cout << i << " -> ";
while (p) {
cout << p->vertex << " -> ";
p = p->next;
}
cout << "null" << endl;
}
}
else {
cout << "(empty)" << endl;
}
}
}

#endif
90 changes: 90 additions & 0 deletions Graph/AdjacencyList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#ifndef __DEUN_GRAPH_ADJ_LIST_H__
#define __DEUN_GRAPH_ADJ_LIST_H__

#include <iostream>
#include <new>

namespace Deun {
enum class AdjacencyListError {
MEMORY_ALLOCATION_FAILED = 1000,
TOO_MANY_VERTICES,
};

typedef struct AdjacencyListNode {
int vertex;
struct AdjacencyListNode* next;
} ALNode;

/**
* 인접 리스트 그래프 (연결 리스트 기반)
*/
class AdjacencyList {
protected:
int vSize; // 정점의 최대 개수 (메모리 할당량)
int vCount; // 정점의 개수
ALNode** list; // 연결 리스트 (포인터 배열)

public:
/**
* 인접 리스트 생성자
*
* @param {int} vSize: 정점의 최대 개수
* @throw {AdjacencyListError} 메모리 할당 오류
*/
AdjacencyList(int vSize = 1000);

/**
* 인접 리스트 소멸자
*/
~AdjacencyList();

/**
* 정점을 삽입하고 삽입된 정점의 인덱스를 반환합니다.
*
* @return {int} 삽입된 정점의 인덱스(0-based)
* @throw {AdjacencyListError} 정점 개수 초과 오류
*/
int insertVertex();

/**
* 간선을 삽입하고 성공 여부를 반환합니다.
* 간선은 from과 to를 연결하며 방향성이 있습니다.
* undirected가 true인 경우에는 to와 from을 잇는 간선도 삽입합니다.
*
* @param {int} from: 시작 정점 인덱스(0-based)
* @param {int} to: 끝 정점 인덱스(0-based)
* @param {bool} undirected: 무방향 그래프 여부
* @return {bool} 성공 여부
*/
bool insertEdge(int from, int to, bool undirected = false);

/**
* 정점의 존재 여부를 반환합니다.
*
* @param {int} v: 정점 인덱스(0-based)
* @return {bool} 존재 여부
*/
bool hasVertex(int v);

/**
* 간선의 존재 여부를 반환합니다.
*
* @param {int} from: 시작 정점 인덱스(0-based)
* @param {int} to: 끝 정점 인덱스(0-based)
* @return {bool} 존재 여부
*/
bool hasEdge(int from, int to);

/**
* 인접 행렬을 초기화합니다.
*/
void clear();

/**
* 인접 행렬을 출력합니다.
*/
void print();
};
}

#endif
Loading

0 comments on commit 97f8ad5

Please sign in to comment.