//1 오른쪽에 있는거 위로 옮기기
else
{
pSuccessor = FindInOrderSuccessor(_target.m_TargetNode);
// 1
if (_target.m_TargetNode->IsRoot())
{
// 2
if (_target.m_TargetNode->HasLeftChild())
{
m_Root = _target.m_TargetNode->pLeftChild;
}
// 3
else
{
m_Root = _target.m_TargetNode->pRightChild;
}
// 4
m_Root->pParent = nullptr;
// 5
//delete _target.m_TargetNode;
}
// 6
else if (_target.m_TargetNode->IsLeftChild())
{
// 7
if (_target.m_TargetNode->HasLeftChild())
{
_target.m_TargetNode->pLeftChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pLeftChild = _target.m_TargetNode->pLeftChild;
}
// 8
else
{
_target.m_TargetNode->pRightChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pLeftChild = _target.m_TargetNode->pRightChild;
}
}
// 9
else
{
// 10
if (_target.m_TargetNode->HasLeftChild())
{
_target.m_TargetNode->pLeftChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pRightChild = _target.m_TargetNode->pLeftChild;
}
// 11
else
{
_target.m_TargetNode->pRightChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pRightChild = _target.m_TargetNode->pRightChild;
}
}
// 12
delete _target.m_TargetNode;
// 13
--m_CurCount;
// 14
return iterator(this, pSuccessor);
}
TestIter = bst.begin();
TestIter = bst.erase(TestIter);
TestIter = bst.erase(TestIter);
100
50 150
25 75 125 170
100
75 150
125 170
else if (_target.m_TargetNode->IsFull()) // 1
{
pSuccessor = FindInOrderSuccessor(_target.m_TargetNode); // 2
assert(pSuccessor); // 3
_target.m_TargetNode->pair = pSuccessor->pair; // 4
erase(iterator(this, pSuccessor)); // 5
return iterator(this, _target.m_TargetNode); // 6
}
TestIter = bst.find(100);
if (bst.end() != TestIter)
{
// 2.7
// 100을 erase로 지워죵.
bst.erase(TestIter);
}
(*TestIter).first;
(*TestIter).second;
.
으로 안에 값에 접근할수 있었다.// 3.2
struct test
{
int first;
int second;
};
int main()
{
test t = {};
test* pTest = &t;
// 1
(*pTest).first;
(*pTest).second;
// 2
pTest->first;
pTest->second;
return 0;
}
.
이고 포인터는 조금더 편하게 쓸려고 2번처럼 -> 를 사용 가능했당. TestIter->first;
TestIter->second;
const BSTPair<T1, T2>* operator-> ()
{
assert(m_Owner && m_TargetNode);
return &m_TargetNode->pair;
}
(TestIter->)->first;
(TestIter->)->second;
TestIter->first;
TestIter->second;
#include <iostream>
using std::cout;
using std::endl;
#include "BST.h"
template<typename T1, typename T2>
class MyTemplateClass
{
T1 m_Data1;
T2 m_Data2;
};
MyTemplateClass<int, float> obj;
#include <set>
#include <map>
using std::set;
using std::map;
using std::make_pair;
// 퀵소트, 머지소트, 힙소트
// O(N logN)
// 그래프 - 노드간의 연결관계를 표현
// 트리 - 순환이 불가능한 그래프
// 이진트리 - 자식의 개수를 2개로 제한한 트리
// 이진탐색트리 - 입력 데이터를 크기에 따라 좌우(작은것을 왼쪽, 큰것을 오른쪽)로 정렬하는 트리
// Self Balanced Binary Search Tree
// 자가균형 이진탐색트리
// Red-Black, AVL
// 탐색
// 순차 탐색 O(N)
// 이진 탐색 O(logN)
// - 데이터가 정렬되어있어야 한다.
// - N(문제의 크기) 을 절반씩 줄여나가는 방식
// 컨테이너 vector list map,set
// 자료구조 동적배열 연결형 리스트 이진탐색트리
// 입력 O(1) O(1) O(logN)
// 삭제 O(N) O(1) O(1)
// 인덱싱 O(1) O(N) O(N)
// 탐색 O(N) O(N) O(logN)
struct test
{
int first;
int second;
};
int main()
{
test t = {};
test* pTest = &t;
(*pTest).first;
(*pTest).second;
pTest->first;
pTest->second;
set<int> intset;
intset.insert(100);
intset.insert(150);
intset.insert(170);
intset.insert(125);
intset.insert(80);
intset.insert(90);
intset.insert(50);
// 100
// / \
// 80 150
// /\ /\
// 50 90 125 170
// find 함수는 입력된 데이터랑 동일한 데이터가 있는지 찾아서 그 데이터를 가리키는 iterator 를 반환.
// 만약 해당 데이터가 컨테이너 안에 없었으면, end iterator 를 반환
set<int>::iterator iter = intset.find(125);
iter = intset.find(124);
if (iter != intset.end())
{
}
else
{
}
// map 사용
map<int, int> intmap;
intmap.insert(make_pair(100, 1));
intmap.insert(make_pair(150, 2));
intmap.insert(make_pair(170, 3));
intmap.insert(make_pair(125, 4));
intmap.insert(make_pair(80, 5));
intmap.insert(make_pair(90, 6));
intmap.insert(make_pair(50, 7));
// 100-1
// / \
// 80-5 150-2
// / \ / \
// 50-7 90-6 125-4 170-3
map<int, int>::iterator mapiter = intmap.find(50);
if (mapiter != intmap.end())
{
(*mapiter).first;
(*mapiter).second;
}
// BST insert 테스트
BST<int, float> bst;
bst.insert(make_bstpair(100, 1.1f));
bst.insert(make_bstpair(150, 2.2f));
bst.insert(make_bstpair(50, 2.2f));
bst.insert(make_bstpair(170, 1.1f));
bst.insert(make_bstpair(125, 2.2f));
bst.insert(make_bstpair(25, 2.2f));
bst.insert(make_bstpair(75, 2.2f));
// 100
// 50 150
// 25 75 125 170
bst.Circit();
BST<int, float>::iterator myiter = bst.begin();
for (; myiter != bst.end(); ++myiter)
{
cout << (*myiter).first << endl;
}
myiter = bst.find(74);
BST<int, float>::iterator TestIter = bst.end();
--TestIter;
--TestIter;
--TestIter;
--TestIter;
--TestIter;
--TestIter;
--TestIter;
TestIter = bst.find(100);
(*TestIter).first;
(*TestIter).second;
TestIter->first;
TestIter->second;
if (bst.end() != TestIter)
{
bst.erase(TestIter);
}
return 0;
}
// 중위 선행자 구하기
// BST iterator -- 구현하기
// 1. erase 구현 마무리
// 2. iterator -> operator
#pragma once
#include <iostream>
#include <assert.h>
#include "List.h"
// Binary Search Tree(BST)
template<typename T1, typename T2>
struct BSTPair
{
T1 first;
T2 second;
BSTPair()
{}
BSTPair(const T1& _first, const T2& _second)
: first(_first)
, second(_second)
{
}
};
template<typename T1, typename T2>
struct BSTNode
{
BSTPair<T1, T2> pair;
BSTNode* pParent;
BSTNode* pLeftChild;
BSTNode* pRightChild;
bool HasRightChild() { return pRightChild; }
bool HasLeftChild() { return pLeftChild; }
bool IsLeftChild() { return pParent->pLeftChild == this; }
bool IsRightChild() { return pParent->pRightChild == this; }
bool IsRoot() { return !pParent; }
bool IsLeaf() { return !(pLeftChild || pRightChild); }
bool IsFull() { return pLeftChild && pRightChild; }
BSTNode()
: pParent(nullptr)
, pLeftChild(nullptr)
, pRightChild(nullptr)
{}
BSTNode(const BSTPair<T1, T2>& _pair, BSTNode* _Parent = nullptr, BSTNode* _LeftChild = nullptr, BSTNode* _RightChild = nullptr)
: pair(_pair)
, pParent(_Parent)
, pLeftChild(_LeftChild)
, pRightChild(_RightChild)
{}
};
template<typename T1, typename T2>
class BST
{
private:
BSTNode<T1, T2>* m_Root; // 루트 노드 주소
int m_CurCount; // 현재 데이터 개수
public:
void Circit()
{
Circit(m_Root);
}
private:
void Circit(BSTNode<T1, T2>* _Node);
public:
class iterator;
void insert(const BSTPair<T1, T2>& _pair);
iterator find(const T1& _key);
iterator erase(const iterator& _target);
iterator begin()
{
assert(m_Root);
BSTNode<T1, T2>* pNode = m_Root;
while (pNode->pLeftChild) { pNode = pNode->pLeftChild; }
return iterator(this, pNode);
}
iterator end()
{
return iterator(this, nullptr);
}
private:
// 중위 후속자, 선행자 찾기
BSTNode<T1, T2>* FindInOrderSuccessor(BSTNode<T1, T2>* _TargetNode);
BSTNode<T1, T2>* FindInOrderPredecessor(BSTNode<T1, T2>* _TargetNode);
public:
BST()
: m_Root(nullptr)
, m_CurCount(0)
{}
~BST()
{
// 모든 노드들을 삭제
// 재귀함수
// 레벨순회
List<BSTNode<T1, T2>*> queue;
queue.push_back(m_Root);
while (!queue.empty())
{
BSTNode<T1, T2>* pNode = queue.pop_front();
if (nullptr != pNode->pLeftChild)
queue.push_back(pNode->pLeftChild);
if (nullptr != pNode->pRightChild)
queue.push_back(pNode->pRightChild);
delete pNode;
}
}
class iterator
{
private:
BST* m_Owner;
BSTNode<T1, T2>* m_TargetNode;
wchar_t m_szDesc[6]; // 설명 정보
// end iterator 조건
// m_Owner 가 nullptr 이 아니고 m_TargetNode 가 nullptr 이면...
public:
const BSTPair<T1, T2>& operator* ()
{
assert(m_Owner && m_TargetNode);
return m_TargetNode->pair;
}
const BSTPair<T1, T2>* operator-> ()
{
assert(m_Owner && m_TargetNode);
return &m_TargetNode->pair;
}
bool operator == (const iterator& _otheriter)
{
if (m_Owner == _otheriter.m_Owner && m_TargetNode == _otheriter.m_TargetNode)
{
return true;
}
return false;
}
bool operator != (const iterator& _otheriter)
{
return !((*this) == _otheriter);
}
iterator& operator ++()
{
assert(m_Owner);
// 중위 후속자(InOrder Successor) 찾아서 가리킨다.
m_TargetNode = m_Owner->FindInOrderSuccessor(m_TargetNode);
if (nullptr == m_TargetNode)
{
wcscpy_s(this->m_szDesc, L"End");
}
return (*this);
}
iterator& operator--()
{
assert(m_Owner);
// 중위 선행자 찾아서 가리킨다.
m_TargetNode = m_Owner->FindInOrderPredecessor(m_TargetNode);
// 중위 선행자를 찾을수 없었다(nullptr)
// ==> Begin Iterator 에 -- 함수를 호출한 상황
assert(m_TargetNode);
// 찾은 중위선행자가 맨 처음이라면
if (!m_TargetNode->HasLeftChild())
{
wcscpy_s(m_szDesc, L"Begin");
}
else
{
// 상태설명 갱신
wcscpy_s(m_szDesc, L"");
}
return (*this);
}
public:
iterator()
: m_Owner(nullptr)
, m_TargetNode(nullptr)
, m_szDesc{}
{
wcscpy_s(m_szDesc, L"None");
}
iterator(BST* _Owner, BSTNode<T1, T2>* _Node)
: m_Owner(_Owner)
, m_TargetNode(_Node)
, m_szDesc{}
{
if (nullptr != m_Owner && nullptr == m_TargetNode)
{
wcscpy_s(m_szDesc, L"End");
}
}
friend class BST<T1, T2>;
};
};
// 입력된 T1, T2 타입의 데이터를 묶어서 BSTPair<T1, T2> 타입 구조체로 반환
template<typename T1, typename T2>
BSTPair<T1, T2> make_bstpair(const T1& _first, const T2& _second)
{
return BSTPair<T1, T2>(_first, _second);
}
template<typename T1, typename T2>
void BST<T1, T2>::insert(const BSTPair<T1, T2>& _pair)
{
BSTNode<T1, T2>* pNewNode = new BSTNode<T1, T2>(_pair);
// 최초로 데이터가 입력된 상황
if (nullptr == m_Root)
{
m_Root = pNewNode;
}
// 데이터가 2개 이상인 경우
else
{
BSTNode<T1, T2>* pNode = m_Root;
while (true)
{
// 입력된 first 값이 현재 노드의 first 값보다 작은 경우
if (pNewNode->pair.first < pNode->pair.first)
{
// 왼쪽이 비어있으면
if (nullptr == pNode->pLeftChild)
{
// 현재 노드의 왼쪽으로 연결
pNode->pLeftChild = pNewNode;
pNewNode->pParent = pNode;
break;
}
// 왼쪽으로 내려간다.
pNode = pNode->pLeftChild;
}
// 입력된 first 값이 현재 노드의 first 값보다 큰 경우
else if (pNode->pair.first < pNewNode->pair.first)
{
// 현재 노드의 오른쪽이 비어있으며
if (nullptr == pNode->pRightChild)
{
// 입력된 노드를 현재 노드의 오른쪽으로 연결
pNode->pRightChild = pNewNode;
pNewNode->pParent = pNode;
break;
}
// 오른쪽으로 내려간다.
pNode = pNode->pRightChild;
}
}
}
++m_CurCount;
}
template<typename T1, typename T2>
inline void BST<T1, T2>::Circit(BSTNode<T1, T2>* _Node)
{
if (nullptr == _Node)
{
return;
}
Circit(_Node->pLeftChild);
//std::cout << _Node->pair.first << std::endl;
Circit(_Node->pRightChild);
}
template<typename T1, typename T2>
typename BST<T1, T2>::iterator BST<T1, T2>::find(const T1& _key)
{
BSTNode<T1, T2>* pNode = m_Root;
while (pNode)
{
if (_key < pNode->pair.first)
{
pNode = pNode->pLeftChild;
}
else if (pNode->pair.first < _key)
{
pNode = pNode->pRightChild;
}
else
{
break;
}
}
return iterator(this, pNode);
}
template<typename T1, typename T2>
typename BST<T1, T2>::iterator BST<T1, T2>::erase(const iterator& _target)
{
BSTNode<T1, T2>* pSuccessor = nullptr;
// 삭제할 노드가 리프노드인 경우 (자식이 0개)
if (_target.m_TargetNode->IsLeaf())
{
// 삭제할 노드의 후속자를 찾는다.
pSuccessor = FindInOrderSuccessor(_target.m_TargetNode);
// 1. 삭제하려는 노드가 루트 노드인 경우
if (_target.m_TargetNode->IsRoot())
{
// 루트노드를 삭제하고, m_Root 포인터를 nullptr 로 변경한다.
delete m_Root;
m_Root = nullptr;
}
// 2. 루트노드는 아니다. (리프노드만)
else
{
// 부모 노드로 가서 삭제될 노드를 가리키는 포인터를 nullptr 로 변경한다.
if (_target.m_TargetNode->IsLeftChild())
{
_target.m_TargetNode->pParent->pLeftChild = nullptr;
}
else
{
_target.m_TargetNode->pParent->pRightChild = nullptr;
}
// 해당 노드를 메모리 해제한다.
delete _target.m_TargetNode;
}
// 데이터 개수를 하나 줄인다.
--m_CurCount;
// 삭제된 노드의 다음(후속자) 을 가리키는 iterator 를 반환해준다.
return iterator(this, pSuccessor);
}
// 자식이 2개 있는 경우
else if (_target.m_TargetNode->IsFull())
{
// 삭제할 노드의 후속자를 찾는다.
pSuccessor = FindInOrderSuccessor(_target.m_TargetNode);
assert(pSuccessor);
// 중위 후속자 노드의 데이터를 삭제할 노드의 데이터로 복사시킨다.
_target.m_TargetNode->pair = pSuccessor->pair;
// 자식이 2개인 노드의 후속자는 자식이 1개 또는 0개 이다.
// erase 함수를 재귀호출해서 자식이 1개 or 0 개인 노드를 삭제하는 부분을 해결한다.
// 이때 erase 안에서 데이터 개수를 줄이므로 여기서 다시 또 데이터개수를 줄일 필요가 없다.
erase(iterator(this, pSuccessor));
// 삭제된 노드의 후속자가 가진 데이터가 삭제할 노드로 복사되었기 때문에
// 원래 삭제하려고 했던 노드가 다시 삭제된 다음노드가 되었다.
return iterator(this, _target.m_TargetNode);
}
// 자식이 1개 있는 경우
else
{
pSuccessor = FindInOrderSuccessor(_target.m_TargetNode);
// 삭제할 노드가 루트인 경우
if (_target.m_TargetNode->IsRoot())
{
// 하나뿐인 자식을 루트로 만든다.
if (_target.m_TargetNode->HasLeftChild())
{
m_Root = _target.m_TargetNode->pLeftChild;
}
else
{
m_Root = _target.m_TargetNode->pRightChild;
}
m_Root->pParent = nullptr;
}
// 삭제할 노드가 왼쪽 자식이다.
else if (_target.m_TargetNode->IsLeftChild())
{
// 보유한 자식이 왼쪽 자식이다.
if (_target.m_TargetNode->HasLeftChild())
{
_target.m_TargetNode->pLeftChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pLeftChild = _target.m_TargetNode->pLeftChild;
}
// 보유한 자식이 오른쪽 자식이다.
else
{
_target.m_TargetNode->pRightChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pLeftChild = _target.m_TargetNode->pRightChild;
}
}
// 삭제할 노드가 오른쪽 자식이다.
else
{
if (_target.m_TargetNode->HasLeftChild())
{
_target.m_TargetNode->pLeftChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pRightChild = _target.m_TargetNode->pLeftChild;
}
else
{
_target.m_TargetNode->pRightChild->pParent = _target.m_TargetNode->pParent;
_target.m_TargetNode->pParent->pRightChild = _target.m_TargetNode->pRightChild;
}
}
// 해당 노드를 메모리 해제한다.
delete _target.m_TargetNode;
// 데이터 개수를 하나 줄인다.
--m_CurCount;
return iterator(this, pSuccessor);
}
}
template<typename T1, typename T2>
BSTNode<T1, T2>* BST<T1, T2>::FindInOrderSuccessor(BSTNode<T1, T2>* _TargetNode)
{
// 오른쪽 자식이 있으면
if (_TargetNode->HasRightChild())
{
// 오른쪽 자식으로 간다.
BSTNode<T1, T2>* pNextNode = _TargetNode->pRightChild;
// 왼쪽자식이 없을 때 까지 내려간다.
while (pNextNode->pLeftChild) { pNextNode = pNextNode->pLeftChild; }
return pNextNode;
}
// 오른쪽 자식이 없으면
else
{
BSTNode<T1, T2>* pNextNode = _TargetNode;
// 부모의 왼쪽 자식일때 까지 올라가서 그때 부모가 나의 중위 후속자
while (true)
{
if (pNextNode->IsRoot())
{
// 현재 노드가 가장 마지막 노드이다(중위 후속자를 찾기전에 루트노드에 도달)
// -> end iterator 로 변경
return nullptr;
}
else if (pNextNode->IsLeftChild())
{
return pNextNode->pParent;
}
else
{
pNextNode = pNextNode->pParent;
}
};
}
}
template<typename T1, typename T2>
BSTNode<T1, T2>* BST<T1, T2>::FindInOrderPredecessor(BSTNode<T1, T2>* _TargetNode)
{
// End Iterator 인데 -- 를 호출받은 경우
if (nullptr == _TargetNode)
{
BSTNode<T1, T2>* pNode = m_Root;
while (pNode->pRightChild) { pNode = pNode->pRightChild; }
return pNode;
}
// 중위 선행자(InOrder Predecessor)
// 왼쪽 자식이 있으면
else if (_TargetNode->HasLeftChild())
{
// 왼쪽 자식으로 간다.
BSTNode<T1, T2>* pNextNode = _TargetNode->pLeftChild;
// 오른쪽 자식이 없을 때 까지 내려간다.
while (pNextNode->pRightChild) { pNextNode = pNextNode->pRightChild; }
return pNextNode;
}
// 왼쪽 자식이 없으면
else
{
BSTNode<T1, T2>* pNextNode = _TargetNode;
// 부모의 오른쪽 자식일때 까지 올라가서, 그때 부모가 나의 중위 선행자
while (true)
{
if (pNextNode->IsRoot())
{
// 현재 노드가 가장 처음 노드이다(중위 선행자를 찾기전에 루트노드에 도달)
// -> assert, begin 이전으로 갈 수 없다.
return nullptr;
}
else if (pNextNode->IsRightChild())
{
return pNextNode->pParent;
}
else
{
pNextNode = pNextNode->pParent;
}
};
}
}
1차 24.01.10
2차 24.01.11
3차 24.01.12
4차 24.01.15
5차 24.01.16