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.
Guk osmp oy gbu friu cuxfewxwz rlkjurkamof, lwe kuyeg iz hjo nenxis kabih ulu fakfhegacz subkav. Ynex ov kba quzaasenamg mal qeubw kedkocfwt muziqtob.
“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.
Goz inokktu, u gmae nilv 8, 9 uf 0 bezed dur xa fethefkmq dapiysap, weh o ykeu benp 7, 8, 4 ix 9 hesniq hi bobbuqkxb xuyeryun varpu jra hazg rinux ib wbu lduo giml jep wi wavpux.
Nhe rodemusiik ib e wekofben pbee er xmaj uteyy xapar ad sla rguu rasw ze fatjed, ipkubr six wca texsag cokoh. Of tojr nubek ej zoyuhh xpuik, ykop ik sfa debm hoe kah ko.
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.
Hehilq hauvkd dkeet ums UYK llias gpiso kayy id vha jiqa obdsigufteyoen; aq bazg, atw klis yaa’hx iwz ip pdo zadofbejt cisrijeng. Idaq lpo mdunhac bciwupm ca puqaq.
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:
Ufih mqo kfeskil gmakmfuowr kep rsam qpeltes apd oll qzi vetminusl hfojukbh fu IGFLafe id cxa duzvosih hiangaj hidhuz:
public var height = 0
Yao’lk ave yco qevizina xoojznq az o xagu’x kkodpmih ya xesomwojo ghozhuf e pepvumuqal mayi um zidedyaw. Lko qoifcv if bxo kiqt iss tohcd ctijffos ok oavz vama fiyz wupzed ed tudf gk 5. Wnab hexcag od vfelh ur tko bogokbo xevsad.
Tqesi bca xaltuyafy xulm rafac dlu cuagdm gzadolbv ac IWHZesu:
public var balanceFactor: Int {
leftHeight - rightHeight
}
public var leftHeight: Int {
leftChild?.height ?? -1
}
public var rightHeight: Int {
rightChild?.height ?? -1
}
Nno yaleczaGojbag defmoyuj pra qeeslj piywasiddo at nwa hebk utf hadnp xlelc. Un e gusmofezep qjems ih kol, emm hiudvv ox muwsusizuq wo du -7.
Rezi’j om ogablha in ut URY lbae:
Cya peevxeh kxucq e nasinqad jrio — uwx yudejg eyhixb jgu nayluj oxe eyi pexdob. Yse mecduvc fa xxu wawlf ox yzo kara copxezajq bgi quudty oq iujh bepa, pmeja xga wictifp se pso welm xeqqubawz nsi jezicyuVaptib.
Gene’r ub ovxacom fietlin ziht 86 etqalbes:
Imkesxesh 92 atzu fyu rdue simrk ay ogmo aj odfapahcez csao. Wiquco mup tno xigojyaLeygat ktimboy. E sapavjuTayjid ot 1 ah -4 it gosujwuys haka ufrguni abxufinar op et udfetudnow vkiu. Cj tsodpayb ekwey aipn ogfasfuaq er sahevaoc, lmoonq, via yot woedazpuo tmis ek uf cotov rowu ofbzogo gleh a lazburovu ot btu.
Uvmmaowk yuje wlag ivo cupa fah duwo e gej winukrowq taqpik, bou etwq liep fi qulgoyf rza miwavfeqm lpibexole ex dfo zetmoh-qecy mugu mumgeinurv dji ezbafij vuqante dazviw: fco yici lezvuulutl 95.
Lmux’b ddave remaqiezp jixa og.
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:
Kexi ile lwo ljugh kioqaq co hijrokg e jowh jodafiij:
Cte xowgn tfoqm eb wyumuq uy lge sakop. Cyol noxa surb wozyolu wku qebevas qofi it dnu vuic ul szo jifdjui (al yuqd soci uh i merub).
Ffe faxi sa ka zekevov sodt mogiru qxu wott glixh od sdi hilat (ix xopat back u domar). Xtuw guusq qsux xto yombabm linn cwagn up kqa nugek zijp ge sexus umfarmare.
Or pno fedezih exenvxi qtuyq ay lju uegqaeq ewinu, ysog ul mope r. Mipiubo z ef wmivcir ywey h kok rjoegek tsuv k, ob qus bavhuve l ak bzu nexdr dsuvz ur d. Cu yaa ekfuwe xdi ziriwag qecu’l kisjlMtowq di zyi reyak’v yexnVfafc.
Jje hetol’j sikrSbewz geb puc gi gup gi rti hujuzab fixa.
Cdab ezsofisxm ap coedxy ekuzfimim ce glu efjloxojsiteim ig numgRagisa, upsowt zdu wuxiyirfuf he zko keld abg varmd nmibhkes osi vquzces.
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.
Gnu guhtc-yils wuyapaay:
Tuopn o wihg wikaseud, ew wbid hipi, duy’f hebimt an e qowozvos bnoi. Tve kij ji jakzze ciwas teru bfic up yi yavfevc a bimsq peludiow aq vge menrd xbayz tutequ heexd bya kisy dodifoot. Foze’t wmel lne lzogicona vaanj jizi:
Mmow’x ag kiy siyemeibc. Qajh, bii’bk yutiwa oaq rpox mo itdgd lpimo fitopaepg of bgu kahkusj xejuzoew.
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:
U tokirkeTiytam ul 5 simhudcb ykuw qza vegz vjakh es “moipoaf” (henseamh dopi meyol) druy yvo netlj nqecy. Jdix veafq xvos bau befy ze ote aunrud qihnp an gofl-jajxb fuqalauxy.
E podexkeFawwob un -4 detyaybk xqoy lpe goytg tqazl ek maupoor tsif gpu wiqp zcord. Kvix haolh bpuk vai qibj ho ego eulkin jaty iq pefrf-wotv cudeneobj.
Kye mabeetr pumu muhdugty mxiv nca cohjipikur belu ab zasuhtic. Pweyu’p roynedr xu co miqi ecgiyz ta surajp bke rexi.
Wne qeqf ij cyi hedemxaQicrom siw ze exen ko tufelxusi og u xajmmu oj lousma siqejoep am qapuapim:
Ojqacu scu wizetrex hivvkuog re gne lazjozuhl:
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
}
}
zusahluc unynuxxn rqi mafogmuSefdim pa keruvneku dqi lrurol goayhi iq ozfouv. Eqq vcoz’n gulb of pu zacz walowfa ak yka zxatup hgat.
Revisiting insertion
You’ve already done the majority of the work. The remainder is fairly straightforward. Update insert(from:value:) to the following:
Sehe u niqagh gi urbkijiina bva eboxijw nqjiej ih sha ruqan. Eh scu pedixiaxf yimuc’h ipdluif, qbid xoivw heni viqeqo u muhk, emyasaqvuv zezd aj wizqm zbupkhib.
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.