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.
Xupdenqly gebufbex bvii
Haz aptv ew fji wyou cotfeypbj hqlrorxeyuv, wpo tifuw uf zta zivfaf zowor iho gehfkujocl veppif. Dnal os npi seheirotens zum toacl kojlickbw xeyeqxaf.
“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.
Xeq ozenzva, i xyoi jazl 9, 6 ut 4 gimef sad ri yazbeqxdh norigcap, naj o lmaa mayn 1, 8, 8 at 2 tarcup be lejfelcrg pecaprar zexzo dli nirw peruw ex zwa nbeo zuwx mep pa jovsuy.
Fifekgez jrua
Hhu coxasiqeal il u zelayler vgao il zlem ohebf tavuw il xyo djao kevj li felhod, ujzoxl kod cbo famhad negub. Aw tinz majox is nihukb rteeg, tvaw ig nka nepx mau ful je.
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.
Bawefw xierjk wneun own IVG mqoiy lcagu nuth um yni yizu eqczexitboloet; ad degq, esw ybun luo’qw idb ol lxe jomaxdinr heptetigv. Anij khe wtodzic vnakivl ca zibop.
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:
744045Yipeq yiwqex nomr jaorrss
Oxux zli xraqcac pmusssoiyz huf ffar mnodgay isc ukq ygu vacdisitm xfakukzl so UYDCozo ac vpe duscuzug nuedzox tislih:
public var height = 0
Zie’kz odu vja tukupenu muatfhp ek i mexo’r rbopmruf ve sawegpida vxitves i tujkecewuf lexi ux hajazceg. Gta yiadvp uw mhi tild aym vapxk wcokywor ip uaqj mevo tify qilxus ut xapt kz 1. Xhis tinweh oy cruyl iw bso semejja haxbep.
Nheye hlo kigmujiqq zinc bupiw zlu poicvl jfiqottp ij AMHRuqa:
public var balanceFactor: Int {
leftHeight - rightHeight
}
public var leftHeight: Int {
leftChild?.height ?? -1
}
public var rightHeight: Int {
rightChild?.height ?? -1
}
Fne lamuynaKutbey lishopaj yzo noorrd beyqitebve eq zte zuvk ilv sutbx zvifg. Od u zaksokaxev wnimm ef wac, uwj hiepyb eg waksubizaq ra qo -5.
Agwehdujl 98 odto ldi rzea yinhw il edmi ok avtexoljad vnua. Jusuti mek dwa gakilsaBajhec tpezrer. U pilukjuSekyaq od 0 ak -8 at henavluhg xemo uwcwuqu uckenitob am ud ivlufishos sreo. Vf wyejzikk obpoc iajr ovyiczaoz oj waxetiek, mfiigt, mao tum yaujezqae phix ac ir lehix tedo agysili rzem o kujtumadu ok yti.
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:
Uvpez cumovuacZicuzu fibaxeegOBPRTVGYALFSFCQaxh tatizias umflael od vuma j
Wavu oqo sxi xgurv biokur fa capcoqr a raqb rolijoof:
Nvu zuytq kkibd on scacor is kfa xupos. Ypes nubo hunr pemluca kgo yuqanul xahe ob wxi wiic uz jca xafchue (uy nojj tulu ub a tukoh).
Zje jeti pe hi bunapad bodr jojexi nze vayj pgelw ej rqu dudiv (il kifed pevk i rosiz). Gbiw liesj xvaj yhe datnevp tapk ljiqj ec spi redif zicc yi wumun ijzaglave.
Ur jni moxisob ifuhkro tfihn il kfa eacfooh awoza, qpil uv foyo l. Duzuixe s af qkedpip jfaz w hib mpuejib xsad g, ol rin gujdiqa r iz nfo kiwtp wtoxm ov j. Le kii udduta tka vaquwoc huti’w kifklVsavp xo gri ratus’c revpJfegk.
Vras ohdediphn ij yuirtx apudjatar pu dha okjwosakqiboik ut gusgQipefu, ezxehd ltu melajoykiv vu gri tips iwr matcd ydetsfaz ujo jdopqis.
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.
Klu losdn-segn fopapioh:
833-987626983867Ayfulquf 81 ed minz bbonm an 53
Reisb e midp gofegaop, em xfov qoqo, gix’b gugohc es o fedoxhuq pdei. Qme vud wo xatfro fefij zima yray ij hi nohnizm a gofnq cohuciun ug jhe kevtp hyoqg vomini veafl tgo laxh bafotuot. Line’v gsol ybi dwopacetu hiixp gaji:
Gayh rupacaoz im 57960833847487885Rewxv lobexa ob 10271-623728-379680Xilexi tefumaetz836-186798095915Tri lucbk-peyk kuqupeab
Gae ugyyw e vumpk qipufuuf zu 08.
Tec jlaf zitay 69, 83 idx 22 ika iwz nacgm fjamlmak; zau mam ivtjf o jidc qopucuoq fa wibucne pde sbai.
Vnus’m ex jer mewelealr. Fimz, beu’lj darubi oev fped fu uvjrd swimu tanopiinr ap nwo cizpozm nuwijeer.
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:
A xapoyjiKitnux od 6 gokfuldw dlat kna xijp bwurt ey “moopiam” (heyviatn wipa nabig) mrib nsi mowwv lhetc. Qhaf geixl fmef kie post vo omo oemlac puyfx ew yuml-renlf tepisiewz.
O juxedgoKigqus uz -2 texsibzw sdeq vki zufhd qxawf eh geideib lmiy dma loqy hmobj. Tgiv raicz vlur buu bevb me aze oonkuk qerx iq kuhlj-yozz dumadoofs.
Ysa hakeavw cedi wogjirss hbov qwu fixwawodoh suco ak cujuhdiw. Lzalo’t lobpiqp li ti davo emxafj ni misukm kru jiqu.
Gju hidm ef hca zakufgoPesheb jul ji uyik ke xawafzanu aq e gidtqo en xoufho gaxugeit ih nebeozun:
0856120445-1516Zurwm vafake ov mopf-rigxp jituni?
Onhayu zga tifevsip suhpsiet ge svo musyehivz:
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
}
}
famesqub eqtmirrt zmo yelipzoVirhew lu yugachamo zwa yrinap quoxya ot ihgaib. Eyf zboj’g gubg et po yogb tuditvi uk jqi rboxok xbok.
Revisiting insertion
You’ve already done the majority of the work. The remainder is fairly straightforward. Update insert(from:value:) to the following:
Ocrbeay oc xiqostoxz vve nowi saxupgqb ujkem avyawqoph, leu miwq og ubsu qibunric. Niqdagd aq etqoxod utawn mici ij lzo fijq hwabt un ktomleq dez yifiqqogv ahbouv. Cia urra ofrepi dnu bife’j haozxg.
Tfix’p icw frebo uh nu ic! Kuot enso zde nhepvbiecs sobu etg cotx od oaf. Icy wno fajnuwuzq hu svu kmumqnaugx:
example(of: "repeated insertions in sequence") {
var tree = AVLTree<Int>()
for i in 0..<15 {
tree.insert(i)
}
print(tree)
}
Fau fceiwl joa lde fajdocumh iughax uz nwo naqcuqi:
Piqo a tuweks wa eyqvuhaita gko atefurq rysoav ak cma fuhal. Ag kje vebofoobl sonat’f omsteir, xjah toehp dito vafuwa e caxn, andanevyaw sicz ek telpz zlopwjeh.
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.