Skip to content

Commit 7637e26

Browse files
committed
Merge pull request xtaci#31 from afernandez90/master
AVL Trees added
2 parents f1473fa + 3171767 commit 7637e26

File tree

5 files changed

+320
-12
lines changed

5 files changed

+320
-12
lines changed

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CC=gcc
33
CPP=g++
44
AR=ar
55
RANLIB=ranlib
6-
CFLAGS= -g -Wall -Wno-unused-function -std=gnu++0x
6+
CFLAGS= -g -Wall -Wno-unused-function -std=c++11
77
SRCDIR = ./src
88
INCLUDEDIR = -I./include -I.
99
DEPS =
@@ -70,7 +70,8 @@ PROGRAMS = m_based_demo \
7070
8queue_demo \
7171
palindrome_demo \
7272
suffix_array_demo \
73-
suffix_tree_demo
73+
suffix_tree_demo \
74+
avl_demo
7475

7576
all: $(PROGRAMS)
7677

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

8081
clean:
8182
rm -rf $(PROGRAMS) *.dSYM
83+

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@
3535
Queue
3636
Stack
3737
Binary Heap
38-
Fibonacci Heap
38+
Fibonacci Heap
3939
Priority Queue (list based)
4040

41-
Bubble sort
42-
Selection sort
41+
Bubble sort
42+
Selection sort
4343
Insertion sort
4444
Radix sort
4545
Quick sort
@@ -51,13 +51,14 @@
5151
Largest common sequence
5252

5353
Binary search tree
54+
AVL tree
5455
Dynamic order statistics
5556
Red-black tree
5657
Interval tree
5758
Prefix Tree(Trie)
5859
Suffix Tree
5960
B-Tree
60-
Suffix Array
61+
Suffix Array
6162

6263
Hash by multiplication
6364
Hash table
@@ -72,7 +73,7 @@
7273
Base64
7374

7475
Graph data structure
75-
Strongly Connected Components(SCC)
76+
Strongly Connected Components(SCC)
7677
Prim's minimum spanning tree
7778
Kruskal MST
7879
Directed/Undirected graph ops
@@ -89,13 +90,14 @@
8990
K-Means
9091
Knuth–Morris–Pratt algorithm
9192
Disjoint-Set
92-
8-Queue Problem
93-
Palindrome
93+
8-Queue Problem
94+
Palindrome
9495

9596
####贡献者 ( Contributors ) :
96-
Samana : for heavy work of MSVC compatability
97+
Samana: for heavy work of MSVC compatability
9798
wycg1984: for K-Means
9899
xmuliang: for HeapSort, Kruskal MST
99100
wyh267: for base64, LRU, bubble sort, selection sort
100101
ZhangYou0122: Push-Relabel algorithm, Suffix Tree
101-
UsingtcNower: Suffix Array
102+
UsingtcNower: Suffix Array
103+
afernandez90: AVL trees

