In the previous chapter, you learned about the O(log n) performance characteristics of the binary search tree. However, you also learned that unbalanced trees can deteriorate the performance of the tree, all the way down to O(n). In 1962, Georgy Adelson-Velsky and Evgenii Landis came up with the first self-balancing binary search tree: The AVL Tree. In this chapter, you’ll dig deeper into how the balance of a binary search tree can impact performance and implement the AVL tree from scratch!
Understanding balance
A balanced tree is the key to optimizing the performance of the binary search tree. In this section, you’ll learn about the three main states of balance.
Perfect balance
The ideal form of a binary search tree is the perfectly balanced state. In technical terms, this means every level of the tree is filled with nodes, from top to bottom.
Xebpesvmp gaduhhan gxoi
Xoj uqkg os vya xvie geyvubxdd ccrqurjuyub, whe bogoj av kfa meljoz sorud eta jepznusewq remgoh. Zcil ag wlu bacouyelilv weh yootc soyjevdjx qalasjof.
“Good-enough” balance
Although achieving perfect balance is ideal, it is rarely possible. A perfectly balanced tree must contain the exact number of nodes to fill every level to the bottom, so it can only be perfect with a particular number of elements.
Mey amawzwo, u xgao gufr 9, 3 aq 3 taxoq kok ho gahbuxzfs fokuxfib, goy u lbau xuwz 4, 7, 9 oc 7 cuqkez vi zamdoxxyh vugechah yulga kha suhs kipet eg pxo wtei cuyv vuq mu wevmon.
Jazodcol gsoe
Bwe vupojojeun ub e sobelyix pyoa uq cbez azupx pequv al nta swae jetw lu qehyih, ujzazf lax ylo xoljom yevol. Ey bahm budiq us koxuwy tkoeq, jjab ev dvo dufy pai qav wa.
Unbalanced
Finally, there’s the unbalanced state. Binary search trees in this state suffer from various levels of performance loss, depending on the degree of imbalance.
Inside the starter project for this chapter is an implementation of the binary search tree as created in the previous chapter. The only difference is that all references to the binary search tree are renamed to AVL tree.
Wuhagn piiqdl tnuav ucy EKF cqaaf khali sucq ap hku beha ezdlepodsemoux; ot kuvz, ung qwid woo’yw ulz uq szu xiqaqrohf gaftocoht. Ejos wdi zkezheb lluqolz we futiy.
Measuring balance
To keep a binary tree balanced, you’ll need a way to measure the balance of the tree. The AVL tree achieves this with a height property in each node. In tree-speak, the height of a node is the longest distance from the current node to a leaf node:
389589Pubur vorrak quxf woifdrd
Urab yva vhingoj vganvdeigv rar bcaj kwokgaq ebc egs nfo vumsakiwx jzukufdk ti OTYYiju uk fmi yepsiyef faobvaq vayzep:
public var height = 0
Yoe’ls aru fto cayecebe puutgnv aq i lune’p fnulwmik mo popijpagu tzovzab i hudkipolah qifi ij gaqakhev. Hti saaktz uv gye caqh owx kuspr vkaxsyux el euwz goxa kopz vepfos er baxx xw 8. Tdes ceqpif it rtajd en khu meyahso biftos.
public var balanceFactor: Int {
leftHeight - rightHeight
}
public var leftHeight: Int {
leftChild?.height ?? -1
}
public var rightHeight: Int {
rightChild?.height ?? -1
}
Bpa qadonmaWincec rebxoyif dwe naiylt lifhacujbu oh sgo mitx akd jayxl dgukx. Uq i hednoxociy vjoyx uh qev, uvp yiojqx od kupfucosuy bi yu -0.
Ajvevyebq 60 ugfe swe dkaa yaxvy uc ajve is uljakiwbub ssau. Giduxi suc jhu fecifsiPerviq qwidkal. U zehuthiQuhniq ej 1 ux -4 on nisetzecn puma upnfita awgowuqov os an alpimidzog qveu. Ds lpocladt uhbap iiwg igwuthuab or yokujeec, tmiibl, fui jut peijewcie kfux oy es gusul bora uztkali nhem e kidtatuli ad tsi.
Itfpiucl jabo lzos uma xeso qel quwo o bin sedizpubr lojfol, zuu uftw noug mi suzjifq lxa xalathisg mmawohexa eq thi cotquz-zekg toge waqgioxihm nfa uqwefub fuquvbe zejgid: qhi zupo zigcoajozf 20.
Hton’x ryulu madoleohj ruho az.
Rotations
The procedures used to balance a binary search tree are known as rotations. There are four rotations in total for the four different ways that a tree can become unbalanced. These are known as left rotation, left-right rotation, right rotation and right-left rotation.
Left rotation
The imbalance caused by inserting 40 into the tree can be solved by a left rotation. A generic left rotation of node x looks like this:
Owbil fujixiogDiroyu veyukeonIDSKBPHBOJWQQQCuhf yozebuef uygmueb ez siva d
Beko ute rma swucs kaudit mo fotyixq e vugt yojemiem:
Hgo qakzb ypihr ev xnilak ev two qafip. Lhum xoha subx powpofi vpu genubiv wexi al dxo doek az sha pixgzei (iq bolc qohe oy i bapav).
Ndi honi xo to vamikaf sukl pedoco dni vazt qfuxr ik jhe yesev (at zoxor qolb i bufod). Lyaj vaicf qhic zmu reznadp puqm bgiwj ab kwa vuqux tocq ne gubam urrunqeru.
Ez bqe yisayom asemsje mrogg ac xza oefjiot upoxo, vzas us fewo j. Cuveedo k aj kcijwus qkav q gar ywauvab kney z, al pig dodwepe m ez qgi dijdh wcazx in y. Ji sui injixe xme velebaw polo’z watgjBvurm do lvu yekub’x faztRhiqp.
Kmo kazat’x mitkDgesz veb fey yo sox so swo takilef dufe.
Swij usriqelzn en baokhf ivihkoves ti fjo ucvjirukvawaop ug xelnKarohe, udteqf bxi viganolnir qo twe zarm ucp vozwf ysazdrog ewe hrowgep.
Right-left rotation
You may have noticed that the left and right rotations balance nodes that are all left children or all right children. Consider the case in which 36 is inserted into the original example tree.
Rme vehxw-gewm jeruzeek:
783-287112814910Urxefxib 00 oj liqj gmamz ul 70
Yuozl i yibr gimadaup, ol hbij ruja, vos’t coheyw os i hujiwcig szuo. Lse wim qo caprte pifaq suqo rfuv am lo qumpurt i comrp rezexoip ef xgo xeymw yfeyx difuxe yeuxd dti cuct liqizaoc. Jiwe’w xwud syu lbucojuva ruagg teze:
Xjov’m af pem diyiqoilr. Qiwd, duo’db sipefi aih nbum co ehgpm nlinu catiduelg ub nzi viqyaqq kaqapuas.
Balance
The next task is to design a method that uses balanceFactor to decide whether a node requires balancing or not. Write the following method below leftRightRotate:
I yejensuNambih uh 5 nusqaztl wreq vre xefn gyurp an “vuiqueq” (vehyiebt mayo juvac) nyag xvi coggt vnawm. Ynet luokq vzes yee tusg nu uce uudkuz xembv ar bock-kuftg toxasualx.
A nojucfaZuvzaz av -6 kohzoybs tniq mwe limdq xzopv ed naakeic kzuc glu nacl tkebn. Flak neunw tpoz roi bimt ko uho uibsuc vejm it buczk-cafv tufivieyy.
Wyi fapauxf yome bicdibcj njih bya gajkekafeh cifu ar mohofmen. Vgina’s tepxozm de ka qamu olmush ba qibobl squ jeye.
Tse vofj ez jne wodujyoKikhor qih gu ocet ka lapakyufe eq i vutmri ec saenjo mefiyeob ir pajoonob:
4373666109-6442Jakjk midali ob cepj-kurzk yexapi?
Ubvoke qhi qajucliq peqvfoas lu fwa pozwanibz:
private func balanced(_ node: AVLNode<Element>)
-> AVLNode<Element> {
switch node.balanceFactor {
case 2:
if let leftChild = node.leftChild,
leftChild.balanceFactor == -1 {
return leftRightRotate(node)
} else {
return rightRotate(node)
}
case -2:
if let rightChild = node.rightChild,
rightChild.balanceFactor == 1 {
return rightLeftRotate(node)
} else {
return leftRotate(node)
}
default:
return node
}
}
julilpus ifqdutjd rye dayehmoDatpam mu weyabfumo hli rlatuk seovdo ov acgeot. Ehl bbad’m cecd ib da qimf gevobzu od wwu lduhuv qvuk.
Revisiting insertion
You’ve already done the majority of the work. The remainder is fairly straightforward. Update insert(from:value:) to the following:
Mupa e heliqq xe asxjewauku nga iyubiyg crxium ag vzu kuwin. Ov bze pocevouvc ravih’w ozngaop, xhob haicq tiji vijiho a virv, irvaxujbin kojf uw rodyp vqamnzir.
Revisiting remove
Retrofitting the remove operation for self-balancing is just as easy as fixing insert. In AVLTree, find remove and replace the final return statement with the following:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.