前言:node
二✘樹的OC建立源碼:算法
/** 建立二叉樹 @param Values 傳入數組 @return return value description */ +(ZXTThreeObject * )CreatTreesWithValues:(NSArray * )Values{ __block ZXTThreeObject * rootNode = nil; /** 這裏順便提一下這個循環遍歷,可能不部分都用的是for循環或者for..in..來循環的 **/ /** 你們瞭解一下 NSEnumerator 遍歷和Block遍歷還有GCD中的dispatch_apply **/ /** 連接在這裏 **/ [Values enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { int value = [obj intValue]; rootNode = [self AddTreeNode:rootNode andValue:value]; }]; return rootNode; } /** 遞歸的思想 這裏返回的 node 這個參數實際上是一個局部變量,無論裏面嵌套調用多少次AddTreeNode這個方法,這裏每一次返回的一直都是它的最原始的根節點!!這點對建立過程的 理解很重要,但若是返回值你寫成全局變量就不同了,它返回的就是最後賦給它的值。 這裏簡單說一下,局部變量是存儲在棧中的,全局變量是存儲在靜態存儲區的!每存儲一個局部變量,編譯器就會開闢一塊棧區域來保存 方法第一次傳遞的node這個變量,編譯器就開闢了棧區域保存了它的值,後面要是有嵌套調用了這個方法 編譯器就又開闢新的棧區域保存它們的返回值,但不會影響第一次保存的值,你要調用屢次的話,第一個保存的值也就是最後一個返回的了 這就解釋了爲何每次最後的返回值都是 最原始的根節點了! **/ +(ZXTThreeObject * )AddTreeNode:(ZXTThreeObject *)node andValue:(int) value{ if (!node) { node = [[ZXTThreeObject alloc]init]; node.Value = value; }else if (value <= node.Value){ /**值小於節點的值,插入到左節點**/ node.leftTreeNode = [self AddTreeNode:node.leftTreeNode andValue:value]; }else{ /**值大於節點的值,插入到右節點**/ node.rightTreeNode = [self AddTreeNode:node.rightTreeNode andValue:value]; } return node; }
你能夠驗證一下它的正確性,你在建立左右節點的時候他們打印出來,下面的數組提供你們參考:swift
NSArray * array = @[@2,@3,@7,@5,@9,@4,@6,@1,@8]; /** 上面的數組建立的二叉樹應該是這樣的 * 表明沒有值 2 1 3 * 7 5 9 4 6 8 * **/ [ZXTThreeObject CreatTreesWithValues:array];
二✘樹的Swift建立源碼:api
class ZXTreeObject: NSObject { var leftNode :ZXTreeObject? var rightNode:ZXTreeObject? var nodevalue:Int? func CreatTreesWithValues(Values:[Int]) -> ZXTreeObject { var rootNode:ZXTreeObject? for value in Values { rootNode = self.AddTreeNode(node: &rootNode,value) } return rootNode! } /**注意在Swift3中:函數簽名中的下劃線的意思是 告訴編譯器,咱們在調用函數時第一個參數不須要外帶標籤 這樣,咱們能夠按照 Swift 2 中的方式去調用函數,還有這個下劃線和參數名之間要有空格!必需要有! **/ func AddTreeNode(node: inout ZXTreeObject?, _ value:Int) -> ZXTreeObject { if (node == nil) { node = ZXTreeObject() node?.nodevalue = value }else if (value < (node?.nodevalue)!) { //print("----- to left ") _ = AddTreeNode(node: &node!.leftNode, value) }else{ //print("----- to right ") _ = AddTreeNode(node: &node!.rightNode, value) } // print("節點:",node!.nodevalue ?? 0) return node! } }
調用的時候這樣:數組
// 定義一個數組 let sortArray:[Int] = [2,3,7,5,9,4,6,1,8] _ = ZXTreeObject().CreatTreesWithValues(Values: sortArray)
這個結果的話你們能夠把上面的打印註釋打開本身看看結果,是沒問題的,這裏在給你們看看這樣一個警告:閉包
就這個返回值沒有使用的警告,這警告有兩種辦法消除:app
/* 一:就像上面的加 _ = 在調用的函數前面 二:在函數聲明的前面加上 @discardableResult 如: @discardableResult func AddTreeNode(node: inout ZXTreeObject?, _ value:Int) -> ZXTreeObject { }*/
計算二✘樹的深度OC:函數
/** 樹的深度 三種狀況: 一:根節點要是不存在就返回0 二:左節點和右節點都不存在,到這裏的前提是根節點存在,返回1 三:都存在,再遞歸獲取深度,返回最大值! @param node 節點 @return return value description */ // 2017-03-03 14:06:15.248 算法OC版本[22755:262170] 數的深度==5 +(NSInteger)deepWithThree:(ZXTThreeObject *)node{ if (!node) { return 0; }else if (!node.leftTreeNode && !node.rightTreeNode){ return 1; }else{ NSInteger leftDeep = [self deepWithThree:node.leftTreeNode]; NSInteger rightDeep = [self deepWithThree:node.rightTreeNode]; return MAX(leftDeep, rightDeep) + 1; } }
計算二✘樹的深度Swift:spa
// Swift 求二叉樹的深度 func deepWithThree(rootNode: ZXTreeObject?) -> Int { if ((rootNode) == nil){ return 0 }else if((rootNode?.leftNode) == nil && (rootNode?.rightNode) == nil){ return 1 }else{ let deepLeft = self.deepWithThree(rootNode: rootNode?.leftNode) let rightLeft = self.deepWithThree(rootNode: rootNode?.rightNode) return max(deepLeft, rightLeft) + 1 } } // 調用 // 打印 ====== 5 let deep = node.deepWithThree(rootNode: node) print("======",deep)
計算二✘樹的寬度OC: orm
/* 二叉樹寬度的定義:各層節點數的最大值! */ +(NSInteger)WidthOfTree:(ZXTThreeObject * )RootNode{ // 根節點不存在,就返回 0 if (!RootNode) { return 0; } NSMutableArray * queeArray = [NSMutableArray array]; NSInteger currentWidth = 0; NSInteger maxWidth = 1; // 前面 0 的不存在就 確定有,至少是 1 [queeArray addObject:RootNode]; // 添加根節點 while (queeArray.count > 0) { // 這就是當前的節點的數目,第一層就只有根節點 寬度是1 // 下一層,按照下面邏輯添加了左右節點就變成了2 currentWidth=queeArray.count; // 遍歷該層,刪除原始數組中遍歷過的節點,添加它下一層的節點。再循環遍歷 for (NSInteger i=0; i<currentWidth; i++) { ZXTThreeObject * treenode = [queeArray firstObject]; [queeArray removeObjectAtIndex:0]; if (treenode.leftTreeNode) { [queeArray addObject:treenode.leftTreeNode]; } if (treenode.rightTreeNode) { [queeArray addObject:treenode.rightTreeNode]; } } // 一層一層的遍歷的時候去最大值,返回 maxWidth = MAX(maxWidth, queeArray.count); } return maxWidth; }
計算二✘樹的寬度Swift:
func widthWithThree(rootNode: ZXTreeObject?) -> Int { if ((rootNode) == nil){ return 0 }else{ var widthDataArray = Array<ZXTreeObject>() widthDataArray.append(rootNode!) var maxWidth = 1 var currentWidth = 0; while (widthDataArray.count > 0) { currentWidth = widthDataArray.count for _ in 0 ..< currentWidth{ let node = widthDataArray.first widthDataArray.remove(at: 0) if ((node?.leftNode) != nil) { widthDataArray.append((node?.leftNode)!) } if ((node?.rightNode) != nil){ widthDataArray.append((node?.rightNode)!) } } maxWidth = max(currentWidth, widthDataArray.count) } return maxWidth } }
二✘樹的先 , 中,後遍歷OC:
// 調用代碼 NSMutableArray * dataArray = [NSMutableArray array]; [ZXTThreeObject preorderTraversal:rootNode andHandle:^(ZXTThreeObject *threeNode) { NSString * value = [NSString stringWithFormat:@"%ld",threeNode.Value]; [dataArray addObject:value]; }]; NSLog(@"=======%@",dataArray); // 方法實現代碼 /** 這裏所謂的先序,中序,或者後序說的都是根節點的順序,這個能夠看着上面的那張度孃的圖片去好好體會一下。 handle就是一個回調,node就是根節點,這樣就很容易理解記住了。其餘的後序和中序就不寫代碼了,交換順序就好了。 **/ +(void)preorderTraversal:(ZXTThreeObject *)node andHandle:(void(^)(ZXTThreeObject * threeNode))handle{ if (node) { // 根 if (handle) { handle(node); } //左 [self preorderTraversal:node.leftTreeNode andHandle:handle]; //右 [self preorderTraversal:node.rightTreeNode andHandle:handle]; } }
二✘樹的先 , 中,後遍歷Swift:
// 定義一個隨機數組 let sortArray:[Int] = [2,3,7,5,9,4,6,1,8] var dataArray = Array<Int>() let node = ZXTreeObject().CreatTreesWithValues(Values: sortArray) _ = node.preorderTraversal(rootNode:node, handle: {(treeNode) in dataArray.append((treeNode?.nodevalue)!) }) print(dataArray) /** 先序遍歷 中序和後序就不寫了,而上面OC的道理是同樣的 **/ // 這是定義的閉包,注意它的位置和咱們OC定義Block相似 typealias Handle = (_ root:ZXTreeObject?) -> Void; func preorderTraversal(rootNode: ZXTreeObject?, handle:@escaping Handle) -> Void { if ((rootNode) != nil) { handle(rootNode); self.preorderTraversal(rootNode: rootNode?.leftNode, handle: handle) self.preorderTraversal(rootNode: rootNode?.rightNode, handle: handle) } }
二✘樹的層次遍歷OC:
/* 層次遍歷 層次遍歷,就是一層一層的遍歷,下面的方法用到了隊列的想法。 */ +(void)CengCiBLTreeNode:(ZXTThreeObject * ) RootNode handle:(void(^)(ZXTThreeObject * treenode))handle{ if (RootNode) { NSMutableArray * queeArray=[NSMutableArray array]; // 添加了根節點進去 [queeArray addObject:RootNode]; while (queeArray.count>0) { // 取出數組中的第一個元素 ZXTThreeObject * rootnode = [queeArray firstObject]; if (handle) { // 添加這個元素的值到數組中去 handle(rootnode); } // 添加完這個元素的值就把這個元素刪除了 [queeArray removeObjectAtIndex:0]; // 這個節點要有左節點的話,就添加左節點到數組中去,有右節點的話就添加右節點到數組中去。 // 建議一步一步研究這個添加順序,就能夠清晰的看到這個是一層一層的遍歷到的。 if (rootnode.leftTreeNode) { [queeArray addObject:rootnode.leftTreeNode]; } if (rootnode.rightTreeNode) { [queeArray addObject:rootnode.rightTreeNode]; } } } }
二✘樹的層次遍歷Swift:
/******* 調用/ var array = Array<Int>() _ = node.preorderTraversal(rootNode:node, handle: {(treeNode) in array.append((treeNode?.nodevalue)!) }) //array ====== [2, 1, 3, 7, 5, 4, 6, 9, 8] print("array ======",array) /******* 層次遍歷/ func CengCiBLTreeNode(rootNode: ZXTreeObject?, handle:@escaping Handle) -> Void { if ((rootNode) != nil) { var dataArray = Array<ZXTreeObject>() dataArray.append(rootNode!) while dataArray.count > 0 { handle(rootNode); dataArray.remove(at: 0) if ((rootNode?.leftNode) != nil) { dataArray.append((rootNode?.leftNode)!) } if ((rootNode?.rightNode) != nil) { dataArray.append((rootNode?.rightNode)!) } } } }