Skip to content

AVL Trees added #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ CC=gcc
CPP=g++
AR=ar
RANLIB=ranlib
CFLAGS= -g -Wall -Wno-unused-function -std=gnu++0x
CFLAGS= -g -Wall -Wno-unused-function -std=c++11
SRCDIR = ./src
INCLUDEDIR = -I./include -I.
DEPS =
Expand Down Expand Up @@ -70,7 +70,8 @@ PROGRAMS = m_based_demo \
8queue_demo \
palindrome_demo \
suffix_array_demo \
suffix_tree_demo
suffix_tree_demo \
avl_demo

all: $(PROGRAMS)

Expand All @@ -79,3 +80,4 @@ all: $(PROGRAMS)

clean:
rm -rf $(PROGRAMS) *.dSYM

20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
Queue
Stack
Binary Heap
Fibonacci Heap
Fibonacci Heap
Priority Queue (list based)

Bubble sort
Selection sort
Bubble sort
Selection sort
Insertion sort
Radix sort
Quick sort
Expand All @@ -51,13 +51,14 @@
Largest common sequence

Binary search tree
AVL tree
Dynamic order statistics
Red-black tree
Interval tree
Prefix Tree(Trie)
Suffix Tree
B-Tree
Suffix Array
Suffix Array

Hash by multiplication
Hash table
Expand All @@ -72,7 +73,7 @@
Base64

Graph data structure
Strongly Connected Components(SCC)
Strongly Connected Components(SCC)
Prim's minimum spanning tree
Kruskal MST
Directed/Undirected graph ops
Expand All @@ -89,13 +90,14 @@
K-Means
Knuth–Morris–Pratt algorithm
Disjoint-Set
8-Queue Problem
Palindrome
8-Queue Problem
Palindrome

####贡献者 ( Contributors ) :
Samana : for heavy work of MSVC compatability
Samana: for heavy work of MSVC compatability
wycg1984: for K-Means
xmuliang: for HeapSort, Kruskal MST
wyh267: for base64, LRU, bubble sort, selection sort
ZhangYou0122: Push-Relabel algorithm, Suffix Tree
UsingtcNower: Suffix Array
UsingtcNower: Suffix Array
afernandez90: AVL trees
238 changes: 238 additions & 0 deletions include/avl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/*******************************************************************************
* ALGORITHM IMPLEMENTAIONS
*
* /\ | _ _ ._ o _|_ |_ ._ _ _
* /--\ | (_| (_) | | |_ | | | | | _>
* _|
*
* Adelson-Velskii and Landis' (AVL) tree
*
* Features, being N the number of elements in the tree:
* 1. Guaranteed search time is O(log(N)).
* 2. Dynamically updated/balanced tree structure O(N) storage.
* 3. Exportable to GraphViz format for easy visualization and verification
*
* http://en.wikipedia.org/wiki/AVL_tree
*
******************************************************************************/

#ifndef __AVL_H__
#define __AVL_H__

#include <iostream>
#include <cmath>
#include <stack>