include/avl.h

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*******************************************************************************
2+
* ALGORITHM IMPLEMENTAIONS
3+
*
4+
* /\ | _ _ ._ o _|_ |_ ._ _ _
5+
* /--\ | (_| (_) | | |_ | | | | | _>
6+
* _|
7+
*
8+
* Adelson-Velskii and Landis' (AVL) tree
9+
*
10+
* Features, being N the number of elements in the tree:
11+
* 1. Guaranteed search time is O(log(N)).
12+
* 2. Dynamically updated/balanced tree structure O(N) storage.
13+
* 3. Exportable to GraphViz format for easy visualization and verification
14+
*
15+
* http://en.wikipedia.org/wiki/AVL_tree
16+
*
17+
******************************************************************************/
18+
19+
#ifndef __AVL_H__
20+
#define __AVL_H__
21+
22+
#include <iostream>
23+
#include <cmath>
24+
#include <stack>
25+
26+
namespace alg {
27+
28+
template <typename T>
29+
class AVL {
30+
31+
public:
32+
33+
AVL() : tree(0), numNodes(0) {}
34+
35+
T root () const { return tree->value; }
36+
unsigned height() const { return Node::getHeight(tree); }
37+
unsigned size() const { return numNodes; }
38+
bool isEmpty() const { return numNodes == 0; }
39+
40+
bool contains(const T &x) const {
41+
if (!isEmpty()) {
42+
return tree->contains(x);
43+
} else return false;
44+
}
45+
46+
void insert(const T &x) {
47+
if (isEmpty()) tree = new Node(x);
48+
else tree = tree->insert(x);
49+
numNodes++;
50+
}
51+
52+
void erase(const T &x) {
53+
if (!isEmpty()) {
54+
bool found = false;
55+
tree = tree->erase(x, found);
56+
if (found) numNodes--;
57+
}
58+
}
59+
60+
void toGraphViz(std::ostream &stream, std::string name) const {
61+
if (!isEmpty()) {
62+
stream << "digraph " << name << " {" << std::endl;
63+
tree->toGraphViz(stream);
64+
stream << "}" << std::endl;
65+
}
66+
}
67+
68+
public:
69+
70+
struct Node {
71+
Node *left, *right;
72+
T value;
73+
unsigned height;
74+
75+
Node(const T &x) : left(0), right(0), value(x), height(1) {}
76+
77+
bool contains(const T &x) const {
78+
if (value == x) return true;
79+
else if (x < value && left != 0) return left->contains(x);
80+
else if (right != 0) return right->contains(x);
81+
else return false;
82+
}
83+
84+
Node *insert(const T &x) {
85+
if (x <= value) {
86+
if (left == 0) left = new Node(x);
87+
else left = left->insert(x);
88+
}
89+
else {
90+
if (right == 0) right = new Node(x);
91+
else right = right->insert(x);
92+
}
93+
94+
return update();
95+
}
96+
97+
Node *erase(const T &x, bool &found) {
98+
if (value == x) {
99+
found = true;
100+
if (left == 0 && right == 0) {
101+
delete this;
102+
return 0;
103+
} else if (left == 0) {
104+
Node *aux = right;
105+
*this = *right;
106+
delete aux;
107+
} else if (right == 0) {
108+
Node *aux = left;
109+
*this = *left;
110+
delete aux;
111+
} else {
112+
// Tracing path to rightmost leaf of the left subtree
113+
std::stack<Node*> trace;
114+
115+
Node *current = left;
116+
while (current != 0) {
117+
trace.push(current);
118+
current = current->right;
119+
}
120+
121+
current = trace.top();
122+
value = current->value;
123+
Node *lsubtree = current->left;
124+
delete current;
125+
trace.pop();
126+
127+
if (trace.empty()) { left = lsubtree; }
128+
else {
129+
trace.top()->right = lsubtree;
130+
trace.pop();
131+
while (!trace.empty()) {
132+
current = trace.top();
133+
current->right = current->right->update();
134+
trace.pop();
135+
}
136+
}
137+
}
138+
return update();
139+
}
140+
else if (x < value) {
141+
if (left != 0) {
142+
left = left->erase(x, found);
143+
return update();
144+
} else return this;
145+
}
146+
else {
147+
if (right != 0) {
148+
right = right->erase(x, found);
149+
return update();
150+
} else return this;
151+
}
152+
}
153+
154+
Node *update() {
155+
updateHeight();
156+
157+
if (getBF(this) >= 2) {
158+
if (getBF(left) <= -1) LR();
159+
return LL();
160+
} else if (getBF(this) <= -2) {
161+
if (getBF(right) >= 1) RL();
162+
return RR();
163+
} else return this;
164+
}
165+
166+
void updateHeight() { height = std::max(getHeight(left), getHeight(right)) + 1; }
167+
168+
void LR() {
169+
Node *lrcopy = left->right;
170+
left->right = lrcopy->left;
171+
lrcopy->left = left;
172+
left = lrcopy;
173+
left->left->updateHeight();
174+
left->updateHeight();
175+
updateHeight();
176+
}
177+
178+
void RL() {
179+
Node *rlcopy = right->left;
180+
right->left = rlcopy->right;
181+
rlcopy->right = right;
182+
right = rlcopy;
183+
right->right->updateHeight();
184+
right->updateHeight();
185+
updateHeight();
186+
}
187+
188+
Node *LL() {
189+
Node *lcopy = left;
190+
left = left->right;
191+
lcopy->right = this;
192+
lcopy->left->updateHeight();
193+
lcopy->right->updateHeight();
194+
lcopy->updateHeight();
195+
return lcopy;
196+
}
197+
198+
Node *RR() {
199+
Node *rcopy = right;
200+
right = right->left;
201+
rcopy->left = this;
202+
rcopy->left->updateHeight();
203+
rcopy->right->updateHeight();
204+
rcopy->updateHeight();
205+
return rcopy;
206+
}
207+
208+
static int getBF(const Node *t) {
209+
return getHeight(t->left) - getHeight(t->right);
210+
}
211+
212+
static int getHeight(const Node *t) {
213+
return t == 0 ? 0 : t->height;
214+
}
215+
216+
void toGraphViz(std::ostream &stream) const {
217+
stream << value << ";" << std::endl;
218+
if (left != 0) {
219+
stream << left->value << ";" << std::endl;
220+
stream << value << "->" << left->value << ";" << std::endl;
221+
left->toGraphViz(stream);
222+
}
223+
if (right != 0) {
224+
stream << right->value << ";" << std::endl;
225+
stream << value << "->" << right->value << ";" << std::endl;
226+
right->toGraphViz(stream);
227+
}
228+
}
229+
};
230+
231+
Node *tree;
232+
unsigned numNodes;
233+
};
234+
235+
} // namespace alg
236+
237+
#endif // _ALG_AVL_HPP
238+

include/binary_search_tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* BINARY SEARCH TREE
99
*
1010
* Features:
11-
* 1. Expected search time is O(nlogn).
11+
* 1. Expected search time is O(log(n)), with worst case O(n).
1212
* 2. Data should be !!!SHUFFLED!!! first before tree creation.
1313
* 3. First initialize the value of the root (pointer to the
1414
* structure treeNode) with NULL. eg:

src/avl_demo.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include <iostream>
2+
#include "avl.h"
3+
4+
using namespace std;
5+
using namespace alg;
6+
7+
const unsigned N = 4096*32;
8+
const unsigned N_ELEMS_TO_REMOVE = N-128; // Must be between 0 and N-1
9+
10+
template <typename T>
11+
void printTreeStatus(const AVL<T> &t) {
12+
cout << "----------------------------------------" << endl;
13+
if (t.isEmpty()) cout << "The tree is empty" << endl;
14+
else {
15+
cout << "Tree root is: " << t.root() << endl;
16+
cout << "Tree height is: " << t.height() << endl;
17+
cout << "Tree contains " << t.size() << " elements" << endl;
18+
}
19+
cout << "----------------------------------------" << endl;
20+
}
21+
22+
int main()
23+
{
24+
int values[N];
25+
26+
AVL<int> avl;
27+
28+
cout << "Populating the tree with " << N << " random values... ";
29+
for (unsigned i = 0; i < N; ++i) {
30+
values[i] = rand();
31+
avl.insert(values[i]);
32+
}
33+
cout << "Done" << endl;
34+
35+
printTreeStatus(avl);
36+
37+
for (unsigned i = 0; i < N; ++i) {
38+
unsigned idx = rand() % N;
39+
if (!avl.contains(values[idx]))
40+
cout << "ERROR: Value " << values[idx] << " was inserted and not found!" << endl;
41+
}
42+
43+
cout << "Now removing a random element from the tree... ";
44+
unsigned idx = rand() % N;
45+
avl.erase(values[idx]);
46+
cout << "Done" << endl;
47+
48+
printTreeStatus(avl);
49+
50+
cout << "Now removing the root of the tree " << N_ELEMS_TO_REMOVE << " times... ";
51+
for (unsigned i = 0; i < N_ELEMS_TO_REMOVE; ++i) {
52+
avl.erase(avl.root());
53+
}
54+
cout << "Done" << endl;
55+
56+
printTreeStatus(avl);
57+
58+
// Outputting to cerr so the output can be redirected with ./avl_demo 2> <name>.gvz
59+
cout << "Do you want to output the GraphViz representation of the tree to the cerr stream (Y/n)? ";
60+
char usrInput;
61+
cin >> usrInput;
62+
if (usrInput == 'Y' || usrInput == 'y') avl.toGraphViz(cerr, "AVL");
63+
64+
return 0;
65+
}
66+

0 commit comments

Comments
 (0)