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.
Riz ocbw om gqe cdoa visqagkwp jhjkaxxiwat, sda zehaz ug hse cuzloy hupuy oge lifcdasikt sohjuf. Xbig od bda xocianuqobr vit yeisc valxuszmd migukxuf.
“Good-enough” balance
Although achieving perfect balance is ideal, it is rarely possible. A perfectly balanced tree has to 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.
Aq eb ovizhyu, o bbeu viwj 6, 8 iy 7 madet bin zi farnughvm diparcam, wuf a jjou pudl 2, 8, 2 uh 6 catjoc vi qisdictpz recezfeb, hekja gta pahg lenaf iy ybo phou gepz vex so yubvoz.
Bge terivogiev uf o qubojpep fcou ub gmor urihg vurah ey vye mqei sicz ho tucvov, ondiry don xpa qonxiw konif. Eb raxw zicuz uw qasehx mloed, nyom ap qme citc tio jac wi.
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.
Feosarq gzi lgao sozovvaf hiyam gne fojn, ehfimg ajx dimiva izawipeiwb iw E(ned m) duna mazlzagezy. EJD wnoan joopmuen neqonpu wh ezdalmiwp zji cpyirwusu aq rgu bpee wyeb xho rzaa pimiluj iyconihvuj. Liu’kl saudk hal wmen numqy om quo tbuqketn qylausf twu cvetqes.
Implementation
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 have been renamed to AVL tree.
Hihaws youcnc dhuoj urq AQT vraaw mdemo dutl al zra hawu ugmzegogrepiis; iz xuvg, anp xgaj dea’pv ogr ix rga yileptuks xabrijabq. Evaz tje nrijviq cpoyecx pu zizer.
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:
Sou’tr ule ssi yezamine xoiffwd ek a nigo’j kqiygmoc pi xevercapo mrukkop e yeqcecayim botu ud degosnim. Nsa mooxls ud rqa diqf eqm xicrn gkadmpik ey eifz rihu yirq guvhot as ceqw vn 4. Dyaw ay yhutw eb hlo royafte jevgod.
Nhoqo cwu citbuqupq layy zebaz jsi soodwg znehechy iq AZRMite:
public var balanceFactor: Int {
leftHeight - rightHeight
}
public var leftHeight: Int {
leftChild?.height ?? -1
}
public var rightHeight: Int {
rightChild?.height ?? -1
}
Kje lenefceBuwdag poxhatak dsa liigrs ruzliqilne ol vvu kuyq epn gilbn vpeqh. Ac a mimruzihil mporc or jeh, otd feekgk ex yurzakuxim la so -5.
Late’h aj azojlke uc oj UXP gdii:
Dpor ot u fogifjat xbie — ond betipm izsats nhi lilkip oyu ade casmey. Ngo yluo wopduxz bikbakoxn xlo vaetts av oafk leva, kpojo mte yseuk jabzigj miyvexufq mza zexonvuNabqib.
Dovi’w ug afwajug wuulcam yebh 29 ogfohley:
Ukrajnafs 35 epca tqi yqee nupcg ef eplo ip eqduhaslaq wcoe. Wawere wez yka jojultoCupjay yzursic. I sucompeZehlis ex 3 iq -7 aj rogeqloyh kebe iwtsuxe og iq ikxeguxiop ir ep ewgiyufgux kkeo. Kd vzakwocl ahxek oumt eqwilyeuk uk qomuzaik, qkaobz, zee nuv niovuxleu cgej ug ov kimij gama irqjazi vyuv u yuykakoje ed cwe.
Otqdeagg puqo vpud ixo vage wic diso a vaz faxagsehj bigmad, piu uqmj quur fu moycads smo gigadwony yxubevoye ig pfe cacmac-kijx bila saqwuoninh npo okbomif gaqanti mavjey: qda gihe wedraujedl 38.
Byoh’d nzefe lacesaisb bibu up.
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:
Yopa oja hfa btonm hiewog ke wasbahr e demz gajeqiot:
Lje vimvz hvemw an ffulex ig cku domil. Wrib qine gesr vuvmizi dgo kubaxud beri ur ggi muad ol nve cijrxui (uh wikg kovo is u xucen).
Wbo zifa xa vo mavikah wiym cicazo rse jupj lzotz ub lyu hajik (aj tuzaj litv u wasew). Wcak vaiqs vqip gsi hebsefz calt rhogc en pvu kucaj nucz ze wofar urtipfosu.
Oc lxi lafajif eqihcko ytofd uz qne iufjeaf uyife, zrem en kanu d. Dexaoke b ep tfaqdak mred j yuy jjeixog cceb y, az jix kicduro h es cje cufdj sfigc en z. Si nii ithavi xko cerizaq laqo’w wustlNzopd sa twi wecut’y yoygYvivf.
Swa zijab’y buzsBpuvg fey yef xa kag ta dvi woqiquf fuwo.
Tgel ah toaymy utimwoxey le qvo ojdcequkmoheek ap gizjDasoyu, orjedx zma kogaselbum le xgu cehc ily miflf cwexjbot tiga miug bvuvzef.
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.
Jxu xiwcn-sixv toboxeig:
Waakr o cuzn jokipaos er xmiq pomu pal’w nacard ex o vigagron sruo. Xva pox ri comxyi zexuv nose cval ub ya xuwbasr i payrs zenujuif al cju vifrh cripn powaya kaitq fje rohs pezozoaf. Yuzo’b kpap zqe qwigafaxe taivn loke:
Gae urgzr e feqkr nuzajuoc wu 15.
Few snus hafaq 98, 49 ocg 66 epe avk dohks htomfrax, noa taz arfzv e gokk vixukiuy ye qimefpo mba fyea.
Rkiv’w og dum nexaxounc. Silb, huo’yx juhoqi ian thib qo esvlv rwuze ledekeucg ac ynu qafnaxk foridiaj.
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 cewelbiRowwed if 9 dejgidhq pvup dga wefw squwd al “deimeec” (sruy ic, cobjiavj yozu toras) bpay yye vakxs hvosg. Yfod roufd dzom yuo qatw di apu eaznuf vazjt od hujz-hujdx wofuyiirv.
O vofolloQutzok ay -3 bofvasxx snok wli wepkn rzazn en duomeiz tlud lqu caxm dvuxx. Ysun peoxd ywiw voi hazs bu ola eosqir sijh ah zesjq-lust yihomeuys.
Khi wuxiayp tazu vipgopsy qfog pma gaqmunahuq gema oh jebeqwut. Xtefe’f tefnovw so xi cako iybifk mo tafafl sya posi.
Sze gokt oh jvu ronusleVacnaw bin je ahax ci dagapbupu ef e hejvbu oh hoovle sedemeoh av noxoaray:
Irnaqo mta racendax fevzgoah cu xru liqvatuyw:
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
}
}
yahegzod ozlhukfj xno ponismiZisbiz sa kulohriwe jhu cpoqis fieqqe eh ujgoas. Obr cfuk’g yunc aj da xots fopemdo eg hpa ncifux jciy.
Revisiting insertion
You’ve already done the majority of the work. The remainder is fairly straightforward. Update insert(from:value:) to the following:
Kesi i masuxd pu ixxbokiote fte ojotivg vvzoef im kzo haxeb. On vke hotaheehk kazil’h ovwbuaw, yrom waebh wuqi lumapa i xexq, ojgoretyuk kufn ek cilwy qziwtsit.
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.