namespace alg {

template <typename T>
class AVL {

public:

AVL() : tree(0), numNodes(0) {}

T root () const { return tree->value; }
unsigned height() const { return Node::getHeight(tree); }
unsigned size() const { return numNodes; }
bool isEmpty() const { return numNodes == 0; }

bool contains(const T &x) const {
if (!isEmpty()) {
return tree->contains(x);
} else return false;
}

void insert(const T &x) {
if (isEmpty()) tree = new Node(x);
else tree = tree->insert(x);
numNodes++;
}

void erase(const T &x) {
if (!isEmpty()) {
bool found = false;
tree = tree->erase(x, found);
if (found) numNodes--;
}
}

void toGraphViz(std::ostream &stream, std::string name) const {
if (!isEmpty()) {
stream << "digraph " << name << " {" << std::endl;
tree->toGraphViz(stream);
stream << "}" << std::endl;
}
}

public:

struct Node {
Node *left, *right;
T value;
unsigned height;

Node(const T &x) : left(0), right(0), value(x), height(1) {}

bool contains(const T &x) const {
if (value == x) return true;
else if (x < value && left != 0) return left->contains(x);
else if (right != 0) return right->contains(x);
else return false;
}

Node *insert(const T &x) {
if (x <= value) {
if (left == 0) left = new Node(x);
else left = left->insert(x);
}
else {
if (right == 0) right = new Node(x);
else right = right->insert(x);
}

return update();
}

Node *erase(const T &x, bool &found) {
if (value == x) {
found = true;
if (left == 0 && right == 0) {
delete this;
return 0;
} else if (left == 0) {
Node *aux = right;
*this = *right;
delete aux;
} else if (right == 0) {
Node *aux = left;
*this = *left;
delete aux;
} else {
// Tracing path to rightmost leaf of the left subtree
std::stack<Node*> trace;

Node *current = left;
while (current != 0) {
trace.push(current);
current = current->right;
}

current = trace.top();
value = current->value;
Node *lsubtree = current->left;
delete current;
trace.pop();

if (trace.empty()) { left = lsubtree; }
else {
trace.top()->right = lsubtree;
trace.pop();
while (!trace.empty()) {
current = trace.top();
current->right = current->right->update();
trace.pop();
}
}
}
return update();
}
else if (x < value) {
if (left != 0) {
left = left->erase(x, found);
return update();
} else return this;
}
else {
if (right != 0) {
right = right->erase(x, found);
return update();
} else return this;
}
}

Node *update() {
updateHeight();

if (getBF(this) >= 2) {
if (getBF(left) <= -1) LR();
return LL();
} else if (getBF(this) <= -2) {
if (getBF(right) >= 1) RL();
return RR();
} else return this;
}

void updateHeight() { height = std::max(getHeight(left), getHeight(right)) + 1; }

void LR() {
Node *lrcopy = left->right;
left->right = lrcopy->left;
lrcopy->left = left;
left = lrcopy;
left->left->updateHeight();
left->updateHeight();
updateHeight();
}

void RL() {
Node *rlcopy = right->left;
right->left = rlcopy->right;
rlcopy->right = right;
right = rlcopy;
right->right->updateHeight();
right->updateHeight();
updateHeight();
}

Node *LL() {
Node *lcopy = left;
left = left->right;
lcopy->right = this;
lcopy->left->updateHeight();
lcopy->right->updateHeight();
lcopy->updateHeight();
return lcopy;
}

Node *RR() {
Node *rcopy = right;
right = right->left;
rcopy->left = this;
rcopy->left->updateHeight();
rcopy->right->updateHeight();
rcopy->updateHeight();
return rcopy;
}

static int getBF(const Node *t) {
return getHeight(t->left) - getHeight(t->right);
}

static int getHeight(const Node *t) {
return t == 0 ? 0 : t->height;
}

void toGraphViz(std::ostream &stream) const {
stream << value << ";" << std::endl;
if (left != 0) {
stream << left->value << ";" << std::endl;
stream << value << "->" << left->value << ";" << std::endl;
left->toGraphViz(stream);
}
if (right != 0) {
stream << right->value << ";" << std::endl;
stream << value << "->" << right->value << ";" << std::endl;
right->toGraphViz(stream);
}
}
};

Node *tree;
unsigned numNodes;
};

} // namespace alg

#endif // _ALG_AVL_HPP

2 changes: 1 addition & 1 deletion include/binary_search_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* BINARY SEARCH TREE
*
* Features:
* 1. Expected search time is O(nlogn).
* 1. Expected search time is O(log(n)), with worst case O(n).
* 2. Data should be !!!SHUFFLED!!! first before tree creation.
* 3. First initialize the value of the root (pointer to the
* structure treeNode) with NULL. eg:
Expand Down
66 changes: 66 additions & 0 deletions src/avl_demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <iostream>
#include "avl.h"

using namespace std;
using namespace alg;

const unsigned N = 4096*32;
const unsigned N_ELEMS_TO_REMOVE = N-128; // Must be between 0 and N-1

template <typename T>
void printTreeStatus(const AVL<T> &t) {
cout << "----------------------------------------" << endl;
if (t.isEmpty()) cout << "The tree is empty" << endl;
else {
cout << "Tree root is: " << t.root() << endl;
cout << "Tree height is: " << t.height() << endl;
cout << "Tree contains " << t.size() << " elements" << endl;
}
cout << "----------------------------------------" << endl;
}

int main()
{
int values[N];

AVL<int> avl;

cout << "Populating the tree with " << N << " random values... ";
for (unsigned i = 0; i < N; ++i) {
values[i] = rand();
avl.insert(values[i]);
}
cout << "Done" << endl;

printTreeStatus(avl);

for (unsigned i = 0; i < N; ++i) {
unsigned idx = rand() % N;
if (!avl.contains(values[idx]))
cout << "ERROR: Value " << values[idx] << " was inserted and not found!" << endl;
}

cout << "Now removing a random element from the tree... ";
unsigned idx = rand() % N;
avl.erase(values[idx]);
cout << "Done" << endl;

printTreeStatus(avl);

cout << "Now removing the root of the tree " << N_ELEMS_TO_REMOVE << " times... ";
for (unsigned i = 0; i < N_ELEMS_TO_REMOVE; ++i) {
avl.erase(avl.root());
}
cout << "Done" << endl;

printTreeStatus(avl);

// Outputting to cerr so the output can be redirected with ./avl_demo 2> <name>.gvz
cout << "Do you want to output the GraphViz representation of the tree to the cerr stream (Y/n)? ";
char usrInput;
cin >> usrInput;
if (usrInput == 'Y' || usrInput == 'y') avl.toGraphViz(cerr, "AVL");

return 0;
}