#ifndef _TREE_H_ #define _TREE_H_ #include template class BinaryTree { public: //конструктор по умолчанию BinaryTree() : pkey(0), pleft(0), pright(0), pparent(0) { } //конструктор копирования BinaryTree(const BinaryTree& other) : pkey(0), pleft(0), pright(0), pparent(0) { pparent = 0; if(other.hasKey()) { pkey = new T(other.key()); if(other.hasLeft()) { pleft = new BinaryTree(this, other.left()); } if(other.hasRight()) { pright = new BinaryTree(this, other.right()); } } } //деструктор ~BinaryTree() { if(pleft) { delete pleft; } if(pright) { delete pright; } if(pkey) { delete pkey; } } //функция для вставки элементов из отрезка [begin, end] //Пример: int m[] = {1, 3, 2, 6, 7, -4} // int* p = m; // tree.insertFrom(p, p + 5); //Занесет в дерево tree пять первых элементов массива. Работает с любыми итераторами template void insertFrom(const Iterator& begin, const Iterator& end) { for(Iterator i = begin; i != end; ++i) { this->insert(*i); } } //Возвращает список, составленный из элементов дерева std::list makeList() const { std::list result; if(pkey) { result.push_back(*pkey); if(hasLeft()) { result.splice(result.end(), pleft->makeList()); } if(hasRight()) { result.splice(result.end(), pright->makeList()); } } return result; } //Вставляет элемент в дерево согласно правилам. Выделяет память, если нужно. void insert(const T& new_value) { if(!pkey) { pkey = new T(new_value); } if(new_value == *pkey) { return; } else if(new_value < *pkey) { if(!pleft) { pleft = new BinaryTree(this); } pleft->insert(new_value); } else { if(!pright) { pright = new BinaryTree(this); } pright->insert(new_value); } } //Возвращает true если у узла есть родитель, иначе false bool isRoot() const { return (pparent ? true : false); } //Возвращает ссылку на узел-родитель. Если родителя нет, кидает исключение BinaryTree& parent() { if(!pparent) { throw NoParent();; } return *pparent; } //Возвращает константную ссылку на узел-родитель. Если родителя нет, кидает исключение const BinaryTree& parent() const { if(!pparent) { throw NoParent();; } return *pparent; } //Возвращает true, если у узла есть ключевое значение, иначе false bool hasKey() const { return (pkey ? true : false); } //Возвращает ссылку на ключевое значение узла. Если значения нет (указатель нулевой), кидает исключение T& key() { if(!pkey) { throw NoValue(); } return *pkey; } //Возвращает константную ссылку на ключевое значение узла. //Если значения нет (указатель нулевой), кидает исключение const T& key() const { if(!pkey) { throw NoValue(); } return *pkey; } //Устанавливает новое ключевое значение. В данном случае, дерево не перестраивается, поэтому эту //функцию нужно использовать очень аккуратно, чтобы не нарушить структуру дерева void setKey(const T& new_value) { if(pkey) { delete pkey; } pkey = new T(new_value); } //Возвращает ссылку на левое поддерево. Если левого поддерева нет (указатель нулевой), //то кидает исключение BinaryTree& left() { if(!pleft) { throw NoSubtree(); } return *pleft; } //Возвращает константную ссылку на левое поддерево. Если левого поддерева нет (указатель нулевой), //то кидает исключение const BinaryTree& left() const { if(!pleft) { throw NoSubtree(); } return *pleft; } //Возвращает ссылку на правое поддерево. Если правого поддерева нет (указатель нулевой), //то кидает исключение BinaryTree& right() { if(!pright) { throw NoSubtree(); } return *pright; } //Возвращает константную ссылку на правое поддерево. Если правого поддерева нет (указатель нулевой), //то кидает исключение const BinaryTree& right() const { if(!pright) { throw NoSubtree(); } return *pright; } //Рекурсивный поиск по дереву. Возвращается указатель на констатное поддерево, //ключевое значение коренного узла которого равно искомому //Если такого значения в дереве нет, возвращается ноль //Сложность по времени: в среднем O(logn), в худшем O(n) const BinaryTree* find(const T& pattern) const { if(!pkey) { return 0; } if(pattern == *pkey) { return this; } if(pattern < *pkey) { if(!pleft) { return 0; } return pleft->find(pattern); } else { if(!pright) { return 0; } return pright->find(pattern); } } //Рекурсивный поиск по дереву. Возвращается указатель на поддерево, //ключевое значение коренного узла которого равно искомому //Если такого значения в дереве нет, возвращается ноль BinaryTree* find(const T& pattern) { if(!pkey) { return 0; } if(pattern == *pkey) { return this; } if(pattern < *pkey) { if(!pleft) { return 0; } return pleft->find(pattern); } else { if(!pright) { return 0; } return pright->find(pattern); } } //Удаляет правое поддерево void removeLeft() { if(pleft) { delete pleft; pleft = 0; } } //Удаляет левое поддерево void removeRight() { if(pright) { delete pright; pright = 0; } } //Удаляет выбранный элемент, если он находится в дереве. //Дерево перестраивается, чтобы соответствовать структуре двоичного дерева bool remove(const T& pattern) { BinaryTree* psearchResult = find(pattern); if(!psearchResult) { return false; } else { BinaryTree& searchResultParent = psearchResult->parent(); bool searchResultIsRight = (psearchResult->key() > searchResultParent.key() ? true : false); if(psearchResult->isLeaf()) { if(searchResultIsRight) { searchResultParent.removeRight(); return true; } else { searchResultParent.removeLeft(); return true; } } if(!psearchResult->hasLeft()) { BinaryTree& searchResultRight = psearchResult->right(); (searchResultIsRight ? searchResultParent.pright : searchResultParent.pleft) = &searchResultRight; searchResultRight.pparent = &searchResultParent; pright = pleft = 0; delete this; return true; } else if(!psearchResult->hasRight()) { BinaryTree& searchResultLeft = psearchResult->left(); (searchResultIsRight ? searchResultParent.pright : searchResultParent.pleft) = &searchResultLeft; searchResultLeft.pparent = &searchResultParent; pright = pleft = 0; delete this; return true; } else { std::list leftList = psearchResult->left().makeList(); std::list rightList = psearchResult->right().makeList(); std::list leftAndRight; leftAndRight.splice(leftAndRight.end(), leftList); leftAndRight.splice(leftAndRight.end(), rightList); if(searchResultIsRight) { searchResultParent.pright = 0; } else { searchResultParent.pleft = 0; } searchResultParent.insertFrom(leftAndRight.begin(), leftAndRight.end()); //TODO: Fix memory leaks return true; } } } //Возвращает true, если у дерева нет поддеревьев bool isLeaf() const { return !pleft && !pright; } //Возвращает true, если у дерева есть левое поддерево bool hasLeft() const { return (pleft ? true : false); } //Возвращает true, если у дерева есть правое поддерево bool hasRight() const { return (pright ? true : false); } //Возвращает true, если дерево пустое bool empty() const { return !(haskey() && isLeaf()); } //Классы для исключений class NoValue{}; class NoSubtree{}; class NoParent{}; protected: //Приватный конструктор для удобства задания родителей BinaryTree(BinaryTree *new_parent, const BinaryTree& other = BinaryTree()) : pkey(0), pleft(0), pright(0), pparent(new_parent) { if(other.hasKey()) { pkey = new T(other.key()); if(other.hasLeft()) { pleft = new BinaryTree(this, other.left()); } if(other.hasRight()) { pright = new BinaryTree(this, other.right()); } } } private: T *pkey; //указатель на ключевое значение BinaryTree *pparent; //указатель на родителя BinaryTree *pleft; //указатель на левое поддерево BinaryTree *pright; //указатель на правое поддерево }; #endif /*_TREE_H_*/