Last active
April 1, 2016 23:44
-
-
Save aessam/b61a0b5ab1a413998fcc to your computer and use it in GitHub Desktop.
Simple Tree structure functions (add to tree, get max, get min, get tree width) for Swift with a playground result viewer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
import XCPlayground | |
// For some reason (May be because Swift is still beta) Xcode goes crazy when I change addTree to generics. | |
// Update Thanks to my friend Shady Said, I forgot to add compareable. | |
class Node<V : Comparable>{ | |
var leftNode:Node?; | |
var rightNode:Node?; | |
var parent:Node?; | |
var value:V?; | |
init(parent: Node<V>){ | |
self.parent = parent | |
} | |
init(){ | |
} | |
} | |
func <<V>(lhs: Node<V>, rhs: Node<V>) -> Bool{ | |
return lhs.value<rhs.value | |
} | |
func ><V>(lhs: Node<V>, rhs: Node<V>) -> Bool{ | |
return lhs.value>rhs.value | |
} | |
// If the incoming value > then add to left, if the value is < add to right | |
// if the left/right has value will go recursively until empty node is found | |
func addToTree<V : Comparable>(tree: Node<V>, value:V){ | |
if (tree.value != nil) { | |
var targetNode: Node<V>? | |
if tree.value > value{ | |
if (tree.leftNode == nil){ | |
tree.leftNode = Node<V>(parent: tree) | |
} | |
targetNode = tree.leftNode! | |
} | |
if tree.value < value{ | |
if (tree.rightNode == nil){ | |
tree.rightNode = Node<V>(parent: tree) | |
} | |
targetNode = tree.rightNode! | |
} | |
if let validNode = targetNode{ | |
addToTree(validNode, value: value) | |
} | |
}else{ | |
tree.value = value | |
} | |
} | |
// Get Max value in the tree by going to the far right side in the tree | |
func getMaxValueInTree<V>(tree: Node<V>)->V{ | |
if let rn = tree.rightNode{ | |
return getMaxValueInTree(rn) | |
} | |
return tree.value! | |
} | |
// Get Min value in the tree by going to the far left side in the tree | |
func getMinValueInTree<V>(tree: Node<V>)->V{ | |
if let ln = tree.leftNode{ | |
return getMinValueInTree(ln) | |
} | |
return tree.value! | |
} | |
// return how many steps does it take to go form root to the far left (Minimum value) | |
func rootToMin<V>(tree: Node<V>)->Int{ | |
if let ln = tree.leftNode{ | |
return rootToMin(ln)+1 | |
} | |
return 0 | |
} | |
// return how many steps does it take to go form root to the far right (Maximum value) | |
func rootToMax<V>(tree: Node<V>)->Int{ | |
if let rn = tree.rightNode{ | |
return rootToMin(rn)+1 | |
} | |
return 0 | |
} | |
// return the number of steps it takes to get from far east to far west nodes in the tree | |
func treeWidth<V>(tree: Node<V>)->Int{ | |
return 1 + rootToMax(tree) + rootToMin(tree) | |
} | |
func getNodePath<V>(node: Node<V>)->String{ | |
if let prnt = node.parent{ | |
if prnt.leftNode === node{ | |
return getNodePath(prnt) + "l" | |
}else{ | |
return getNodePath(prnt) + "r" | |
} | |
} | |
return "" | |
} | |
func prepareForVisialViewer<V>(tree: Node<V>)-> Array<Array<String>>{ | |
var res = Array<Array<String>>() | |
var next = Array<Node<V>>() | |
var current = Array<Node<V>>() | |
if let x = tree.rightNode{ | |
current.append(x) | |
} | |
if let x = tree.leftNode{ | |
current.append(x) | |
} | |
res.append(Array(["\(tree.value!)"])) | |
repeat{ | |
var toAdd = Array<String>() | |
for node in current{ | |
if let rn = node.rightNode{ | |
next.append(rn) | |
} | |
if let ln = node.leftNode{ | |
next.append(ln) | |
} | |
if let vl = node.value{ | |
toAdd.append("\(getNodePath(node)) \(vl)") | |
} | |
} | |
res.append(toAdd) | |
current = next | |
next = Array<Node<V>>() | |
}while(current.count+next.count>0) | |
return res | |
} | |
func calcWidth(path: String)->CGFloat{ | |
var tbl = ["r":1.0, "l":0.0] | |
var deepth = 0.0 | |
// var part = 1/CGFloat(1<<(path.characters.count+1)) | |
var c = 0 | |
for char in path.characters{ | |
if let v = tbl[String(char)]{ | |
deepth += v*1/Double(1<<(c+1)) | |
} | |
c+=1 | |
} | |
deepth += 1/Double(1<<(path.characters.count+1)) | |
return CGFloat(deepth) | |
} | |
// Testing | |
var root:Node<Int> = Node<Int>() | |
let rawTree = [16,8,24,4,12,20,28,2,6,10,14,18,22,26,30,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31] | |
let tree = Node<Int>() | |
for v in rawTree{ | |
addToTree(tree, value: v) | |
} | |
var treeForUI = prepareForVisialViewer(tree) | |
class CustomView: NSView { | |
override init(frame: NSRect) { | |
super.init(frame: frame) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func drawRect(dirtyRect: NSRect) { | |
for deepth in 0..<treeForUI.count{ | |
var line = treeForUI[deepth] | |
for idxOfNode in 0..<line.count{ | |
let txt = line[idxOfNode] | |
var arrOfParts = txt.componentsSeparatedByString(" ") | |
if arrOfParts.count>1{ | |
let partValue = 1<<deepth | |
let boxWidth = self.frame.size.width/CGFloat(partValue) | |
for boxs in 0...partValue{ | |
NSFrameRect(CGRectMake(boxWidth*CGFloat(boxs), self.frame.size.height - CGFloat((deepth+1)*16), boxWidth, 16)) | |
} | |
"\(arrOfParts[1])".drawAtPoint(CGPointMake(calcWidth(arrOfParts[0] as String)*self.frame.size.width, self.frame.size.height - CGFloat((deepth+1)*16)), withAttributes: nil) | |
}else{ | |
NSFrameRect(CGRectMake(1, self.frame.size.height - CGFloat((deepth+1)*16), self.frame.size.width-2, 16)) | |
"\(arrOfParts[0])".drawAtPoint(CGPointMake(calcWidth("")*self.frame.size.width, self.frame.size.height - CGFloat((deepth+1)*16)), withAttributes: nil) | |
} | |
} | |
} | |
"Maximum Value in the tree is \(getMaxValueInTree(tree))".drawAtPoint(CGPointMake(0, 0),withAttributes: nil) | |
"Maximum Value in the tree is \(getMinValueInTree(tree))".drawAtPoint(CGPointMake(0, 16),withAttributes: nil) | |
"Distance from far left to far right is \(treeWidth(tree))".drawAtPoint(CGPointMake(0, 32),withAttributes: nil) | |
} | |
} | |
var view = CustomView(frame: | |
NSRect(x: 0, y: 0, width: 600, height: 150)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment