-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[LinkedList] Add Singly-Linked-Lists
- Loading branch information
Showing
7 changed files
with
633 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#include "LinkedList.h" | ||
|
||
namespace Deun { | ||
LinkedList::LinkedList() { | ||
head = tail = NULL; | ||
count = 0; | ||
} | ||
|
||
LinkedList::~LinkedList() { | ||
Node* current = head; | ||
Node* next; | ||
while (current) { // 모두 삭제 | ||
next = current->link; | ||
delete current; | ||
current = next; | ||
} | ||
} | ||
|
||
// 인덱스 유효성 검증 | ||
bool LinkedList::isValid(unsigned int index) { | ||
// index는 0부터 시작하므로, count보다 작아야 함 | ||
return (index < count); | ||
} | ||
|
||
Node* LinkedList::getNode(unsigned int index) { | ||
if (!isValid(index)) { | ||
return NULL; | ||
} | ||
if (index + 1 == count) { | ||
return tail; | ||
} | ||
|
||
// index가 유효하다면, current는 항상 NULL이 아님 | ||
Node* current = head; | ||
for (unsigned int i = 0; i < index; i++) { | ||
current = current->link; | ||
} | ||
return current; | ||
} | ||
|
||
bool LinkedList::isEmpty() { | ||
return (count == 0); | ||
} | ||
|
||
unsigned int LinkedList::getCount() { | ||
return count; | ||
} | ||
|
||
// 삽입 | ||
bool LinkedList::insert(unsigned int index, int data) { | ||
if (index == 0) { // 맨 앞에 삽입 | ||
return insertFront(data); | ||
} | ||
else if (index == count) { // 맨 뒤에 삽입 | ||
return insertRear(data); | ||
} | ||
else if (!isValid(index)) { | ||
return false; | ||
} | ||
|
||
// 여기부터는 index가 1 이상임이 보장됨 | ||
Node* preNode = getNode(index - 1); | ||
Node* newNode = new (std::nothrow) Node; | ||
if (!newNode) { | ||
return false; // 메모리 할당 실패 | ||
} | ||
|
||
// head와 tail 포인터는 수정할 필요가 없음 | ||
// 수정이 필요한 경우는 insertFront()와 insertRear()에서 따로 처리함 | ||
newNode->data = data; | ||
newNode->link = preNode->link; | ||
preNode->link = newNode; | ||
count++; | ||
return true; | ||
} | ||
|
||
bool LinkedList::insertFront(int data) { | ||
Node* newNode = new (std::nothrow) Node; | ||
if (!newNode) { | ||
return false; // 메모리 할당 실패 | ||
} | ||
|
||
newNode->data = data; | ||
newNode->link = head; | ||
head = newNode; | ||
tail = (tail ? tail : newNode); // 노드가 하나인 경우 tail도 같게 함 | ||
count++; | ||
return true; | ||
} | ||
|
||
bool LinkedList::insertRear(int data) { | ||
Node* newNode = new (std::nothrow) Node; | ||
if (!newNode) { | ||
return false; // 메모리 할당 실패 | ||
} | ||
|
||
newNode->data = data; | ||
newNode->link = NULL; | ||
tail->link = newNode; | ||
tail = newNode; | ||
head = (head ? head : newNode); // 노드가 하나인 경우 head도 같게 함 | ||
count++; | ||
return true; | ||
} | ||
|
||
// 삭제 | ||
bool LinkedList::remove(unsigned int index) { | ||
if (index == 0) { // 맨 앞 노드 삭제 | ||
return removeFront(); | ||
} | ||
else if (!isValid(index)) { | ||
return false; | ||
} | ||
|
||
// 여기부터는 index가 1 이상임이 보장됨 | ||
Node* preNode = getNode(index - 1); | ||
Node* curNode = preNode->link; | ||
preNode->link = curNode->link; | ||
delete curNode; | ||
count--; | ||
if (!preNode->link) { // 삭제된 노드가 마지막 노드이면 tail 변경 | ||
tail = preNode; | ||
} | ||
return true; | ||
} | ||
|
||
bool LinkedList::removeFront() { | ||
if (!head) { | ||
return false; | ||
} | ||
|
||
Node* next = head->link; | ||
delete head; | ||
head = next; | ||
tail = (head ? tail : NULL); // 노드가 하나도 없는 경우 tail도 NULL로 변경 | ||
count--; | ||
return true; | ||
} | ||
|
||
bool LinkedList::removeRear() { | ||
// tail의 앞 노드를 저장해두지 않았기 때문에 O(1)로 삭제할 수 없음 | ||
return remove(count - 1); | ||
} | ||
|
||
// 조회 | ||
int LinkedList::get(unsigned int index) { | ||
Node* current = getNode(index); | ||
if (!current) { | ||
throw LinkedListError::NODE_NOT_FOUND; | ||
} | ||
return current->data; | ||
} | ||
|
||
int LinkedList::getFront() { | ||
if (!head) { | ||
throw LinkedListError::NODE_NOT_FOUND; | ||
} | ||
return head->data; | ||
} | ||
|
||
int LinkedList::getRear() { | ||
if (!tail) { | ||
throw LinkedListError::NODE_NOT_FOUND; | ||
} | ||
return tail->data; | ||
} | ||
|
||
// 수정 | ||
bool LinkedList::update(unsigned int index, int data) { | ||
Node* current = getNode(index); | ||
if (!current) { | ||
return false; | ||
} | ||
current->data = data; | ||
return true; | ||
} | ||
|
||
bool LinkedList::updateFront(int data) { | ||
if (!head) { | ||
return false; | ||
} | ||
head->data = data; | ||
return true; | ||
} | ||
|
||
bool LinkedList::updateRear(int data) { | ||
if (!tail) { | ||
return false; | ||
} | ||
tail->data = data; | ||
return true; | ||
} | ||
|
||
// 검색 | ||
unsigned int LinkedList::find(int data) { | ||
if (!head) { | ||
throw LinkedListError::NODE_NOT_FOUND; | ||
} | ||
|
||
Node* current = head; | ||
for (unsigned int i = 0; i < count; i++) { | ||
if (current->data == data) { | ||
return i; | ||
} | ||
current = current->link; | ||
} | ||
throw LinkedListError::NODE_NOT_FOUND; | ||
} | ||
|
||
// 출력 | ||
void LinkedList::print() { | ||
using namespace std; | ||
|
||
cout << "LinkedList(count=" << count; | ||
cout << ", head=0x" << head << ", tail=0x" << tail << ")" << endl; | ||
|
||
cout << "head -> "; | ||
Node* current = head; | ||
for (unsigned int i = 0; i < count; i++) { | ||
cout << i << "=" << current->data << "(0x" << current << ") -> "; | ||
current = current->link; | ||
} | ||
cout << "NULL" << endl; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#ifndef __DEUN_LINKED_LIST__ | ||
#define __DEUN_LINKED_LIST__ | ||
|
||
#include <iostream> | ||
#include <new> | ||
|
||
namespace Deun { | ||
enum class LinkedListError { | ||
NODE_NOT_FOUND = 1000, | ||
}; | ||
|
||
typedef struct Node { | ||
int data; | ||
struct Node* link; | ||
} Node; | ||
|
||
// 단순 연결 리스트 | ||
class LinkedList { | ||
private: | ||
Node* head; | ||
Node* tail; | ||
unsigned int count; | ||
|
||
bool isValid(unsigned int index); | ||
Node* getNode(unsigned int index); // O(n) | ||
|
||
public: | ||
LinkedList(); | ||
~LinkedList(); | ||
|
||
bool isEmpty(); | ||
unsigned int getCount(); | ||
|
||
// index: 0-based | ||
|
||
bool insert(unsigned int index, int data); // 특정 위치에 노드 삽입 (성공 = true, 실패 = false) | ||
bool insertFront(int data); // 맨 앞에 노드 삽입 (성공 = true, 실패 = false) | ||
bool insertRear(int data); // 맨 뒤에 노드 삽입 (성공 = true, 실패 = false) | ||
|
||
bool remove(unsigned int index); // 특정 위치 노드 제거 (성공 = true, 실패 = false) | ||
bool removeFront(); // 맨 앞 노드 제거 (성공 = true, 실패 = false) | ||
bool removeRear(); // 맨 뒤 노드 제거 (성공 = true, 실패 = false) | ||
|
||
int get(unsigned int index); // 특정 위치 노드 반환 (실패 = throw) | ||
int getFront(); // 맨 앞 노드 반환 (실패 = throw) | ||
int getRear(); // 맨 뒤 노드 반환 (실패 = throw) | ||
|
||
bool update(unsigned int index, int data); // 특정 위치 노드 수정 (성공 = true, 실패 = false) | ||
bool updateFront(int data); // 맨 앞 노드 수정 (성공 = true, 실패 = false) | ||
bool updateRear(int data); // 맨 뒤 노드 수정 (성공 = true, 실패 = false) | ||
|
||
unsigned int find(int data); // 주어진 값과 일치하는 첫 번째 노드의 인덱스 반환 (실패 = throw) | ||
void print(); // 현재 상태 출력 | ||
|
||
// 시간 복잡도 | ||
|
||
// insert() insertFront() insertRear() | ||
// O(n) O(1) O(1) | ||
|
||
// remove() removeFront() removeRear() | ||
// O(n) O(1) O(n) | ||
|
||
// get() getFront() getRear() | ||
// O(n) O(1) O(1) | ||
|
||
// update() updateFront() updateRear() | ||
// O(n) O(1) O(1) | ||
|
||
// find() | ||
// O(n) | ||
|
||
// removeRear()가 O(n)인 이유는 tail의 앞 노드를 알 수 없기 때문임 | ||
// tail의 link는 사용하지 않으므로, link를 tail의 앞 노드로 설정하면 | ||
// O(1)에 삭제가 가능하게 바꿀 수 있을 것 같음 (TODO?) | ||
}; | ||
} | ||
|
||
#endif |
Oops, something went wrong.