일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- ML
- Andrew Ng
- BST
- 최소공배수
- coursera
- timestamp
- 데이터베이스
- 최대공약수
- BFS
- 개발
- COALESCE
- 알고리즘
- 백준
- self join
- 깊이우선탐색
- nullif
- 너비우선탐색
- postgresql
- Machine Learning
- C++
- 시퀄
- CREATE TABLE
- pgadmin
- 유데미
- udemy
- 과제
- Advanced SQL
- 자료구조
- sql
- AVLTree
- Today
- Total
승1's B(log n)
[자료구조 - C++] Assignment 4 Search Tree 구현하기 본문
마지막 과제는 바로 Search Tree를 구현하는 것이었다. 일반적인 BST와 AVL Tree들을 구현해서 실행시간을 비교하고 레포트까지 작성하는 것이 과제였다. 사실 이번 과제는 교재(Data Structures&Algorithms in C++ 2nd Edition by Michael T.Goodrich, Roberto Tamissa, David M.Mount)에서 많은 도움을 얻었다. 교수님께서도 그래도 된다고 하시기도 하셨고, 스켈레톤 코드도 상당 부분 유사했다. 그러나 완전히 동일하지는 않았고 어느 정도 응용을 했어야 했다.
주어진 파일은 6개로, AVL Tree 구현에 사용되는 파일 두 개, BST 구현에 사용되는 파일 두 개, 메인 파일 한 개, AVL과 BST의 기초가 되는 Linked Binary Tree 헤더 파일 한 개로 구성되어 있었다.
1-1) 구현해야 하는 함수들 - SearchTree.txx
Iterator& operator++()
TPos eraser(TPos& v)
TPos finder(const K& k, const TPos& v)
TPos inserter(const K& k, const V& x) // replace if k exists
1-2) 구현해야 하는 함수들 - AVLTree.txx
void erase(const K& k)
Iterator insert(const K& k, const V& x) // replace if k exists
void rebalance(const TPos& v)
TPos restructure(const TPos& v)
참고사항 :
1. insert operation in SearchTree and AVLTree must replace the existing key rather than duplicating same keys. : SearchTree와 AVLTree에서 이미 존재하는 키 값을 insert operation을 통해 입력받으면 같은 키를 복제하는 것이 아니라 대체해야 함.
2. You will be able to find most of the implementation of the above functions from our textbook, so you may use them. However, simple cut-and-paste would not work because the code in the textbook may have some errors/bugs. Make sure your code works correctly. : 위 함수들의 구현의 많은 부분을 책에서 찾을 수 있으므로 그것을 사용해도 된다. 그러나 단순 복사 및 붙여넣기는 작동하지 않을 것이다. 확실히 작동하도록 작성할 것.
3. You can freely modify main.cpp for your experiment (see below) : 자유롭게 main.cpp 파일을 조작해도 된다.
main.cpp 파일 조작 관련 안내 :
(a) insert operations only - 두 트리의 삽입 연산 시간 비교
- skewed order, random order 두 가지로 삽입
- 삽입되는 key와 value pair의 size가 각각 1000, 10000, 100000, 1000000일 때 비교
(b) find operations only - 두 트리의 검색 연산 시간 비교
- skewed order, random order 두 가지로 삽입
- 삽입되는 key와 value pair의 size가 각각 1000, 10000, 100000, 1000000일 때 비교
2) LinkedBinaryTree.h
#ifndef BINARYTREE_H
#define BINARYTREE_H
#include <list>
using namespace std;
//
// Binary Tree Class
//
//typedef int Elem; // base element type
template <typename K, typename V>
class Entry { // a (key, value) pair
public: // public functions
typedef K Key; // a key
typedef V Value;
Entry(const K& k = K(), const V& v = V()) // constructor
: _key(k), _value(v) { }
const K& key() const { return _key; } // get key
const V& value() const { return _value; } // get value
void setKey(const K& k) { _key = k; } // set key
void setValue(const V& v) { _value = v; } // set value
private: // private data
K _key; // key
V _value; // value
};
typedef Entry<int,float> Elem;
template <typename E>
class LinkedBinaryTree {
protected:
struct Node { // a node of the tree
E elt; // element value
Node* par; // parent
Node* left; // left child
Node* right; // right child
Node() : elt(), par(NULL), left(NULL), right(NULL) { } // constructor
};
public:
class Position { // position in the tree
//private:
public:
Node* v; // pointer to the node
public:
Position(Node* _v = NULL) : v(_v) { } // constructor
E& operator*() const // get element
{ return v->elt; }
Position left() const // get left child
{ return Position(v->left); }
Position right() const // get right child
{ return Position(v->right); }
Position parent() const // get parent
{ return Position(v->par); }
bool isRoot() const // root of the tree?
{ return v->par == NULL; }
bool isExternal() const // an external node?
{ return v->left == NULL && v->right == NULL; }
// additional
bool isInternal() const
{ return !isExternal(); }
bool operator==(const Position& p) const // are iterators equal?
{ return v == p.v; }
bool operator!=(const Position& p) const // are iterators equal?
{ return v != p.v; }
friend class LinkedBinaryTree; // give tree access
};
typedef std::list<Position> PositionList; // list of positions
public:
LinkedBinaryTree(); // constructor
~LinkedBinaryTree(); // destructor
int size() const; // number of nodes
bool empty() const; // is tree empty?
Position root() const; // get the root
PositionList positions() const; // list of nodes
void addRoot(); // add root to empty tree
void expandExternal(const Position& p); // expand external node
Position removeAboveExternal(const Position& p); // remove p and parent
// housekeeping functions omitted...
protected: // local utilities
void preorder(Node* v, PositionList& pl) const; // preorder utility
private:
Node* _root; // pointer to the root
int n; // number of nodes
};
//
// Implementation
//
template <typename E>
void LinkedBinaryTree<E>::expandExternal(const Position& p) {
Node* v = p.v; // p's node
v->left = new Node; // add a new left child
v->left->par = v; // v is its parent
v->right = new Node; // and a new right child
v->right->par = v; // v is its parent
n += 2; // two more nodes
}
template <typename E>
typename LinkedBinaryTree<E>::PositionList LinkedBinaryTree<E>::positions() const {
PositionList pl;
preorder(_root, pl); // preorder traversal
return PositionList(pl); // return resulting list
}
// preorder traversal
template <typename E>
void LinkedBinaryTree<E>::preorder(Node* v, PositionList& pl) const {
pl.push_back(Position(v)); // add this node
if (v->left != NULL) // traverse left subtree
preorder(v->left, pl);
if (v->right != NULL) // traverse right subtree
preorder(v->right, pl);
}
template <typename E>
typename LinkedBinaryTree<E>::Position // remove p and parent
LinkedBinaryTree<E>::removeAboveExternal(const Position& p) {
Node* w = p.v; Node* v = w->par; // get p's node and parent
Node* sib = (w == v->left ? v->right : v->left);
if (v == _root) { // child of root?
_root = sib; // ...make sibling root
sib->par = NULL;
}
else {
Node* gpar = v->par; // w's grandparent
if (v == gpar->left) gpar->left = sib; // replace parent by sib
else gpar->right = sib;
sib->par = gpar;
}
delete w; delete v; // delete removed nodes
n -= 2; // two fewer nodes
return Position(sib);
}
template <typename E>
LinkedBinaryTree<E>::LinkedBinaryTree() // constructor
: _root(NULL), n(0) { }
template <typename E>
LinkedBinaryTree<E>::~LinkedBinaryTree() // destructor
{
PositionList pl = positions();
for(typename PositionList::iterator it = pl.begin();it != pl.end();it++)
{
Node* w = (*it).v;
delete w;
}
}
template <typename E>
int LinkedBinaryTree<E>::size() const // number of nodes
{ return n; }
template <typename E>
bool LinkedBinaryTree<E>::empty() const // is tree empty?
{ return size() == 0; }
template <typename E>
typename LinkedBinaryTree<E>::Position LinkedBinaryTree<E>::root() const // get the root
{ return Position(_root); }
template <typename E>
void LinkedBinaryTree<E>::addRoot() // add root to empty tree
{ _root = new Node; n = 1; }
#endif
3) SearchTree.h
#ifndef SEARCHTREE_H
#define SEARCHTREE_H
#include <iostream>
#include "LinkedBinaryTree.h"
//
// SearchTree Class
//
template <typename E>
class SearchTree { // a binary search tree
public: // public types
typedef typename E::Key K; // a key
typedef typename E::Value V; // a value
class Iterator; // an iterator/position
public: // public functions
SearchTree(); // constructor
int size() const; // number of entries
bool empty() const; // is the tree empty?
Iterator find(const K& k); // find entry with key k
Iterator insert(const K& k, const V& x); // insert (k,x)
void erase(const K& k); // remove key k entry
void erase(const Iterator& p); // remove entry at p
Iterator begin(); // iterator to first entry
Iterator end(); // iterator to end entry
protected: // local utilities
typedef LinkedBinaryTree<E> BinaryTree; // linked binary tree
typedef typename BinaryTree::Position TPos; // position in the tree
TPos root() const; // get virtual root
TPos finder(const K& k, const TPos& v); // find utility
TPos inserter(const K& k, const V& x); // insert utility
TPos eraser(TPos& v); // erase utility
TPos restructure(const TPos& v); // restructure
private: // member data
BinaryTree T; // the binary tree
int n; // number of entries
public:
class Iterator { // an iterator/position
private:
TPos v; // which entry
public:
Iterator(const TPos& vv) : v(vv) { } // constructor
const E& operator*() const { return *v; } // get entry (read only)
E& operator*() { return *v; } // get entry (read/write)
bool operator==(const Iterator& p) const // are iterators equal?
{ return v == p.v; }
bool operator!=(const Iterator& p) const // are iterators not equal?
{ return v != p.v; }
Iterator& operator++(); // inorder successor
friend class SearchTree; // give search tree access
};
};
#ifndef SEARCHTREE_TXX
#define SEARCHTREE_TXX
#include "SearchTree.txx"
#endif
#endif
4) SearchTree.txx
template <typename E> // constructor
SearchTree<E>::SearchTree() : T(), n(0)
{ T.addRoot(); T.expandExternal(T.root()); } // create the super root
template <typename E> // get virtual root
typename SearchTree<E>::TPos SearchTree<E>::root() const
{ return T.root().left(); } // left child of super root
template <typename E> // iterator to first entry
typename SearchTree<E>::Iterator SearchTree<E>::begin() {
TPos v = root(); // start at virtual root
while (v.isInternal()) v = v.left(); // find leftmost node
return Iterator(v.parent());
}
template <typename E> // iterator to end entry
typename SearchTree<E>::Iterator SearchTree<E>::end()
{ return Iterator(T.root()); } // return the super root
template <typename E> // remove key k entry
void SearchTree<E>::erase(const K& k) { //throw(NonexistentElement) {
TPos v = finder(k, root()); // search from virtual root
if (v.isExternal()) // not found?
throw "Erase of nonexistent";//NonexistentElement("Erase of nonexistent");
eraser(v); // remove it
}
template <typename E> // erase entry at p
void SearchTree<E>::erase(const Iterator& p)
{ eraser(p.v); }
template <typename E> // find entry with key k
typename SearchTree<E>::Iterator SearchTree<E>::find(const K& k) {
TPos v = finder(k, root()); // search from virtual root
if (v.isInternal()) return Iterator(v); // found it
else return end(); // didn't find it
}
template <typename E> // insert (k,x)
typename SearchTree<E>::Iterator SearchTree<E>::insert(const K& k, const V& x)
{ TPos v = inserter(k, x); return Iterator(v); }
template <typename E>
int SearchTree<E>::size() const { return n; }
//
// ToDo
//
template <typename E> // inorder successor
typename SearchTree<E>::Iterator& SearchTree<E>::Iterator::operator++() {
TPos w = v.right();
if (w.isInternal()){
do{v = w; w = w.left();}
while (w.isInternal());
}
else{
w = v.parent();
while (v == w.right())
{v = w; w = w.parent();}
v = w;
}
return *this;
}
template <typename E> // remove utility
typename SearchTree<E>::TPos SearchTree<E>::eraser(TPos& v) {
TPos w;
if (v.left().isExternal()) w = v.left();
else if (v.right().isExternal()) w = v.right();
else { w = v.right(); do{w = w.left();} while (w.isInternal());
TPos u = w.parent();
(*v).setKey((*u).key()); (*v).setValue((*u).value());}
n--;
return T.removeAboveExternal(w);
}
template <typename E> // find utility
typename SearchTree<E>::TPos SearchTree<E>::finder(const K& k, const TPos& v) {
if (v.isExternal()) return v; //key not found
if (k < (*v).key()) return finder(k, v.v->left); //search left subtree
else if ((*v).key() < k) return finder(k, v.v->right); //search right subtree
else return v;
}
template <typename E> // insert utility
typename SearchTree<E>::TPos SearchTree<E>::inserter(const K& k, const V& x) {
TPos v = finder(k, root());
if((*v).key() == k){}
else{
while (v.isInternal()) v = finder(k, v.right());
T.expandExternal(v);
(*v).setKey(k);
n++;}
(*v).setValue(x);
return v;
}
5) AVLTree.h
#ifndef AVLTREE_H
#define AVLTREE_H
#include <iostream>
#include "SearchTree.h"
template <typename E> class AVLTree;
template <typename E>
class AVLEntry : public E { // an AVL entry
private:
int ht; // node height
protected: // local types
typedef typename E::Key K; // key type
typedef typename E::Value V; // value type
int height() const { return ht; } // get height
void setHeight(int h) { ht = h; } // set height
public: // public functions
AVLEntry(const K& k = K(), const V& v = V()) // constructor
: E(k,v), ht(0) { }
friend class AVLTree<E>; // allow AVLTree access
};
//
// AVL Tree class
//
template <typename E> // an AVL tree
class AVLTree : public SearchTree< AVLEntry<E> > {
public: // public types
typedef AVLEntry<E> Entry; // an entry
typedef typename SearchTree<Entry>::Iterator Iterator; // an iterator
protected: // local types
typedef typename Entry::Key K; // a key
typedef typename Entry::Value V; // a value
typedef SearchTree<Entry> ST; // a search tree
typedef typename ST::TPos TPos; // a tree position
public: // public functions
AVLTree(); // constructor
Iterator insert(const K& k, const V& x); // insert (k,x)
void erase(const K& k); // remove key k entry
void erase(const Iterator& p); // remove entry at p
protected: // utility functions
int height(const TPos& v) const; // node height utility
void setHeight(TPos v); // set height utility
bool isBalanced(const TPos& v) const; // is v balanced?
TPos tallGrandchild(const TPos& v) const; // get tallest grandchild
void rebalance(const TPos& v); // rebalance utility
TPos restructure(const TPos& v); // restructure
};
#ifndef AVLTREE_TXX
#define AVLTREE_TXX
#include "AVLTree.txx"
#endif
#endif
6) AVLTree.txx
//
// Implementation
//
template <typename E> // constructor
AVLTree<E>::AVLTree() : ST() { }
template <typename E> // node height utility
int AVLTree<E>::height(const TPos& v) const
{ return (v.isExternal() ? 0 : (*v).height()); }
template <typename E> // set height utility
void AVLTree<E>::setHeight(TPos v) {
int hl = height(v.left());
int hr = height(v.right());
(*v).setHeight(1 + std::max(hl, hr)); // max of left & right
}
template <typename E> // is v balanced?
bool AVLTree<E>::isBalanced(const TPos& v) const {
int bal = height(v.left()) - height(v.right());
return ((-1 <= bal) && (bal <= 1));
}
template <typename E> // get tallest grandchild
typename AVLTree<E>::TPos AVLTree<E>::tallGrandchild(const TPos& z) const {
TPos zl = z.left();
TPos zr = z.right();
if (height(zl) >= height(zr)) // left child taller
if (height(zl.left()) >= height(zl.right()))
return zl.left();
else
return zl.right();
else // right child taller
if (height(zr.right()) >= height(zr.left()))
return zr.right();
else
return zr.left();
}
//
// ToDo
//
template <typename E> // remove key k entry
void AVLTree<E>::erase(const K& k) {
TPos v = finder(k, ST::root());
TPos w = eraser(v);
rebalance(w);
}
template <typename E> // insert (k,x)
typename AVLTree<E>::Iterator AVLTree<E>::insert(const K& k, const V& x) {
TPos v = ST::inserter(k, x);
setHeight(v);
rebalance(v);
return Iterator(v);
}
template <typename E> // rebalancing utility
void AVLTree<E>::rebalance(const TPos& v) {
TPos z = v;
while (!(z == ST::root()))
{
z = z.parent();
setHeight(z);
if (!isBalanced(z))
{
TPos x = tallGrandchild(z);
z = restructure(x);
setHeight(z.left());
setHeight(z.right());
setHeight(z);
}
}
}
template <typename E> // Binary Search Tree Rotation
typename AVLTree<E>::TPos AVLTree<E>::restructure(const TPos& v) {
TPos x = v;
TPos y = v.parent(); //parent node of x
TPos z = y.parent(); //parent node of y(== grandparent node of x)
TPos GP = z; //grandparent node is z, it needs to compare with great grand parent
TPos GGP = z.parent(); //great grand parent node is parent node of z
K key_z = (*z).key();
K key_y = (*y).key();
K key_x = (*x).key();
if(key_z < key_y) // Left rotation
{
if(key_y < key_x) //RR rotation
{
TPos ylc = y.left();
y.v->par = z.v->par;
z.v->right = ylc.v;
y.v->left = z.v;
z.v->par = x.v->par = y.v;
ylc.v->par = z.v;
if(GGP.left() == GP)
GGP.v->left = y.v;
else if(GGP.right() == GP)
GGP.v->right = y.v;
return y;
}
else if(key_y > key_x) //RL rotation
{
TPos xlc = x.left();
TPos xrc = x.right();
x.v->par = y.v->par; //LL rotation begins
y.v->left = xrc.v;
x.v->right = y.v;
xlc.v->par = y.v->par = x.v;
xrc.v->par = y.v; //LL rotation ends
x.v->par = z.v->par; //RR rotation begins
z.v->right = xlc.v;
x.v->left = z.v;
z.v->par = y.v->par = x.v;
xlc.v->par = z.v; //RR rotation ends
if(GGP.left() == GP)
GGP.v->left = x.v;
else if(GGP.right() == GP)
GGP.v->right = x.v;
return x;
}
}
else //Right rotation
{
if(key_y > key_x) //LL rotation
{
TPos yrc = y.right();
y.v->par = z.v->par;
z.v->left = yrc.v;
y.v->right = z.v;
z.v->par = x.v->par = y.v;
yrc.v->par = z.v;
if(GGP.left() == GP)
GGP.v->left = y.v;
else if(GGP.right() == GP)
GGP.v->right = y.v;
return y;
}
else if(key_y < key_x) //LR rotation
{
TPos xlc = x.left();
TPos xrc = x.right();
x.v->par = y.v->par; //RR rotation begins
y.v->right = xlc.v;
x.v->left = y.v;
y.v->par = xrc.v->par = x.v;
xlc.v->par = y.v; //RR rotation ends
x.v->par = z.v->par; //LL rotation begins
z.v->left = xrc.v;
x.v->right = z.v;
z.v->par = y.v->par = x.v;
xrc.v->par = z.v; //LL rotatiion ends
if(GGP.left() == GP)
GGP.v->left = x.v;
else if(GGP.right() == GP)
GGP.v->right = x.v;
return x;
}
}
return NULL; //if an error occurs
}
7) main.cpp
#include "LinkedBinaryTree.h"
#include "SearchTree.h"
#include "AVLTree.h"
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
#include <iostream>
using namespace std;
int main()
{
typedef Entry<int, float> EntryType;
LinkedBinaryTree<EntryType> t;
std::cout << "Size : " << t.size() << std::endl;
t.addRoot();
std::cout << "Size : " << t.size() << std::endl;
//
//
//
SearchTree<EntryType> st;
std::cout << "Size : " << st.size() << std::endl;
st.insert(1, 2.5);
st.insert(3, 4.5);
st.insert(7, 5.5);
st.insert(2, 1.5);
st.insert(3, 8.5);
std::cout << "Size : " << st.size() << std::endl;
for(SearchTree<EntryType>::Iterator it = st.begin(); it != st.end(); ++it)
{
std::cout << (*it).key() << " , " << (*it).value() << std::endl;
}
st.erase(3);
std::cout << "Size : " << st.size() << std::endl;
for(SearchTree<EntryType>::Iterator it = st.begin(); it != st.end(); ++it)
{
std::cout << (*it).key() << " , " << (*it).value() << std::endl;
}
std::cout << "------------" << std::endl;
//
//
AVLTree<EntryType> avl;
//
// random test
int nElem = 100000; //100000000;
int *key = new int[nElem*2];
float *val = new float[nElem*2];
std::srand((unsigned int)time(NULL)); // use current time as seed for random generator
// initialize
for(int i=0; i<nElem*2; i++)
{
key[i] = i+1;
val[i] = (float) std::rand()/RAND_MAX * 20000;
}
//
// AVL tree Insert test
//
clock_t tm;
tm = clock();
for(int i=0; i<nElem; i++)
{
avl.insert(key[i], val[i]);
}
tm = clock() - tm;
printf ("It took me %f seconds.\n",((float)tm)/(float)CLOCKS_PER_SEC);
//
// AVL tree Find test
//
tm = clock();
for(int i=nElem; i<nElem*2; i++)
{
avl.find(key[i]);
}
tm = clock() - tm;
printf ("It took me %f seconds.\n",((float)tm)/(float)CLOCKS_PER_SEC);
delete[] key;
delete[] val;
std::cout << "------------" << std::endl;
//
//Test Cases Implementation
//
std::cout << "Test Cases Implementation" << std::endl;
//1) size = 1000
std::cout << " 1. size = 1000" << std::endl;
//In skewed order(increasing order)
std::cout << " " << std::endl;
std::cout << " 1-(1). Skewed Order(Increasing Order)" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int n1Elem = 1000;
int *n11key = new int[n1Elem];
float *n11val = new float[n1Elem];
for(int i=0; i<n1Elem; i++) //initialize
{
n11key[i] = i+1; //keys are initialized in increasing order.
n11val[i] = (float) std::rand()/RAND_MAX * 20000; //value doesn't matter, so I will use it repeatedly
}
//Search Tree Insertion
SearchTree<EntryType> st_test1_1;
tm = clock();
for(int i=0; i<n1Elem; i++)
st_test1_1.insert(n11key[i], n11val[i]);
tm = clock() - tm;
float st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test1_1;
tm = clock();
for(int i=0; i<n1Elem; i++)
avl_test1_1.insert(n11key[i], n11val[i]);
tm = clock() - tm;
float avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
//Comparison
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n1Elem; i++)
st_test1_1.find(n11key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n1Elem; i++)
avl_test1_1.find(n11key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n11key;
delete[] n11val;
std::cout << " " << std::endl;
std::cout << " 1-(2). Random Order" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int* n12key = new int[n1Elem];
float* n12val = new float[n1Elem];
for(int i=0; i<n1Elem; i++) //randomly initialize
{
n12key[i] = std::rand();
n12val[i] = (float) std::rand()/RAND_MAX * 20000;
}
//Search Tree Insertion
SearchTree<EntryType> st_test1_2;
tm = clock();
for(int i=0; i<n1Elem; i++)
st_test1_2.insert(n12key[i], n12val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test1_2;
tm = clock();
for(int i=0; i<n1Elem; i++)
avl_test1_2.insert(n12key[i], n12val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n1Elem; i++)
st_test1_2.find(n12key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n1Elem; i++)
avl_test1_2.find(n12key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n12key;
delete[] n12val;
std::cout << " ------------" << std::endl;
std::cout << " 2. size = 10000" << std::endl;
//In skewed order(increasing order)
std::cout << " " << std::endl;
std::cout << " 2-(1). Skewed Order(Increasing Order)" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int n2Elem = 10000;
int* n21key = new int[n2Elem];
float* n21val = new float[n2Elem];
for(int i=0; i<n2Elem; i++) //initialize
{
n21key[i] = i+1; //keys are initialized in increasing order.
n21val[i] = (float) std::rand()/RAND_MAX * 20000; //value doesn't matter, so I will use it repeatedly
}
//Search Tree Insertion
SearchTree<EntryType> st_test2_1;
tm = clock();
for(int i=0; i<n2Elem; i++)
st_test2_1.insert(n21key[i], n21val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test2_1;
tm = clock();
for(int i=0; i<n2Elem; i++)
avl_test2_1.insert(n21key[i], n21val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n2Elem; i++)
st_test2_1.find(n21key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n2Elem; i++)
avl_test2_1.find(n21key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n21key;
delete[] n21val;
std::cout << " " << std::endl;
std::cout << " 2-(2). Random Order" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int* n22key = new int[n2Elem];
float* n22val = new float[n2Elem];
for(int i=0; i<n2Elem; i++) //randomly initialize
{
n22key[i] = std::rand();
n22val[i] = (float) std::rand()/RAND_MAX * 20000;
}
//Search Tree Insertion
SearchTree<EntryType> st_test2_2;
tm = clock();
for(int i=0; i<n2Elem; i++)
st_test2_2.insert(n22key[i], n22val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test2_2;
tm = clock();
for(int i=0; i<n2Elem; i++)
avl_test2_2.insert(n22key[i], n22val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n2Elem; i++)
st_test2_2.find(n22key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n2Elem; i++)
avl_test2_2.find(n22key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n22key;
delete[] n22val;
std::cout << " ------------" << std::endl;
std::cout << " 3. size = 100000" << std::endl;
//In skewed order(increasing order)
std::cout << " " << std::endl;
std::cout << " 3-(1). Skewed Order(Increasing Order)" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int n3Elem = 100000;
int *n31key = new int[n3Elem];
float *n31val = new float[n3Elem];
for(int i=0; i<n3Elem; i++) //initialize
{
n31key[i] = i+1; //keys are initialized in increasing order.
n31val[i] = (float) std::rand()/RAND_MAX * 20000; //value doesn't matter, so I will use it repeatedly
}
//Search Tree Insertion
SearchTree<EntryType> st_test3_1;
tm = clock();
for(int i=0; i<n3Elem; i++)
st_test3_1.insert(n31key[i], n31val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test3_1;
tm = clock();
for(int i=0; i<n3Elem; i++)
avl_test3_1.insert(n31key[i], n31val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i< n3Elem; i++)
st_test3_1.find(n31key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n3Elem; i++)
avl_test3_1.find(n31key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n31key;
delete[] n31val;
std::cout << " " << std::endl;
std::cout << " 3-(2). Random Order" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int *n32key = new int[n3Elem];
float *n32val = new float[n3Elem];
for(int i=0; i<n3Elem; i++) //randomly initialize
{
n32key[i] = std::rand();
n32val[i] = (float) std::rand()/RAND_MAX * 20000;
}
//Search Tree Insertion
SearchTree<EntryType> st_test3_2;
tm = clock();
for(int i=0; i<n3Elem; i++)
st_test3_2.insert(n32key[i], n32val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test3_2;
tm = clock();
for(int i=0; i<n3Elem; i++)
avl_test3_2.insert(n32key[i], n32val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n3Elem; i++)
st_test3_2.find(n32key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n3Elem; i++)
avl_test3_2.find(n32key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n32key;
delete[] n32val;
std::cout << " ------------" << std::endl;
std::cout << " 4. size = 1000000" << std::endl;
//In skewed order(increasing order)
std::cout << " " << std::endl;
std::cout << " 4-(1). Skewed Order(Increasing Order)" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int n4Elem = 1000000;
int *n41key = new int[n4Elem];
float *n41val = new float[n4Elem];
for(int i = 0; i < n4Elem; i++) //initialize
{
n41key[i] = i+1; //keys are initialized in increasing order.
n41val[i] = (float) std::rand()/RAND_MAX * 20000; //value doesn't matter, so I will use it repeatedly
}
//Search Tree Insertion
SearchTree<EntryType> st_test4_1;
tm = clock();
for(int i = 0; i < n4Elem; i++)
st_test4_1.insert(n41key[i], n41val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test4_1;
tm = clock();
for(int i = 0; i < n4Elem; i++)
avl_test4_1.insert(n41key[i], n41val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i = 0; i < n4Elem; i++)
st_test4_1.find(n41key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n4Elem; i++)
avl_test4_1.find(n41key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n41key;
delete[] n41val;
std::cout << " " << std::endl;
std::cout << " 4-(2). Random Order" << std::endl;
std::cout << " " << std::endl;
std::cout << " (a). Insert Operation" << std::endl;
int *n42key = new int[n4Elem];
float *n42val = new float[n4Elem];
for(int i = 0; i < n4Elem; i++) //randomly initialize
{
n42key[i] = std::rand();
n42val[i] = (float) std::rand()/RAND_MAX * 20000;
}
//Search Tree Insertion
SearchTree<EntryType> st_test4_2;
tm = clock();
for(int i=0; i<n4Elem; i++)
st_test4_2.insert(n42key[i], n42val[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Insertion
AVLTree<EntryType> avl_test4_2;
tm = clock();
for(int i=0; i<n4Elem; i++)
avl_test4_2.insert(n42key[i], n42val[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Insertion was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Insertion was faster than Search Tree's." << std::endl;
std::cout << " " << std::endl;
std::cout << " (b). Find Operation" << std::endl;
//Search Tree Find
tm = clock();
for(int i=0; i<n4Elem; i++)
st_test4_2.find(n42key[i]);
tm = clock() - tm;
st_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (i) Search Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//AVL Tree Find
tm = clock();
for(int i=0; i<n4Elem; i++)
avl_test4_2.find(n42key[i]);
tm = clock() - tm;
avl_Clock = ((float)tm)/(float)CLOCKS_PER_SEC;
std::cout << " (ii) AVL Tree : " << ((float)tm)/(float)CLOCKS_PER_SEC << " seconds." << std::endl;
//comparison
if(st_Clock < avl_Clock)
std::cout << " -> Search Tree Find was faster than AVL Tree's." << std::endl;
else
std::cout << " -> AVL Tree Find was faster than Search Tree's." << std::endl;
delete[] n42key;
delete[] n42val;
std::cout << " ------------" << std::endl;
return 0;
}
8) 레포트
점수 : 97/100
대부분의 구현을 책에서 찾을 수 있어서 그렇게 어렵지는 않았으나 restructure 함수를 구현하는데는 애를 좀 먹었다. 여러가지 케이스들을 생각해야 됐기 때문이다. 오히려 레포트를 쓰는 것이 더 힘들었던 것 같다. 함수가 구현되어 있는 방식 때문에 size가 커질 경우에 본인 컴퓨터에서 작동이 잘 되지 않았던 부분도 있었다. 그래도 실제로 AVLTree와 BST를 구현해볼 수 있었다는 것이 이번 과제의 장점이 아닐까 싶다.
'Data Structures & Algorithms' 카테고리의 다른 글
[알고리즘] DFS & BFS 깊이우선탐색과 너비우선탐색 (0) | 2022.08.22 |
---|---|
[알고리즘] 최소공배수와 최대공약수 구하기 (0) | 2022.08.21 |
[자료구조 - C++] Assignment 3 Hash Map을 통해 단어 빈도수 확인 기능 구현하기 (0) | 2022.07.01 |
[자료구조 - C++] Assignment 2 Doubly Linked List를 응용한 간단한 문서편집기 만들기 (0) | 2022.06.24 |
[자료구조 - C++] Assignment 1 다항식 계산기 만들기 (0) | 2022.06.23 |