어떤 개념의 하위 개념을 표현한다. 어떤 개념 안에 있는 멤버 변수들을 개념 안에 묶는다.
인벤토리라는 개념이 있을 때, 그 인벤토리라는 개념 안에 인텐토리 아이콘이라는 개념이 속한다.
Class 안에 Inner Class를 만들 수 있다. InventoryIcon 클래스를 Inventory 클래스 내에서만 사용하고 싶다면 private, 외부에서도 InventoryIcon 클래스를 사용한다면 public으로 두면 된다.
#include<vector>
class Image {
};
class Inventory {
public:
class InventoryIcon {
Image Image;
int Count;
};
std::vector<InventoryIcon> Icons;
};
int main()
{
Inventory Inventory;
Inventory::InventoryIcon Icon;
}
Inner Class에서 바깥 클래스의 변수 사용 불가하다. 그냥 밖에 있는 클래스랑 다를 게 없음.
https://learn.microsoft.com/ko-kr/cpp/cpp/friend-cpp?view=msvc-170
헤더 #include <list>
안에 더미노드방식으로 ListNode 만들어서 사용한다.
End 노드의 Prev에 새로운 데이터를 넣겠다.
새로운 노드의 Prev는 무조건 End의 Prev.
void push_back(const DataType& _Data){
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
//새로운 노드의 Prev는 항상 바뀐다.
NewNode->Next = End;
NewNode->Prev = End->Prev;
// 새로 생긴 노드의 앞과 뒤에게 이제 자신이 그들의 앞과 뒤라는 것을 알려준다.
ListNode* PrevNode = NewNode->Prev; // 내 앞
ListNode* NextNode = NewNode->Next; // 내 뒤
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
Start 노드의 Next에 새로운 데이터를 넣겠다.
(과제1에 자세히)
std의 거의 모든 자료구조는 iterator 라는 통일된 인터페이스를 사용한다.
이유는 순회를 돌리는 방식이 각 자료구조마다 다르기 때문이다.
그 인터페이스를 순회를 돌려주는 순회자라는 클래스를 만들고 똑같은 방식으로 이용하게 해서 진입장벽을 낮춘 것이다.
class MyList
{
private:
class ListNode
{
public:
DataType Data = DataType();
ListNode* Next = nullptr;
ListNode* Prev = nullptr;
};
public:
class iterator
{
public:
iterator(ListNode* _CurNode)
: CurNode(_CurNode)
{
}
bool operator!=(const iterator& _Other)
{
return CurNode != _Other.CurNode;
}
DataType& operator*()
{
return CurNode->Data;
}
void operator++()
{
CurNode = CurNode->Next;
}
private:
ListNode* CurNode = nullptr;
};
MyList()
{
Start->Next = End;
End->Prev = Start;
}
iterator begin()
{
return iterator(Start->Next);
}
iterator end()
{
return iterator(End);
}
/* MyList 구현 내용 일부 생략 */
}
protected:
private:
ListNode* Start = new ListNode();
ListNode* End = new ListNode();
};
MyList::iterator StartIter = NewList.begin();
MyList::iterator EndIter = NewList.end();
for ( ; StartIter != EndIter; ++StartIter)
{
std::cout << *StartIter << std::endl;
// std::cout << StartIter .operator*() << std::endl;
}
Start부터 End까지 다 지워야 함
~MyList() {
ListNode* Node = Start;
while (Node != nullptr) {
ListNode* tmp = Node->Next;
delete Node;
Node = tmp;
}
Node = nullptr;
}
std::cout << "내 리스트" << std::endl;
MyList NewList = MyList();
for (int i = 0; i < 10; i++)
{
NewList.push_front(i);
// NewList.push_front();
}
MyList::iterator StartIter = NewList.begin();
MyList::iterator EndIter = NewList.end();
// 안된다.,
//NewList[5];
StartIter = NewList.erase(StartIter);
for (/*std::list<int>::iterator StartIter = NewList.begin()*/
; StartIter != EndIter
; ++StartIter
)
{
int& Value = *StartIter;
StartIter.operator*();
StartIter.operator*() += 10;
StartIter.operator*() += 20;
std::cout << *StartIter << std::endl;
// std::cout << StartIter.operator*() << std::endl;
}
트리 구조
연관 컨테이너, 노드형
트리 구조 노드 중에서 자식의 개수가 2개일 때 2진 트리
라고 한다.
노드를 넣을 때 크기 비교를 하게 되면 써치 트리
라고 한다.
→ Map은 2진 써치 트리
그 중에도
→ 레드블랙 바이너리 써치트리
(= 레드블랙트리)
Map은 기본적으로 (속도보다)탐색과 정렬에 특화되어 있는 자료구조입니다.
트리의 기본적인 단점은 편향트리가 생길 수 있다는 점이다.
레드블랙 알고리즘은 스핀이라는 알고리즘을 통해서 트리의 균형을 잡아준다.
→ 레드블랙 자가균형 2진 트리
라고 부른다.
언리얼에서는 모든 자료구조가 전부 배열형 메모리를 가진 자료구조이다. 노드형이 없다고 한다. 신기함..
// in MyList class
void push_back(const DataType& _Data)
{
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Next = End;
NewNode->Prev = End->Prev;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
// Start의 Next에 새로운 데이터를 넣겠다.
void push_front(const DataType& _Data)
{
// 역함수
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Prev = Start;
NewNode->Next = Start->Next;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
모든 노드를 지워줘야 하는데 지우고 나면 Node->Next를 알 수 없으므로 임시로 받아두는 포인터를 만들었다.
~MyList() {
ListNode* Node = Start;
while (Node != nullptr) {
ListNode* tmp = Node->Next;
delete Node;
Node = tmp;
}
Node = nullptr;
}
iterator 클래스를 복사해서 reverse_iterator 클래스를 만들었다. 그 안에서 operator++와 rbegin(), rend()를 조금 수정했다.
#include <iostream>
#include <list>
#include <ConsoleEngine/EngineDebug.h>
typedef int DataType;
class MyList
{
private:
class ListNode
{
public:
DataType Data = DataType();
ListNode* Next = nullptr;
ListNode* Prev = nullptr;
};
public:
class iterator
{
friend MyList;
public:
iterator()
{
}
iterator(ListNode* _CurNode)
: CurNode(_CurNode)
{
}
bool operator!=(const iterator& _Other)
{
return CurNode != _Other.CurNode;
}
DataType& operator*()
{
return CurNode->Data;
}
// 연산자 겹지정 중에
void operator++()
{
CurNode = CurNode->Next;
}
private:
ListNode* CurNode = nullptr;
};
class reverse_iterator
{
friend MyList;
public:
reverse_iterator()
{
}
reverse_iterator(ListNode* _CurNode)
: CurNode(_CurNode)
{
}
bool operator!=(const reverse_iterator& _Other)
{
return CurNode != _Other.CurNode;
}
DataType& operator*()
{
return CurNode->Data;
}
// 연산자 겹지정 중에
void operator++()
{
CurNode = CurNode->Prev;
}
private:
ListNode* CurNode = nullptr;
};
MyList()
{
Start->Next = End;
End->Prev = Start;
}
~MyList()
{
ListNode* CurNode = Start;
while (CurNode)
{
ListNode* Next = CurNode->Next;
if (nullptr != CurNode)
{
delete CurNode;
CurNode = Next;
}
}
}
iterator begin()
{
return iterator(Start->Next);
}
iterator end()
{
return iterator(End);
}
reverse_iterator rbegin() {
return reverse_iterator(End->Prev);
}
reverse_iterator rend() {
return reverse_iterator(Start);
}
// End의 Prev에 새로운 데이터를 넣겠다.
void push_back(const DataType& _Data)
{
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Next = End;
NewNode->Prev = End->Prev;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
// Start의 Next에 새로운 데이터를 넣겠다.
void push_front(const DataType& _Data)
{
// 역함수
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Prev = Start;
NewNode->Next = Start->Next;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
iterator erase(iterator& _Iter)
{
if (_Iter.CurNode == Start)
{
MsgBoxAssert("Start를 삭제하려고 했습니다.");
}
if (_Iter.CurNode == End)
{
MsgBoxAssert("End를 삭제하려고 했습니다.");
}
iterator ReturnIter;
if (nullptr != _Iter.CurNode)
{
ReturnIter = iterator(_Iter.CurNode->Next);
ListNode* PrevNode = _Iter.CurNode->Prev;
ListNode* NextNode = _Iter.CurNode->Next;
PrevNode->Next = NextNode;
NextNode->Prev = PrevNode;
if (nullptr != _Iter.CurNode)
{
delete _Iter.CurNode;
_Iter.CurNode = nullptr;
}
}
return ReturnIter;
}
protected:
private:
ListNode* Start = new ListNode();
ListNode* End = new ListNode();
};
int main()
{
LeakCheck;
{
std::cout << "std 리스트" << std::endl;
std::list<int> NewList = std::list<int>();
// 0, 1, 2, 3, 4
for (int i = 0; i < 5; i++)
{
NewList.push_back(i);
// NewList.push_front();
}
std::list<int>::reverse_iterator rStartIter = NewList.rbegin();
std::list<int>::reverse_iterator rEndIter = NewList.rend();
for (/*std::list<int>::iterator StartIter = NewList.begin()*/
; rStartIter != rEndIter
; ++rStartIter)
{
std::cout << *rStartIter << std::endl;
}
}
{
std::cout << "내 리스트" << std::endl;
MyList NewList = MyList();
for (int i = 0; i < 5; i++) {
NewList.push_back(i);
}
MyList::reverse_iterator rStartIter = NewList.rbegin();
MyList::reverse_iterator rEndIter = NewList.rend();
for (; rStartIter != rEndIter; ++rStartIter) {
std::cout << *rStartIter << std::endl;
}
}
}
선생님은 iterator와 reverse_iterator의 공통된 부분을 iterator_Base 클래스로 뽑아 상속시켰다.
#include <iostream>
#include <list>
#include <ConsoleEngine/EngineDebug.h>
typedef int DataType;
// template<typename DataType>
class MyList
{
private:
class ListNode
{
public:
DataType Data = DataType();
ListNode* Next = nullptr;
ListNode* Prev = nullptr;
};
private:
class iterator_Base
{
public:
iterator_Base()
{
}
iterator_Base(ListNode* _CurNode)
: CurNode(_CurNode)
{
}
bool operator!=(const iterator_Base& _Other)
{
return CurNode != _Other.CurNode;
}
DataType& operator*()
{
return CurNode->Data;
}
public:
ListNode* CurNode = nullptr;
};
public:
class iterator : public iterator_Base
{
public:
iterator()
{
}
iterator(ListNode* _CurNode)
: iterator_Base(_CurNode)
{
}
// 연산자 겹지정 중에
void operator++()
{
CurNode = CurNode->Next;
}
};
class reverse_iterator : public iterator_Base
{
friend MyList;
public:
reverse_iterator()
{
}
reverse_iterator(ListNode* _CurNode)
: iterator_Base(_CurNode)
{
}
void operator++()
{
CurNode = CurNode->Prev;
}
protected:
};
MyList()
{
Start->Next = End;
End->Prev = Start;
}
~MyList()
{
ListNode* CurNode = Start;
while (CurNode)
{
ListNode* Next = CurNode->Next;
if (nullptr != CurNode)
{
delete CurNode;
CurNode = Next;
}
}
}
iterator begin()
{
return iterator(Start->Next);
}
iterator end()
{
return iterator(End);
}
// End의 Prev에 새로운 데이터를 넣겠다.
void push_back(const DataType& _Data)
{
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Next = End;
NewNode->Prev = End->Prev;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
// Start의 Next에 새로운 데이터를 넣겠다.
void push_front(const DataType& _Data)
{
// 역함수
ListNode* NewNode = new ListNode();
NewNode->Data = _Data;
NewNode->Prev = Start;
NewNode->Next = Start->Next;
ListNode* PrevNode = NewNode->Prev;
ListNode* NextNode = NewNode->Next;
PrevNode->Next = NewNode;
NextNode->Prev = NewNode;
}
iterator erase(iterator& _Iter)
{
if (_Iter.CurNode == Start)
{
MsgBoxAssert("Start를 삭제하려고 했습니다.");
}
if (_Iter.CurNode == End)
{
MsgBoxAssert("End를 삭제하려고 했습니다.");
}
iterator ReturnIter;
if (nullptr != _Iter.CurNode)
{
ReturnIter = iterator(_Iter.CurNode->Next);
ListNode* PrevNode = _Iter.CurNode->Prev;
ListNode* NextNode = _Iter.CurNode->Next;
PrevNode->Next = NextNode;
NextNode->Prev = PrevNode;
if (nullptr != _Iter.CurNode)
{
delete _Iter.CurNode;
_Iter.CurNode = nullptr;
}
}
return ReturnIter;
}
reverse_iterator rbegin()
{
return reverse_iterator(End->Prev);
}
reverse_iterator rend()
{
return reverse_iterator(Start);
}
protected:
private:
ListNode* Start = new ListNode();
ListNode* End = new ListNode();
};
int main()
{
LeakCheck;
{
std::cout << "std 리스트" << std::endl;
std::list<int> NewList = std::list<int>();
// 0, 1, 2, 3, 4
for (int i = 0; i < 5; i++)
{
NewList.push_back(i);
// NewList.push_front();
}
std::list<int>::reverse_iterator rStartIter = NewList.rbegin();
std::list<int>::reverse_iterator rEndIter = NewList.rend();
for (/*std::list<int>::iterator StartIter = NewList.begin()*/
; rStartIter != rEndIter
; ++rStartIter)
{
std::cout << *rStartIter << std::endl;
}
}
{
std::cout << "내 리스트" << std::endl;
MyList NewList = MyList();
// 0, 1, 2, 3, 4
for (int i = 0; i < 5; i++)
{
NewList.push_back(i);
// NewList.push_front();
}
MyList::reverse_iterator rStartIter = NewList.rbegin();
MyList::reverse_iterator rEndIter = NewList.rend();
for (/*std::list<int>::iterator StartIter = NewList.begin()*/
; rStartIter != rEndIter
; ++rStartIter)
{
std::cout << *rStartIter << std::endl;
}
}
}