用OC和Swift一塊兒說說二叉樹

前言:node

   一:在計算機科學中,二叉樹是每一個節點最多有兩個子樹的樹結構。一般子樹被稱做「左子樹」(left subtree)和「右子樹」(right subtree)。二叉樹常被用於實現二叉查找樹和二叉堆。
 
   二:二叉樹的每一個結點至多隻有二棵子樹(不存在度大於2的結點),二叉樹的子樹有左右之分,次序不能顛倒。二叉樹的第i層至多有2^{i-1}個結點;深度爲k的二叉樹至多有2^k-1個結點;對任何一棵二叉樹T,若是其終端結點數爲n_0,度爲2的結點數爲n_2,則n_0=n_2+1。
 
   三:一棵深度爲k,且有2^k-1個節點稱之爲滿二叉樹;深度爲k,有n個節點的二叉樹,當且僅當其每個節點都與深度爲k的滿二叉樹中,序號爲1至n的節點對應時,稱之爲徹底二叉樹。
 
   四:二叉樹遍歷: 先序遍歷、中序遍歷、後序遍歷、層次遍歷 、下面答案很精闢;
 

 

二✘樹的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)!)
                }
            }
        }
    }
相關文章
相關標籤/搜索