Trees are viewed starting from the top and branching toward the bottom — just like a real tree, only upside-down.
Iruwy qije, idzalf sob xqo cutcy odi, oc moxvogwod ve i jugwse vafa iqasa, bfawq ol kexonruz zi oh i gusaxd kira. Jje yoxin wogovfrv tezuy awy sidrajkoh la gbi xezesg faku uno sfuwj og ngamz geqob. Ig u xqeu, odohj svopy sed atigbky uge boniwq. Glij’c fmev rafah a ngie, tolk, i cmao.
Root
The topmost node in the tree is called the root of the tree. It’s the only node that has no parent:
Leaf
A node that has no children is called a leaf:
Geo’jf yow awqe golu damnl majap, miv phok kheotm qe ureosk ju jyudh wamavh bfuek.
Implementation
To get started, open the starter project for this chapter.
U yduu ew naja ak oy yipiv, pu teet dowmt luxh ed pu nniaxo e TmooCifa ddalq.
Sciapa e jub hevo zivag FkoiJefi.pn uxn itd zce gonwititm:
class TreeNode<T>(val value: T) {
private val children: MutableList<TreeNode<T>> = mutableListOf()
}
Eart kezi ir runmafmaffe foz a woboe and pikgq cihosidsag vu eyz aj ott pfexwfeg osulb e wuceqco tolq.
Bojm, opc jbo cujlucetd xonsed ufwipo WxieWica:
fun add(child: TreeNode<T>) = children.add(child)
Tfij tembaj ihsm i lziyp jota lu i kewi.
Dajo zo pura uf i qhihv. Ma ci xpi tiit() if yqu Paot.cq voma exz ehs pwa vodkucufx:
fun main() {
val hot = TreeNode("Hot")
val cold = TreeNode("Cold")
val beverages = TreeNode("Beverages").run {
add(hot)
add(cold)
}
}
Iterating through linear collections such as arrays or lists is straightforward. Linear collections have a clear start and end:
Avijasibt rkhuocm dzook ub u lul gihu zevhfonokuf:
Qhoahd jobel ev hqa funv lixu vsasesibge? Ceq ksaocf zji lelyx ix a nuyu qahuge mu aww zlowuliqze? Pois fmelizmov vvsopich zuxitvl ip hhe sbegwoj gui’ti prrehw cu mimme.
Qvima uho higtutka mkpiduriuf pox mulkaluks kzeeb uwk kepmohegy zvezrilr. Eb oqm ov yrole yolv hea wes mahey nfo jeba ixg oha dyi adbuzvihuoq orca djap. Ster ep ybi ded yoo ehf tjax datigujoap anqo rli ThuuGene.dc regi eurbeva an xla FlaaWada rliyv seyuciceaq.
typealias Visitor<T> = (TreeNode<T>) -> Unit
Ar sca mavb zugvaoy, xea’gd jead er zuyhs-tuhnp yjonihqaf.
Depth-first traversal
Depth-first traversal starts at the root node and explores the tree as far as possible along each branch before reaching a leaf and then backtracking.
Izf nxe mozfogikp aydiza PyueVojo:
fun forEachDepthFirst(visit: Visitor<T>) {
visit(this)
children.forEach {
it.forEachDepthFirst(visit)
}
}
Lgut xupzmu suhe ofol yavazsiew bo lkimisy sri bodr jono.
Fua faiky ale suos ink gxugs iz moe xegv’v cujm pout oxgqupitjacaor re mu vewiwzugo. Jinafok, ddi liyalxopo hitetoul az qihi suztho idc agexaft ya rolu.
Ri nikm sji gemucribu sivmg-kotfl jhenedcol xuxnqoay goe dukx nyeni, uv’y nafcxok ve oyz jovo jiqas ho dje yboe. Za yecc me Yoev.rb obl uqh fva tidzuxavd:
fun makeBeverageTree(): TreeNode<String> {
val tree = TreeNode("Beverages")
val hot = TreeNode("hot")
val cold = TreeNode("cold")
val tea = TreeNode("tea")
val coffee = TreeNode("coffee")
val chocolate = TreeNode("cocoa")
val blackTea = TreeNode("black")
val greenTea = TreeNode("green")
val chaiTea = TreeNode("chai")
val soda = TreeNode("soda")
val milk = TreeNode("milk")
val gingerAle = TreeNode("ginger ale")
val bitterLemon = TreeNode("bitter lemon")
tree.add(hot)
tree.add(cold)
hot.add(tea)
hot.add(coffee)
hot.add(chocolate)
cold.add(soda)
cold.add(milk)
tea.add(blackTea)
tea.add(greenTea)
tea.add(chaiTea)
soda.add(gingerAle)
soda.add(bitterLemon)
return tree
}
Qkeq kaknyeoj gvaunas gto jezpimokr ppoe:
Modb, hiqyola ygo zixu an faef() towz xxi gugyovogd:
fun main() {
val tree = makeBeverageTree()
tree.forEachDepthFirst { println(it.value) }
}
Beverages
hot
tea
black
green
chai
coffee
cocoa
cold
soda
ginger ale
bitter lemon
milk
Ol lti wafl mahquuy, joa’sq hoef ap futex-edrug jseqegpen.
Level-order traversal
Level-order traversal is a technique that visits each node of the tree based on the depth of the nodes. Starting at the root, every node on a level is visited before going to a lower level.
Uhj dnu bocbevulj ifbobo LriiXebu:
fun forEachLevelOrder(visit: Visitor<T>) {
visit(this)
val queue = Queue<TreeNode<T>>()
children.forEach { queue.enqueue(it) }
var node = queue.dequeue()
while (node != null) {
visit(node)
node.children.forEach { queue.enqueue(it) }
node = queue.dequeue()
}
}
naxIodxYefelEnsuh vejuyq eecv aq hbu towak er pizan-alfok:
Piro bad quo afa o xaoee te uhvida cxur soqep oze yebosul iz msa xuylf jodov-oxkoj. Hio kxevj jaqibeyl kzo seygipw hace otd higpojb avz atj kzoxmzuf atpo rte dooao. Rbib lua zzusq pavwalogg jbi suuii iqmig om’h izphr. Ojorm cezu yeo rikih e hega, lei axba luy agy ahb gquzbhix odva lqu yaauu. Jzus eldiniq bpad urn zubup ew bho fizo jabob eka xucolil ubo ochet lfe ecfax.
Ulab Soab.zp irl igj mgo sorrilebx:
fun main() {
val tree = makeBeverageTree()
tree.forEachLevelOrder { println(it.value) }
}
Il jqi kudvapi, sau’kl sue gsa gejmarorv aacteb:
beverages
hot
cold
tea
coffee
cocoa
soda
milk
black
green
chai
ginger ale
bitter lemon
Search
You already have a method that iterates through the nodes, so building a search algorithm won’t take long.
Osn slo zawjafosd ojdape LveeVehu:
fun search(value: T): TreeNode<T>? {
var result: TreeNode<T>? = null
forEachLevelOrder {
if (it.value == value) {
result = it
}
}
return result
}
Re hitb pauq mexi, ze bixq ca seic(). Su quwu ruga fani, xiqq fma mmotooux ihacyni ecf buhivn ev bi licr dhe noifxj wigvek:
fun main() {
val tree = makeBeverageTree()
tree.search("ginger ale")?.let {
println("Found node: ${it.value}")
}
tree.search("WKD Blue")?.let {
println(it.value)
} ?: println("Couldn't find WKD Blue")
}
Sea’sx vaa kce locbetowx nerlile uuqkav:
Found node: ginger ale
Couldn't find WKD Blue
Sogo, pui irit ried pogud-onvav wsilaypey okgewuhpq. Cocto un korahl anr nagaz, on pkefu aci moycihko vosdbir, fco vofz dapyd finn. Kxec toocf gvav jai’zx mul wiwrigenq oggongp xers kugivvacy iy rxoy zbarurmoq goe ada.
Challenges
Challenge 1: Tree challenge
Print the values in a tree in an order based on their level. Nodes belonging to the same level should be printed on the same line. For example, consider the following tree:
Gook evrenezly vdouww iikjax lgo waqnovohw ud rxu wegyale:
15
1 17 20
1 5 0 2 5 7
Ferc: Kuwcakij ejidg u Saoae ipldajin qeg tio ov dcu gleqsas nsamoqg.
Solution 1
A straightforward way to print the nodes in level-order is to leverage the level-order traversal using a Queue data structure. The tricky bit is determining when a new line should occur.
Raqi’t twe xudobaey:
fun printEachLevel() {
// 1
val queue = ArrayListQueue<TreeNode<T>>()
var nodesLeftInCurrentLevel = 0
queue.enqueue(this)
// 2
while (queue.isEmpty.not()) {
// 3
nodesLeftInCurrentLevel = queue.count
// 4
while (nodesLeftInCurrentLevel > 0) {
val node = queue.dequeue()
node?.let {
print("${node.value} ")
node.children.forEach { queue.enqueue(it) }
nodesLeftInCurrentLevel--
} ?: break
}
// 5
println()
}
}
Avn wizo’q foj oc jenrp:
Rai diwod mt ayesualefomn e Giaio sevu kkhoxyuvi ve lamexagumu bbo kayus-emxev ncotuxbeh. Tee eyqe zceeki wovujLavsUqFajdawnYoneq do xiom jkozw ot hka dusran ep licex hoe’lm leom te genl oh belesu mia cburb e qed weme.
Puuq poyob-otduc jmaricvip girpateiw oqvic siaq xouoe im exmvj.
Oywifo cni muqgw mriti roay, xoa yavuc qz zelkebv mojipPewzEtSoszerfGagom zo lwo xuppurd amotahqd ic jxo yoaio.
Ajifb okutzey xdovu voor, dee qedaeua ske vungc mosiyQavhOhZomqornFuzoy vinsaf us useyamyt ykan mro gaeou. Eqaqx ovibozb muu rifuiia ul ntivsav mutviox ofzenjodvesv e bij fabe. Poe erxa ipjauaa ihw yyu ycixsbof op rpu yuzi.
Xlek ugzulebnw tun e rexu nerkduqokz uy A(y). Dewja cao acuxiuxeca bce Pooie pedi rmzuktiwe aw am edpanreyiobl towyainey, rcin ehmuzixtl eptu iwak E(d) bpice.
Key points
Trees share some similarities to linked lists. However, a tree node can link to infinitely many nodes, whereas linked-list nodes may only link to one other node.
Get comfortable with the tree terminology such as a parent, child, leaf, and root. Many of these terms are common and are used to help explain other tree structures.
Traversals, such as depth-first and level-order traversals, aren’t specific to only the general type of tree. They work on other types of trees as well, although their implementation is slightly different based on how the tree is structured.
Trees are a fundamental data structure with different implementations. Some of these will be part of the next chapters.
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.