Skip to content

Commit 6276136

Browse files
author
Alejandro Fernández Suárez
committed
AVL tree added, but there's still a bug in the erasure method
1 parent f1473fa commit 6276136

File tree

5 files changed

+305
-12
lines changed

5 files changed

+305
-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: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
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+
tree = tree->erase(x);
55+
numNodes--;
56+
}
57+
}
58+
59+
void toGraphViz(std::ostream &stream, std::string name) const {
60+
if (!isEmpty()) {
61+
stream << "digraph " << name << " {" << std::endl;
62+
tree->toGraphViz(stream);
63+
stream << "}" << std::endl;
64+
}
65+
}
66+
67+
private:
68+
69+
struct Node {
70+
Node *left, *right;
71+
T value;
72+
unsigned height;
73+
74+
Node(const T &x) : left(0), right(0), value(x), height(1) {}
75+
76+
bool contains(const T &x) const {
77+
if (value == x) return true;
78+
else if (x < value && left != 0) return left->contains(x);
79+
else if (right != 0) return right->contains(x);
80+
else return false;
81+
}
82+
83+
Node *insert(const T &x) {
84+
if (x <= value) {
85+
if (left == 0) left = new Node(x);
86+
else left = left->insert(x);
87+
}
88+
else {
89+
if (right == 0) right = new Node(x);
90+
else right = right->insert(x);
91+
}
92+
93+
return update();
94+
}
95+
96+
Node *erase(const T &x) {
97+
if (value == x) {
98+
if (left == 0 && right == 0) {
99+
delete this;
100+
return 0;
101+
} else if (left == 0) {
102+
*this = *right;
103+
delete right;
104+
} else if (right == 0) {
105+
*this = *left;
106+
delete left;
107+
} else {
108+
// Tracing path to rightmost leaf of the left subtree
109+
std::stack<Node*> trace;
110+
111+
Node *current = left;
112+
while (current->right != 0) {
113+
trace.push(current);
114+
current = current->right;
115+
}
116+
117+
value = current->value;
118+
Node *lsubtree = current->left;
119+
delete current;
120+
121+
if (trace.empty()) trace.push(left);
122+
123+
trace.top()->right = lsubtree;
124+
125+
do {
126+
trace.top()->update();
127+
trace.pop();
128+
} while (!trace.empty());
129+
}
130+
return update();
131+
}
132+
else if (x < value) {
133+
if (left != 0) {
134+
left = left->erase(x);
135+
return update();
136+
} else return this;
137+
}
138+
else {
139+
if (right != 0) {
140+
right = right->erase(x);
141+
return update();
142+
} else return this;
143+
}
144+
}
145+
146+
Node *update() {
147+
updateHeight();
148+
149+
if (getBF(this) >= 2) {
150+
if (getBF(left) <= -1) LR();
151+
return LL();
152+
} else if (getBF(this) <= -2) {
153+
if (getBF(right) >= 1) RL();
154+
return RR();
155+
} else return this;
156+
}
157+
158+
void updateHeight() { height = std::max(getHeight(left), getHeight(right)) + 1; }
159+
160+
void LR() {
161+
Node *lrcopy = left->right;
162+
left->right = lrcopy->left;
163+
lrcopy->left = left;
164+
left = lrcopy;
165+
left->left->updateHeight();
166+
left->updateHeight();
167+
updateHeight();
168+
}
169+
170+
void RL() {
171+
Node *rlcopy = right->left;
172+
right->left = rlcopy->right;
173+
rlcopy->right = right;
174+
right = rlcopy;
175+
right->right->updateHeight();
176+
right->updateHeight();
177+
updateHeight();
178+
}
179+
180+
Node *LL() {
181+
Node *lcopy = left;
182+
left = left->right;
183+
lcopy->right = this;
184+
lcopy->left->updateHeight();
185+
lcopy->right->updateHeight();
186+
lcopy->updateHeight();
187+
return lcopy;
188+
}
189+
190+
Node *RR() {
191+
Node *rcopy = right;
192+
right = right->left;
193+
rcopy->left = this;
194+
rcopy->left->updateHeight();
195+
rcopy->right->updateHeight();
196+
rcopy->updateHeight();
197+
return rcopy;
198+
}
199+
200+
static int getBF(const Node *t) {
201+
return getHeight(t->left) - getHeight(t->right);
202+
}
203+
204+
static int getHeight(const Node *t) {
205+
return t == 0 ? 0 : t->height;
206+
}
207+
208+
void toGraphViz(std::ostream &stream) const {
209+
stream << value << ";" << std::endl;
210+
if (left != 0) {
211+
stream << left->value << ";" << std::endl;
212+
stream << value << "->" << left->value << ";" << std::endl;
213+
left->toGraphViz(stream);
214+
}
215+
if (right != 0) {
216+
stream << right->value << ";" << std::endl;
217+
stream << value << "->" << right->value << ";" << std::endl;
218+
right->toGraphViz(stream);
219+
}
220+
}
221+
};
222+
223+
Node *tree;
224+
unsigned numNodes;
225+
};
226+
227+
} // namespace alg
228+
229+
#endif // _ALG_AVL_HPP
230+

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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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 = 4096*8;
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 " << N_ELEMS_TO_REMOVE << " random elements for the tree... ";
44+
for (unsigned i = 0; i < N_ELEMS_TO_REMOVE; ++i) {
45+
unsigned idx = rand() % N;
46+
avl.erase(values[idx]);
47+
}
48+
cout << "Done" << endl;
49+
50+
printTreeStatus(avl);
51+
52+
cout << "Do you want to see the GraphViz representation of the Tree (Y/n)? ";
53+
char usrInput;
54+
cin >> usrInput;
55+
if (usrInput == 'Y' || usrInput == 'y') avl.toGraphViz(cout, "AVL");
56+
57+
return 0;
58+
}
59+

0 commit comments

Comments
 (0)