GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||
GeezerVison is showing www.w3schools.com — Python AVL Trees
❮
❯
Python TutorialPython HOME Python Intro Python Get Started Python Syntax Python Output Python Comments Python Variables
Python Variables
Variable Names
Assign Multiple Values
Output Variables
Global Variables
Variable Exercises
Code Challenge
Python Data Types
Python Numbers
Python Casting
Python Strings
Python Strings
Slicing Strings
Modify Strings
Concatenate Strings
Format Strings
Escape Characters
String Methods
String Exercises
Code Challenge
Python Booleans
Python Operators
Python Operators
Arithmetic Operators
Assignment Operators
Ternary Operator
Comparison Operators
Logical Operators
Identity Operators
Membership Operators
Bitwise Operators
Operator Precedence
Code Challenge
Python Lists
Python Lists
Access List Items
Change List Items
Add List Items
Remove List Items
Loop Lists
List Comprehension
Sort Lists
Copy Lists
Join Lists
List Methods
List Exercises
Code Challenge
Python Tuples
Python Tuples
Access Tuples
Update Tuples
Unpack Tuples
Loop Tuples
Join Tuples
Tuple Methods
Tuple Exercises
Code Challenge
Python Sets
Python Sets
Access Set Items
Add Set Items
Remove Set Items
Loop Sets
Join Sets
Frozenset
Set Methods
Set Exercises
Code Challenge
Python Dictionaries
Python Dictionaries
Access Items
Change Items
Add Items
Remove Items
Loop Dictionaries
Copy Dictionaries
Nested Dictionaries
Dictionary Methods
Dictionary Exercises
Code Challenge
Python If...Else
Python If
Python Elif
Python Else
Shorthand If
Logical Operators
Nested If
Pass Statement
Code Challenge
Python Match
Python While Loops
Python For Loops
Python Functions
Python Functions
Python Arguments
Python *args / **kwargs
Python Scope
Python Decorators
Python Lambda
Python Recursion
Python Generators
Code Challenge
Python Range
Python Arrays
Python Iterators
Python Modules
Python Dates
Python Math
Python JSON
Python RegEx
Python PIP
Python Try...Except
Python String Formatting
Python None
Python User Input
Python VirtualEnv
Python ClassesPython OOP Python Classes/Objects Python __init__ Method Python self Parameter Python Class Properties Python Class Methods Python Magic Methods Python Inheritance Python Polymorphism Python Encapsulation Python Inner ClassesFile HandlingPython File Handling Python Read Files Python Write/Create Files Python Delete FilesPython ModulesNumPy Tutorial Pandas Tutorial SciPy Tutorial Django TutorialPython MatplotlibMatplotlib Intro Matplotlib Get Started Matplotlib Pyplot Matplotlib Plotting Matplotlib Markers Matplotlib Line Matplotlib Labels Matplotlib Grid Matplotlib Subplot Matplotlib Scatter Matplotlib Bars Matplotlib Histograms Matplotlib Pie ChartsMachine LearningGetting Started Mean Median Mode Standard Deviation Percentile Data Distribution Normal Data Distribution Scatter Plot Linear Regression Polynomial Regression Multiple Regression Scale Train/Test Decision Tree Confusion Matrix Hierarchical Clustering Logistic Regression Grid Search Categorical Data K-means Bootstrap Aggregation Cross Validation AUC - ROC Curve K-nearest neighborsPython DSAPython DSA Lists and Arrays Stacks Queues Linked Lists Hash Tables Trees Binary Trees Binary Search Trees AVL Trees Graphs Linear Search Binary Search Bubble Sort Selection Sort Insertion Sort Quick Sort Counting Sort Radix Sort Merge SortPython MySQLMySQL Get Started MySQL Create Database MySQL Create Table MySQL Insert MySQL Select MySQL Where MySQL Order By MySQL Delete MySQL Drop Table MySQL Update MySQL Limit MySQL JoinPython MongoDBMongoDB Get Started MongoDB Create DB MongoDB Collection MongoDB Insert MongoDB Find MongoDB Query MongoDB Sort MongoDB Delete MongoDB Drop Collection MongoDB Update MongoDB LimitPython CertPython CertificatePython How ToRemove List Duplicates Reverse a String Add Two NumbersPython ExamplesPython Examples Python Videos Python Compiler Python Exercises Python Quiz Python Challenges Python Practice Problems Python Server Python Syllabus Python Study Plan Python Interview Q&A Python TrainingPython ReferencePython Overview Python Built-in Functions
abs()
all()
any()
ascii()
bin()
bool()
bytearray()
bytes()
callable()
chr()
compile()
complex()
delattr()
dict()
dir()
divmod()
enumerate()
eval()
exec()
filter()
float()
format()
frozenset()
getattr()
globals()
hasattr()
hex()
id()
input()
int()
isinstance()
issubclass()
iter()
len()
list()
locals()
map()
max()
memoryview()
min()
next()
object()
oct()
open()
ord()
pow()
print()
range()
reversed()
round()
set()
setattr()
slice()
sorted()
str()
sum()
super()
tuple()
type()
vars()
zip()
Python String Methods
capitalize()
casefold()
center()
count()
encode()
endswith()
expandtabs()
find()
format()
format_map()
index()
isalnum()
isalpha()
isascii()
isdecimal()
isdigit()
isidentifier()
islower()
isnumeric()
isprintable()
isspace()
istitle()
isupper()
join()
ljust()
lower()
lstrip()
maketrans()
partition()
replace()
rfind()
rindex()
rjust()
rpartition()
rsplit()
rstrip()
split()
splitlines()
startswith()
strip()
swapcase()
title()
translate()
upper()
zfill()
Python List Methods
Python Dictionary Methods
Python Tuple Methods
Python Set Methods
add()
clear()
copy()
difference()
difference_update()
discard()
intersection()
intersection_update()
isdisjoint()
issubset()
<
issuperset()
>
pop()
remove()
symmetric_difference()
symmetric_difference_update()
union()
update()
Python File Methods
close()
fileno()
flush()
isatty()
read()
readable()
readline()
readlines()
seek()
seekable()
tell()
truncate()
writable()
write()
writelines()
Python Keywords
and
as
assert
async
await
break
case
class
continue
def
del
elif
else
except
False
finally
for
from
global
if
import
in
is
lambda
match
None
nonlocal
not
or
pass
raise
return
True
try
while
with
yield
Python Exceptions
ArithmeticError
AssertionError
AttributeError
Exception
EOFError
FloatingPointError
GeneratorExit
ImportError
IndentationError
IndexError
KeyError
KeyboardInterrupt
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
ReferenceError
RuntimeError
StopIteration
SyntaxError
TabError
SystemError
SystemExit
TypeError
UnboundLocalError
UnicodeError
UnicodeEncodeError
UnicodeDecodeError
UnicodeTranslateError
ValueError
ZeroDivisionError
Python Glossary
Module ReferenceBuilt-in Modules
abc
aifc
argparse
array
ast
asyncio
atexit
base64
bdb
binascii
bisect
builtins
bz2
calendar
cgi
cgitb
cmd
code
codecs
codeop
collections
colorsys
concurrent
configparser
contextlib
contextvars
copy
copyreg
csv
ctypes
curses
dataclasses
datetime
dbm
decimal
difflib
dis
doctest
email
encodings
ensurepip
enum
errno
faulthandler
filecmp
fileinput
fnmatch
fractions
ftplib
functools
gc
getopt
getpass
gettext
glob
graphlib
gzip
hashlib
heapq
hmac
html
http
idlelib
imaplib
imghdr
imp
importlib
inspect
io
json
keyword
linecache
locale
logging
lzma
mailbox
mailcap
marshal
math
mimetypes
mmap
modulefinder
msilib
msvcrt
multiprocessing
netrc
nntplib
numbers
nis
ntpath
operator
optparse
os
pathlib
pdb
pickle
pickletools
pipes
pkgutil
platform
plistlib
poplib
posix
pprint
profile
pstats
pty
pyclbr
pydoc
py_compile
queue
quopri
random
re
reprlib
resource
rlcompleter
runpy
sched
secrets
select
selectors
shelve
shlex
shutil
signal
site
smtplib
socket
socketserver
sqlite3
ssl
stat
statistics
string
stringprep
struct
subprocess
sunau
symtable
sys
sysconfig
tabnanny
tarfile
telnetlib
tempfile
termios
test
textwrap
threading
time
timeit
tkinter
token
tokenize
tomllib
trace
traceback
tracemalloc
tty
turtle
types
typing
unicodedata
unittest
urllib
uuid
venv
warnings
wave
weakref
webbrowser
wsgiref
xdrlib
xml
xmlrpc
zipapp
zipfile
zipimport
zlib
zoneinfo
Random Module
seed()
getstate()
setstate()
getrandbits()
randrange()
randint()
choice()
choices()
shuffle()
sample()
random()
uniform()
triangular()
Requests Module
Statistics Module
statistics.harmonic_mean()
statistics.mean()
statistics.median()
statistics.median_grouped()
statistics.median_high()
statistics.median_low()
statistics.mode()
statistics.pstdev()
statistics.stdev()
statistics.pvariance()
statistics.variance()
Math Module
math.acos()
math.acosh()
math.asin()
math.asinh()
math.atan()
math.atan2()
math.atanh()
math.ceil()
math.comb()
math.copysign()
math.cos()
math.cosh()
math.degrees()
math.dist()
math.erf()
math.erfc()
math.exp()
math.expm1()
math.fabs()
math.factorial()
math.floor()
math.fmod()
math.frexp()
math.fsum()
math.gamma()
math.gcd()
math.hypot()
math.isclose()
math.isfinite()
math.isinf()
math.isnan()
math.isqrt()
math.ldexp()
math.lgamma()
math.log()
math.log10()
math.log1p()
math.log2()
math.perm()
math.pow()
math.prod()
math.radians()
math.remainder()
math.sin()
math.sinh()
math.sqrt()
math.tan()
math.tanh()
math.trunc()
math.e
math.inf
math.nan
math.pi
math.tau
cMath Module
cmath.acos(x)
cmath.acosh(x)
cmath.asin(x)
cmath.asinh(x)
cmath.atan(x)
cmath.atanh(x)
cmath.cos(x)
cmath.cosh(x)
cmath.exp(x)
cmath.isclose()
cmath.isfinite(x)
cmath.isinf(x)
cmath.isnan(x)
cmath.log(x[, base])
cmath.log10(x)
cmath.phase()
cmath.polar()
cmath.rect()
cmath.sin(x)
cmath.sinh(x)
cmath.sqrt(x)
cmath.tan(x)
cmath.tanh(x)
cmath.e
cmath.inf
cmath.infj
cmath.nan
cmath.nanj
cmath.pi
cmath.tau
Python AVL TreesThe AVL Tree is a type of Binary Search Tree named after two Soviet inventors Georgy Adelson-Velsky and Evgenii Landis who invented the AVL Tree in 1962. AVL trees are self-balancing, which means that the tree height is kept to a minimum so that a very fast runtime is guaranteed for searching, inserting and deleting nodes, with time complexity \(O( \log n)\).
Share
AVL TreesThe only difference between a regular Binary Search Tree and an AVL Tree is that AVL Trees do rotation operations in addition, to keep the tree balance. A Binary Search Tree is in balance when the difference in height between left and right subtrees is less than 2. By keeping balance, the AVL Tree ensures a minimum tree height, which means that search, insert, and delete operations can be done really fast. (unbalanced) Height: 6 (self-balancing) Height: 3 The two trees above are both Binary Search Trees, they have the same nodes, and the same in-order traversal (alphabetical), but the height is very different because the AVL Tree has balanced itself. Step through the building of an AVL Tree in the animation below to see how the balance factors are updated, and how rotation operations are done when required to restore the balance. Continue reading to learn more about how the balance factor is calculated, how rotation operations are done, and how AVL Trees can be implemented. Left and Right RotationsTo restore balance in an AVL Tree, left or right rotations are done, or a combination of left and right rotations. The previous animation shows one specific left rotation, and one specific right rotation. But in general, left and right rotations are done like in the animation below. Notice how the subtree changes its parent. Subtrees change parent in this way during rotation to maintain the correct in-order traversal, and to maintain the BST property that the left child is less than the right child, for all nodes in the tree. Also keep in mind that it is not always the root node that become unbalanced and need rotation. The Balance FactorA node's balance factor is the difference in subtree heights. The subtree heights are stored at each node for all nodes in an AVL Tree, and the balance factor is calculated based on its subtree heights to check if the tree has become out of balance. The height of a subtree is the number of edges between the root node of the subtree and the leaf node farthest down in that subtree. The Balance Factor (\(BF\)) for a node (\(X\)) is the difference in height between its right and left subtrees. \[ BF(X) = height(rightSubtree(X)) - height(leftSubtree(X)) \] Balance factor values
If the balance factor is less than -1, or more than 1, for one or more nodes in the tree, the tree is considered not in balance, and a rotation operation is needed to restore balance. Let's take a closer look at the different rotation operations that an AVL Tree can do to regain balance. The Four "out-of-balance" CasesWhen the balance factor of just one node is less than -1, or more than 1, the tree is regarded as out of balance, and a rotation is needed to restore balance. There are four different ways an AVL Tree can be out of balance, and each of these cases require a different rotation operation.
See animations and explanations of these cases below. The Left-Left (LL) CaseThe node where the unbalance is discovered is left heavy, and the node's left child node is also left heavy. When this LL case happens, a single right rotation on the unbalanced node is enough to restore balance. Step through the animation below to see the LL case, and how the balance is restored by a single right rotation. As you step through the animation above, two LL cases happen:
Note: The second time the LL case happens in the animation above, a right rotation is done, and L goes from being the right child of D to being the left child of P. Rotations are done like that to keep the correct in-order traversal ('B, C, D, L, P, Q' in the animation above). Another reason for changing parent when a rotation is done is to keep the BST property, that the left child is always lower than the node, and that the right child always higher. The Right-Right (RR) CaseA Right-Right case happens when a node is unbalanced and right heavy, and the right child node is also right heavy. A single left rotation at the unbalanced node is enough to restore balance in the RR case. The RR case happens two times in the animation above:
The Left-Right (LR) CaseThe Left-Right case is when the unbalanced node is left heavy, but its left child node is right heavy. In this LR case, a left rotation is first done on the left child node, and then a right rotation is done on the original unbalanced node. Step through the animation below to see how the Left-Right case can happen, and how the rotation operations are done to restore balance. As you are building the AVL Tree in the animation above, the Left-Right case happens 2 times, and rotation operations are required and done to restore balance:
The Right-Left (RL) CaseThe Right-Left case is when the unbalanced node is right heavy, and its right child node is left heavy. In this case we first do a right rotation on the unbalanced node's right child, and then we do a left rotation on the unbalanced node itself. Step through the animation below to see how the Right-Left case can occur, and how rotations are done to restore the balance. After inserting node B, we get a Right-Left case because node A becomes unbalanced and right heavy, and its right child is left heavy. To restore balance, a right rotation is first done on node F, and then a left rotation is done on node A. The next Right-Left case occurs after nodes G, E, and D are added. This is a Right-Left case because B is unbalanced and right heavy, and its right child F is left heavy. To restore balance, a right rotation is first done on node F, and then a left rotation is done on node B. Retracing in AVL TreesAfter inserting or deleting a node in an AVL tree, the tree may become unbalanced. To find out if the tree is unbalanced, we need to update the heights and recalculate the balance factors of all ancestor nodes. This process, known as retracing, is handled through recursion. As the recursive calls propagate back to the root after an insertion or deletion, each ancestor node's height is updated and the balance factor is recalculated. If any ancestor node is found to have a balance factor outside the range of -1 to 1, a rotation is performed at that node to restore the tree's balance. In the simulation below, after inserting node F, the nodes C, E and H are all unbalanced, but since retracing works through recursion, the unbalance at node H is discovered and fixed first, which in this case also fixes the unbalance in nodes E and C. After node F is inserted, the code will retrace, calculating balancing factors as it propagates back up towards the root node. When node H is reached and the balancing factor -2 is calculated, a right rotation is done. Only after this rotation is done, the code will continue to retrace, calculating balancing factors further up on ancestor nodes E and C. Because of the rotation, balancing factors for nodes E and C stay the same as before node F was inserted. AVL Tree Implementation in PythonThis code is based on the BST implementation on the previous page, for inserting nodes. There is only one new attribute for each node in the AVL tree compared to the BST, and that is the height, but there are many new functions and extra code lines needed for the AVL Tree implementation because of how the AVL Tree rebalances itself. The implementation below builds an AVL tree based on a list of characters, to create the AVL Tree in the simulation above. The last node to be inserted 'F', also triggers a right rotation, just like in the simulation above. ExampleImplement AVL Tree in Python:
class TreeNode:
Try it Yourself »
def __init__(self, data): self.data = data self.left = None self.right = None self.height = 1 def getHeight(node): if not node: return 0 return node.height def getBalance(node): if not node: return 0 return getHeight(node.left) - getHeight(node.right) def rightRotate(y): print('Rotate right on node',y.data) x = y.left T2 = x.right x.right = y y.left = T2 y.height = 1 + max(getHeight(y.left), getHeight(y.right)) x.height = 1 + max(getHeight(x.left), getHeight(x.right)) return x def leftRotate(x): print('Rotate left on node',x.data) y = x.right T2 = y.left y.left = x x.right = T2 x.height = 1 + max(getHeight(x.left), getHeight(x.right)) y.height = 1 + max(getHeight(y.left), getHeight(y.right)) return y def insert(node, data): if not node: return TreeNode(data) if data < node.data: node.left = insert(node.left, data) elif data > node.data: node.right = insert(node.right, data) # Update the balance factor and balance the tree node.height = 1 + max(getHeight(node.left), getHeight(node.right)) balance = getBalance(node) # Balancing the tree # Left Left if balance > 1 and getBalance(node.left) >= 0: return rightRotate(node) # Left Right if balance > 1 and getBalance(node.left) < 0: node.left = leftRotate(node.left) return rightRotate(node) # Right Right if balance < -1 and getBalance(node.right) <= 0: return leftRotate(node) # Right Left if balance < -1 and getBalance(node.right) > 0: node.right = rightRotate(node.right) return leftRotate(node) return node def inOrderTraversal(node): if node is None: return inOrderTraversal(node.left) print(node.data, end=", ") inOrderTraversal(node.right) # Inserting nodes root = None letters = ['C', 'B', 'E', 'A', 'D', 'H', 'G', 'F'] for letter in letters: root = insert(root, letter) inOrderTraversal(root) AVL Delete Node ImplementationWhen deleting a node that is not a leaf node, the AVL Tree requires the To delete a node in an AVL Tree, the same code to restore balance is needed as for the code to insert a node. ExampleDelete Node:
def minValueNode(node):
Try it Yourself »
current = node while current.left is not None: current = current.left return current def delete(node, data): if not node: return node if data < node.data: node.left = delete(node.left, data) elif data > node.data: node.right = delete(node.right, data) else: if node.left is None: temp = node.right node = None return temp elif node.right is None: temp = node.left node = None return temp temp = minValueNode(node.right) node.data = temp.data node.right = delete(node.right, temp.data) return node def inOrderTraversal(node): if node is None: return inOrderTraversal(node.left) print(node.data, end=", ") inOrderTraversal(node.right) # Inserting nodes root = None letters = ['C', 'B', 'E', 'A', 'D', 'H', 'G', 'F'] for letter in letters: root = insert(root, letter) inOrderTraversal(root) Time Complexity for AVL TreesTake a look at the unbalanced Binary Search Tree below. Searching for "M" means that all nodes except 1 must be compared. But searching for "M" in the AVL Tree below only requires us to visit 4 nodes. So in worst case, algorithms like search, insert, and delete must run through the whole height of the tree. This means that keeping the height (h) of the tree low, like we do using AVL Trees, gives us a lower runtime. (unbalanced) (self-balancing) See the comparison of the time complexities between Binary Search Trees and AVL Trees below, and how the time complexities relate to the height (\(h\)) of the tree, and the number of nodes (\(n\)) in the tree.
\(O( \log n)\) ExplainedThe fact that the time complexity is \(O(h) = O( \log n)\) for search, insert, and delete on an AVL Tree with height \(h\) and nodes \(n\) can be explained like this: Imagine a perfect Binary Tree where all nodes have two child nodes except on the lowest level, like the AVL Tree below. The number of nodes on each level in such an AVL Tree are: \[1, 2, 4, 8, 16, 32, ..\] Which is the same as: \[2^0, 2^1, 2^2, 2^3, 2^4, 2^5, ..\] To get the number of nodes \(n\) in a perfect Binary Tree with height \(h=3\), we can add the number of nodes on each level together: \[n_3=2^0 + 2^1 + 2^2 + 2^3 = 15\] Which is actually the same as: \[n_3=2^4 - 1 = 15\] And this is actually the case for larger trees as well! If we want to get the number of nodes \(n \) in a tree with height \(h=5 \) for example, we find the number of nodes like this: \[n_5=2^6 - 1 = 63\] So in general, the relationship between the height \(h \) of a perfect Binary Tree and the number of nodes in it \(n \), can be expressed like this: \[n_h = 2^{h+1} - 1\] Note: The formula above can also be found by calculating the sum of the geometric series \(2^0 + 2^1 + 2^2+ 2^3 + ... + 2^n \) We know that the time complexity for searching, deleting, or inserting a node in an AVL tree is \(O(h) \), but we want to argue that the time complexity is actually \(O(\log(n)) \), so we need to find the height \(h\) described by the number of nodes \(n\): \[ \begin{equation} \begin{aligned} n & = 2^{h+1}-1 \\ n+1 & = 2^{h+1} \\ \log_2(n+1) & = \log_2(2^{h+1}) \\ h & = \log_2(n+1) - 1 \\ \\ O(h) & = O(\log{n}) \end{aligned} \end{equation} \] How the last line above is derived might not be obvious, but for a Binary Tree with a lot of nodes (big \(n\)), the "+1" and "-1" terms are not important when we consider time complexity. For more details on how to calculate the time complexity using Big O notation, see this page. The math above shows that the time complexity for search, delete, and insert operations on an AVL Tree \(O(h) \), can actually be expressed as \(O(\log{n}) \), which is fast, a lot faster than the time complexity for BSTs which is \(O(n) \). Free account Track your progress
XP earned 0
Day streak 0
Spaces 0
League —
New Learn in Adventure Mode W3Schools Adventure AppCoding fundamentals as bite-sized lessons and challenges.
×
Contact SalesIf you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: Report ErrorIf you want to report an error, or if you want to make a suggestion, send us an e-mail: Top TutorialsHTML TutorialCSS Tutorial JavaScript Tutorial How To Tutorial SQL Tutorial Python Tutorial W3.CSS Tutorial Bootstrap Tutorial PHP Tutorial Java Tutorial C++ Tutorial jQuery Tutorial Top ReferencesHTML ReferenceCSS Reference JavaScript Reference SQL Reference Python Reference W3.CSS Reference Bootstrap Reference PHP Reference HTML Colors Java Reference AngularJS Reference jQuery Reference
W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning.
Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookies and privacy policy. Copyright 1999-2026 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS. | |||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |