이야기박스
c++) 스플레이 트리 (Splay Tree) 본문
반응형
Splay Tree 코드 게시글입니다.
지난번에 포스팅했던, AVL 트리 코드를 거의 그대로 가져다 썼습니다. ㅎㅎ
그래서 쓰지 않는 메서드들도 꽤 있네요 ㅎㅎ ㅜㅜ
정리가 좀 안된 감이 있지만, 코드 자체가 쉬우니 금방 이해하실 수 있을겁니다.
코드
- main.cpp
#include "Splay.h" #include <ctime> #include <cstdlib> #define NUM 6 int main() { srand((unsigned int)time(nullptr)); cout << "Splay Tree Test Start !!! " << endl; Splay splayT((int)(rand() % 20 + 1)); cout << "root : " << splayT.getRoot()->data << endl; splayT.print(splayT.getRoot()); for (int i = 0; i < NUM; ++i) { int t = (int)(rand() % 20 + 1); cout << endl << endl << "this turn's value : " << t << endl; splayT.insertItem(t); cout << "root : " << splayT.getRoot()->data << endl; splayT.print(splayT.getRoot()); } cout << endl << endl << "Splay Tree Result !!! " << endl; cout << "root : " << splayT.getRoot()->data << endl; splayT.print(splayT.getRoot()); // find cout << endl << endl << endl << "Splay Tree Find Test !!!" << endl; while (1) { int n; cout << "this turn find value(0 : end the program) : "; cin >> n; if (n == 0) break; splayT.findElement(n); cout << "root : " << splayT.getRoot()->data << endl; } // remove cout << endl << endl << endl << "Splay Tree Remove Test !!!" << endl; while (1) { int n; cout << "this turn remove value(0 : end the program) : "; cin >> n; if (n == 0) break; splayT.removeElement(n); cout << "root : " << splayT.getRoot()->data << endl; splayT.print(splayT.getRoot()); cout << endl; } return 0; }
- Splay.h
#pragma once #include <iostream> #include <algorithm> #include <iomanip> #include <queue> using namespace std; // 노드 정보 typedef struct Node { Node *parent = nullptr; Node *leftc = nullptr; Node *rightc = nullptr; int data = NULL; } Node; // Splay Tree Class class Splay { Node *root; public: Splay(); Splay(int element); // 핵심 매서드 void insertItem(int element); void removeElement(int element); void findElement(int element); Node *treeSearch(Node *now, int element); // 트리 기본 매서드 void expand(Node *external, int element); Node *reduce(Node *external); Node *inOrderSuc(Node *now); int depth(Node *now); int height(Node *now); // Splay 트리 매서드 void doSplay(Node *now); // rotate void rightRotate(Node *x, Node *y); void leftRotate(Node *x, Node *y); // 트리 boolean 매서드 bool isRoot(Node *tmp); bool isExternal(Node *tmp); // get Node *getRoot(); // print void display(); void print(Node *p); }; // 생성자 Splay::Splay() {} // 루트 초기화 생성자 Splay::Splay(int element) { root = new Node; root->data = element; root->parent = nullptr; root->leftc = new Node; root->rightc = new Node; root->leftc->parent = root; root->rightc->parent = root; } /* ** 핵심 메서드 */ // 노드 삽입 void Splay::insertItem(int element) { Node *tmp = treeSearch(root, element); if (isExternal(tmp)) { expand(tmp, element); doSplay(tmp); } } // 노드 삭제 void Splay::removeElement(int element) { Node *tmp = treeSearch(root, element); if (isExternal(tmp)) { cout << " No Such Key" << endl; return; } // first step // 삭제 Node *child = tmp->leftc; if (!isExternal(child)) { child = tmp->rightc; } Node *zs; // 둘 중 하나라도 외부노드라면 if (isExternal(child)) { zs = reduce(child); } // 둘 다 내부노드라면 else { // 중위 순회 계승자 // inOrder Successor child = inOrderSuc(tmp); Node *y = child->parent; // y 값 tmp 위치에 복사 (제거하려는 노드 위치에) tmp->data = y->data; // child, y 제거 zs = reduce(child); } // 부모 splay doSplay(zs->parent); } // 사전 검색 void Splay::findElement(int element) { Node *tmp = treeSearch(root, element); // 값이 없다면 if (isExternal(tmp)) { cout << "No Such Key" << endl; // 부모를 Splay doSplay(tmp->parent); } // 값이 있다면 else { cout << "fond element " << tmp->data << endl; // 자신을 스플레이 doSplay(tmp); } } // 트리 검색 // 원소의 위치를 반환 Node *Splay::treeSearch(Node *now, int element) { if (element == now->data) return now; Node *tmp = nullptr; if (element < now->data) { tmp = now->leftc; } else { tmp = now->rightc; } if (isExternal(tmp)) return tmp; treeSearch(tmp, element); } /* ** 트리 기본 매서드 */ // 내부 노드로 확장 void Splay::expand(Node *external, int element) { external->data = element; external->leftc = new Node; external->rightc = new Node; external->leftc->parent = external; external->rightc->parent = external; } // 노드 제거 Node *Splay::reduce(Node *external) { Node *w = external->parent; Node *g = w->parent; // sibling Node *zs; if (external == w->leftc) { zs = w->rightc; } else { zs = w->leftc; } // connect with grandparent; zs->parent = g; if (w == g->leftc) { g->leftc = zs; } else { g->rightc = zs; } // deallocate delete external; delete w; return zs; } // 중위 순휘 계승자 Node *Splay::inOrderSuc(Node *now) { Node *tmp = now->rightc; while (!isExternal(tmp)) { tmp = tmp->leftc; } return tmp; } // 깊이를 반환 int Splay::depth(Node *now) { int ret = 0; while (!isRoot(now)) { now = now->parent; ++ret; } return ret; } // 노드의 높이를 반환 int Splay::height(Node *now) { int h = 0; int left = 0, right = 0; if (now->leftc->data != NULL) { left = height(now->leftc); } if (now->rightc->data != NULL) { right = height(now->rightc); } int maxHeight = max(left, right); h = 1 + maxHeight; return h; } /* ** Splay 트리 매서드 */ void Splay::doSplay(Node *now) { // 예외처리 if (now == nullptr) return; // 루트에 도착하면 종료 if (isRoot(now)) { root = now; return; } // 부모가 루트인가? if (isRoot(now->parent)) { if (now == now->parent->leftc) { rightRotate(now, root); } else { leftRotate(now, root); } root = now; return; } // 나머지 경우 Node *p = now->parent; Node *gp = p->parent; if (now == gp->leftc->leftc) { rightRotate(p, gp); rightRotate(now, p); } else if (now == gp->rightc->rightc) { leftRotate(p, gp); leftRotate(now, p); } else if (now == gp->rightc->leftc) { rightRotate(now, p); leftRotate(now, gp); } else { leftRotate(now, p); rightRotate(now, gp); } // recur doSplay(now); } /* ** Rotate */ // Right void Splay::rightRotate(Node *x, Node *y) { y->leftc = x->rightc; x->rightc->parent = y; x->parent = y->parent; if (y->parent != nullptr) { if (y == y->parent->leftc) y->parent->leftc = x; else y->parent->rightc = x; } x->rightc = y; y->parent = x; } // Left void Splay::leftRotate(Node *x, Node *y) { y->rightc = x->leftc; x->leftc->parent = y; x->parent = y->parent; if (y->parent != nullptr) { if (y == y->parent->leftc) y->parent->leftc = x; else y->parent->rightc = x; } x->leftc = y; y->parent = x; } /* ** 트리 boolean 매서드 */ // 루트인가? bool Splay::isRoot(Node *tmp) { return tmp->parent == nullptr; } // 외부 노드인가? bool Splay::isExternal(Node *tmp) { return tmp->data == NULL; } // get Node *Splay::getRoot() { return root; } // 출력 // inorder void Splay::print(Node *p) { if (!isExternal(p->leftc)) print(p->leftc); cout << p->data << " "; if (!isExternal(p->rightc)) print(p->rightc); } // 트리 모양 출력 void Splay::display() { int n = depth(root); int width = 40; queue<Node*> level; level.push(root); cout << "***********************************************************************" << endl; while (!level.empty()) { if (n != depth(level.front())) { n = depth(level.front()); width /= 2; cout << endl; } Node *now = level.front(); if (now->leftc != nullptr) level.push(now->leftc); if (now->rightc != nullptr) level.push(now->rightc); cout << setw(width); if (now->data != NULL) cout << now->data; else cout << " "; cout << setw(width) << ""; level.pop(); } cout << endl; }
실행 화면
- 노드 삽입
- 노드 탐색
- 노드 삭제
이제,RB 트리만 하면 다음 챕터로 넘어 가겠군요.
빨강~까망트리 빨리 하고 탐색트리 마무리 하고싶네요.
반응형
'Programming Language > c, c++' 카테고리의 다른 글
c++) 피보나치 - 동적 계획법(Fibonacci - Dynamic Programming) (0) | 2017.11.24 |
---|---|
c++) CreateThread, Critical Section (0) | 2017.11.24 |
c++) AVL 트리 ( 삽입, 삭제, 트리 출력 ) (0) | 2017.11.11 |
c++) 이진 탐색 트리 (0) | 2017.11.04 |
c++) 정렬 알고리즘 종합 정리 (0) | 2017.10.22 |