Linkedlist.h (템플릿으로 구현해서 헤더파일에 구현까지 넣음)
#pragma once
template <typename T>
class CNode
{
// 생성자, 소멸자를 privated으로 두고 CLinkedlist를 friend로 선언해서
// 외부에선 생성못하고 CLinkedlist만 생성할 수 있도록 함
private:
CNode() {}
~CNode() {}
private:
template <typename T>
friend class CLinkedlist;
template <typename T>
friend class CIterator;
private:
CNode<T>* m_Next;
CNode<T>* m_Prev;
T m_Data;
};
template <typename T>
class CIterator
{
private:
template <typename T>
friend class CLinkedlist;
public:
CIterator() :
m_Node(nullptr)
{
}
~CIterator()
{
}
private:
CNode<T>* m_Node;
public:
void operator ++ ()
{
m_Node = m_Node->m_Next;
}
void operator ++ (int)
{
m_Node = m_Node->m_Next;
}
void operator -- ()
{
m_Node = m_Node->m_Prev;
}
void operator -- (int)
{
m_Node = m_Node->m_Prev;
}
bool operator == (const CIterator<T>& iter) const
{
return m_Node == iter.m_Node;
}
bool operator != (const CIterator<T>& iter) const
{
return m_Node != iter.m_Node;
}
T& operator * () const
{
return m_Node->m_Data;
}
};
template <typename T>
class CLinkedlist
{
public:
CLinkedlist()
{
m_Head = new NODE;
m_Tail = new NODE;
m_Head->m_Next = m_Tail;
m_Tail->m_Prev = m_Head;
m_Head->m_Prev = nullptr;
m_Tail->m_Next = nullptr;
}
~CLinkedlist()
{
PNODE DeleteNode = m_Head;
PNODE NextDeleteNode = DeleteNode->m_Next;
while (DeleteNode)
{
delete DeleteNode;
DeleteNode = NextDeleteNode;
NextDeleteNode = NextDeleteNode->m_Next;
}
}
private:
// 자주 사용하는 타입을 typedef으로 재정의
typedef CNode<T>* PNODE;
typedef CNode<T> NODE;
// main에서도 쓸 수 있어야하니 public으로
public:
typedef CIterator<T> iterator;
private:
// Head를 의미하는 더미노드
PNODE m_Head;
// Tail을 의미하는 더미노드
PNODE m_Tail;
// 더미노드를 제외한 노드 개수
int m_Count;
public:
int size() const
{
return m_Count;
}
iterator GetHead() const
{
iterator iter;
iter.m_Node = m_Head;
return iter;
}
iterator GetTail() const
{
iterator iter;
iter.m_Node = m_Tail;
return iter;
}
iterator begin() const
{
iterator iter;
iter.m_Node = m_Head->m_Next;
return iter;
}
iterator end() const
{
iterator iter;
iter.m_Node = m_Tail;
return iter;
}
const T& back() const
{
iterator iter = end();
--iter;
return iter.m_Node->m_Data;
}
const T& front() const
{
iterator iter = begin();
return iter.m_Node->m_Data;
}
public:
void push_back(const T& data)
{
PNODE NewNode = new NODE;
NewNode->m_Data = data;
// 원래 링크드 리스트의 가장 뒤 노드
PNODE PushPrev = m_Tail->m_Prev;
PushPrev->m_Next = NewNode;
m_Tail->m_Prev = NewNode;
NewNode->m_Next = m_Tail;
NewNode->m_Prev = PushPrev;
++m_Count;
}
void push_front(const T& data)
{
PNODE NewNode = new NODE;
NewNode->m_Data = data;
// 원래 링크드 리스트의 가장 앞에 노드
PNODE PushNext = m_Head->m_Next;
PushNext->m_Prev = NewNode;
m_Head->m_Next = NewNode;
NewNode->m_Prev = m_Head;
NewNode->m_Next = PushNext;
++m_Count;
}
void pop_back()
{
// pop_back할 노드가 없으면 바로 종료
if (empty())
return;
PNODE DeleteNode = m_Tail->m_Prev;
PNODE DeletePrev = DeleteNode->m_Prev;
DeletePrev->m_Next = m_Tail;
m_Tail->m_Prev = DeletePrev;
DeleteNode->m_Next = nullptr;
DeleteNode->m_Prev = nullptr;
delete DeleteNode;
--m_Count;
}
void pop_front()
{
// pop_back할 노드가 없으면 바로 종료
if (empty())
return;
PNODE DeleteNode = m_Head->m_Next;
PNODE DeleteNext = DeleteNode->m_Next;
DeleteNext->m_Prev = m_Head;
m_Head->m_Next = DeleteNext;
DeleteNode->m_Next = nullptr;
DeleteNode->m_Prev = nullptr;
delete DeleteNode;
--m_Count;
}
void clear()
{
if (empty())
return;
// m_Head, m_Tail을 제외하고 모든 노드를 삭제
PNODE DeleteNode = m_Head->m_Next;
PNODE NextNode = DeleteNode->m_Next;
while (DeleteNode != GetTail().m_Node)
{
NextNode = DeleteNode->m_Next;
delete DeleteNode;
DeleteNode = NextNode;
}
}
bool empty() const
{
return m_Count == 0;
}
// data를 갖고 있는 첫번째 노드의 iterator 리턴
iterator find(const T& data)
{
iterator iter = begin();
iterator iterEnd = end();
for (; iter != iterEnd; ++iter)
{
if (*iter == data)
{
return iter;
}
}
// 만약 없다면 end() 리턴
return iterEnd;
}
// const T&로 인자타입을 설정해야한다.
// 그렇게 해야 int num = 3; erase(num);처럼 lvalue를 인자타입으로 줄 수 있을 뿐만 아니라
// erase(80)처럼 rvalue도 인자타입으로 줄 수 있다.
iterator erase(const T& data)
{
iterator iter = find(data);
if (iter == end())
return iter;
return erase(iter);
}
// 노드를 지우는 함수
// 만약 없는 노드를 지우려고 하거나, 더미노드를 지우려고하면 tail노드 리턴
// 정상적으로 지웠다면 지운 다음 노드를 리턴
iterator erase(const iterator& iter)
{
if (iter == GetHead() || iter == GetTail())
return GetTail();
PNODE EraseNode = iter.m_Node;
PNODE ErasePrev = EraseNode->m_Prev;
PNODE EraseNext = EraseNode->m_Next;
ErasePrev->m_Next = EraseNext;
EraseNext->m_Prev = ErasePrev;
delete EraseNode;
--m_Count;
iterator ret;
ret.m_Node = EraseNext;
return ret;
}
void sort(bool (*pFunc)(const T&, const T&))
{
iterator iter1 = begin();
iterator iter1End = end();
--iter1End;
iterator iter2;
iterator iter2End = end();
for (; iter1 != iter1End; ++iter1)
{
iter2 = iter1;
++iter2;
for (; iter2 != iter2End; ++iter2)
{
if (pFunc(*iter1, *iter2))
{
T data = *iter1;
*iter1 = *iter2;
*iter2 = data;
}
}
}
}
};
main.cpp
#include <iostream>
#include "Linkedlist.h"
#include <time.h>
#include <vector>
// 오름차순 정렬을 위한 compare 함수
bool SortInt(const int& data1, const int& data2)
{
return data1 > data2;
}
int main()
{
srand((unsigned int)time(0));
rand();
//MyInt Test = 100;
CLinkedlist<int> listInt;
CLinkedlist<float> listFloat;
for (int i = 0; i < 100; ++i)
{
listInt.push_back(i + 1);
}
std::cout << listInt.back() << std::endl;
std::cout << listInt.front() << std::endl;
CLinkedlist<int>::iterator iter;
iter = listInt.erase(80);
std::cout << "Delete Next Node Data : " << *iter << std::endl;
int num = 1;
iter = listInt.erase(num);
std::cout << "Delete Next Node Data : " << *iter << std::endl;
listInt.clear();
for (int i = 0; i < 100; ++i)
{
listInt.push_back(rand() % 1000);
}
std::cout << "======= Before =======" << std::endl;
for (iter = listInt.begin(); iter != listInt.end(); ++iter)
{
std::cout << *iter << std::endl;
}
listInt.sort(SortInt);
std::cout << "======= After =======" << std::endl;
for (iter = listInt.begin(); iter != listInt.end(); ++iter)
{
std::cout << *iter << std::endl;
}
return 0;
}
출력 결과를 보면 랜덤한 값을 넣은 링크드 리스트에 sort함수를 이용해서 오름차순으로 정렬까지 잘 되어 있음을 확인할 수 있다.
'공부 > Data Structure' 카테고리의 다른 글
자료구조 별 장단점(vector, list, queue, stack, map, hash map, tree) (0) | 2022.09.15 |
---|---|
해시 테이블(Hash Table) (0) | 2021.08.12 |
AVL Tree (0) | 2021.08.06 |
이진 탐색 트리(Binary Search Tree), 화살표 연산자 오버로딩(-> operator overloading, arrow operator overloading) (0) | 2021.08.06 |