二叉樹(shù)的4種遍歷

樹(shù)

定義:二叉樹(shù)是n(n>0)個(gè)節(jié)點(diǎn)的有限集合,該集合或者為空集(空二叉樹(shù)),或者由一個(gè)根節(jié)點(diǎn)和兩棵互不相交分別稱(chēng)為根節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的二叉樹(shù)組成。

*** 注意:***

  • n>0 時(shí)節(jié)點(diǎn)是唯一的,不可能存在多個(gè)節(jié)點(diǎn),別和現(xiàn)實(shí)中的樹(shù)木混在一起。
  • m>0 時(shí),子樹(shù)的個(gè)數(shù)沒(méi)有限制,但是一定是不交互的。

樹(shù)的四種遍歷

遍歷:二叉樹(shù)的遍歷是指從根節(jié)點(diǎn)出發(fā),按照某種次序依次訪(fǎng)問(wèn)二叉樹(shù)中所有節(jié)點(diǎn),使得每個(gè)節(jié)點(diǎn)被訪(fǎng)問(wèn)依次且被訪(fǎng)問(wèn)依次。

  • 前序遍歷
  • 中序遍歷
  • 后序遍歷
  • 層序遍歷

前序遍歷

定義:規(guī)則是若二叉樹(shù)為空,則空操作返回。 否則先訪(fǎng)問(wèn)跟節(jié)點(diǎn),然后前序遍歷左子樹(shù),再遍歷右子樹(shù)。
優(yōu)先級(jí):根->左->右

中序遍歷

定義:規(guī)則是樹(shù)若為空,操作返回,否則從根節(jié)點(diǎn)開(kāi)始,中序遍歷(注意并不是訪(fǎng)問(wèn)根節(jié)點(diǎn))根節(jié)點(diǎn)的左子樹(shù),然后訪(fǎng)問(wèn)根節(jié)點(diǎn),最后中序遍歷右子樹(shù)。
優(yōu)先級(jí):左->根->右

后序遍歷

定義:規(guī)則是若樹(shù)空,操作返回,否則是從左到右先葉子后節(jié)點(diǎn)的方式遍歷訪(fǎng)問(wèn)左右子樹(shù),最后是訪(fǎng)問(wèn)跟節(jié)點(diǎn)。
優(yōu)先級(jí):左->右->根

層序遍歷

定義:規(guī)則是若樹(shù)空,操作返回,否則是從樹(shù)的第一層,也就是從根節(jié)點(diǎn)開(kāi)始訪(fǎng)問(wèn),從上而下逐層遍歷,在同一層中,從左到右的順序?qū)?jié)點(diǎn)逐個(gè)訪(fǎng)問(wèn)。優(yōu)先級(jí):頂部到底部的所有節(jié)點(diǎn)

代碼示例4中遍歷



這四種遍歷示例:   

             A
          /    \
        B        C
      /  \      /  \ 
     D    E     F   G  
 層序遍歷結(jié)果是:  ABCDEFG
 前序遍歷結(jié)果是:  ABDECFG
 中序遍歷結(jié)果是:  DBEAFCG
 后序遍歷結(jié)果是:  DEBFGCA



//節(jié)點(diǎn)對(duì)象
@interface Node : NSObject

@property (nonatomic) NSInteger data;//存儲(chǔ)的數(shù)據(jù)

@property (nonatomic) Node * leftNode; //左節(jié)點(diǎn)

@property (nonatomic) Node * rightNode; //右節(jié)點(diǎn)

@end

@implementation Node

@end

每一種遍歷其實(shí)都是遞歸,只是遞歸的時(shí)候,處理數(shù)據(jù)的代碼時(shí)機(jī)不一樣。


//前序 遍歷
/*
 規(guī)則是若二叉樹(shù)為空,則空操作返回。 否則先訪(fǎng)問(wèn)跟節(jié)點(diǎn),然后前序遍歷左子樹(shù),再遍歷右子樹(shù)。跟->左->右
 
 */
-(void)printNode:(Node *)node{
    if (node == nil) {
        return;
    }
    NSLog(@"%ld",node.data);
    [self printNode:node.leftNode];
    [self printNode:node.rightNode];
}
// 中序遍歷   從 左子樹(shù)【左->根->右】
-(void)printCenterNode:(Node *)node{
    if (node == nil) {
        return;
    }
    [self printCenterNode:node.leftNode];
     NSLog(@"%ld",node.data);
    [self printCenterNode:node.rightNode];
}

// 后序遍歷   從 左子樹(shù)【左->右->根】
-(void)print2Node:(Node *)node{
    if (node == nil) {
        return;
    }
    [self print2Node:node.leftNode];
    [self print2Node:node.rightNode];
    NSLog(@"%ld",node.data);//節(jié)點(diǎn)數(shù)據(jù)可以進(jìn)行其他操作
}

//層序遍歷 迭代版本
    func trav_L_R(tree:Tree) -> Void {
        var i = 0
        self.treesAray.append(tree);//添加根節(jié)點(diǎn)
        while true {
//直到所有子樹(shù)都遍歷完成則退出
            if i >= self.treesAray.count{break};
            let t = self.treesAray[i];
            if t.left != nil{//如果有左子樹(shù)就入棧
                self.treesAray.append(t.left ?? Tree());
            }
            if t.right != nil{//如果有右子樹(shù)就入棧
                self.treesAray.append(t.right ?? Tree());
            }
            i += 1;// 遍歷下個(gè)子樹(shù)
        }
    }
 

Swift版本

//中序遍歷
    func travIn_C(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        travIn_C(tree: tree?.left);
        self.valsArray.append(tree?.val ?? 0);
        travIn_C(tree: tree?.right);
    }




    //先序遍歷
    func travIn_L(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        self.valsArray.append(tree?.val ?? 0);
        travIn_L(tree: tree?.left);
        travIn_L(tree: tree?.right);
    }
    //后續(xù)遍歷
    func travIn_R(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        travIn_R(tree: tree?.left);
        travIn_R(tree: tree?.right);
        self.valsArray.append(tree?.val ?? 0);
    }

二叉樹(shù)的迭代前中后序遍歷

原二叉樹(shù)

前序遍歷迭代:


前序遍歷迭代

中序遍歷迭代:


中序遍歷迭代

后序遍歷迭代

//先序遍歷
    func travIn_I_L(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        var t = tree;
        while true {
            while t != nil {
                self.valsArray.append(t?.val ?? -1);
                if t?.right != nil{
                    self.treesAray.append(t?.right ?? Tree());
                }
                t = t?.left;
            }
            if self.treesAray.count == 0 {
                break;
            }
            t = self.treesAray.removeLast();
        }
    }

   //中序遍歷
    func travIn_I_C(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        var t = tree;
        while true {
            while t != nil {
                self.treesAray.append(t ?? Tree());
                t = t?.left;
            }
            if self.treesAray.count == 0 {
                break;
            }
            t = self.treesAray.removeLast();
            self.valsArray.append(t?.val ?? -1);
            //有右結(jié)點(diǎn) 則向右移動(dòng)一個(gè)節(jié)點(diǎn)
            if t?.right != nil{
                t = t?.right;
            }else{//否則刪除已經(jīng)添加好的結(jié)點(diǎn)
                t = nil;
            }
        }
    }


//后續(xù)遍歷
    func travIn_I_R(tree:Tree?) -> Void {
        if tree == nil{
            return;
        }
        var t = tree;
        while true {
            while t != nil {
                self.treesAray.append(t ?? Tree());
                t = t?.left;
            }
            if self.treesAray.count == 0 {
                break;
            }
            t = self.treesAray.last;
            //有右結(jié)點(diǎn) 則向右移動(dòng)一個(gè)節(jié)點(diǎn)
            if t?.right != nil{
                t = t?.right;
            }else{//否則刪除已經(jīng)添加好的結(jié)點(diǎn)
                self.valsArray.append(t?.val ?? -1);
                self.treesAray.removeLast();
                
                if self.treesAray.count > 0 {
                    let t1 = self.treesAray.last;
                    t1?.left = nil;
                    if t1?.right == t{//判斷是否是向上攀爬 YES則刪除右結(jié)點(diǎn),否則不刪除
                        t1?.right = nil;
                    }
                }
                t = nil;
            }
        }
    }


func isSymmetric(_ root: TreeNode?) -> Bool {
     // 層序遍歷 校驗(yàn)是否是 對(duì)稱(chēng)樹(shù)
        if  root == nil {
            return true;
        }
        var list :Array = [TreeNode]()
        if let val = root {
            list.append(val)
        }        
        while list.count > 0 {
            for index in 0...list.count/2 {
                let node1 = list[index]
                let node2 = list[list.count-index-1];
                if isSameTree2(node1, node2) == false {
                    return false;
                }
            }
            var subList:Array = [TreeNode]()
            var end:Int = 0 //統(tǒng)計(jì)空節(jié)點(diǎn)
            
            for index in list {
                if let left = index.left {
                    subList.append(left)
                }else {
                    end += 1
                    let left = TreeNode(0);
                    subList.append(left);
                }
                if let right = index.right {
                    subList.append(right)
                }else {
                    end += 1
                    let left = TreeNode(0);
                    subList.append(left);
                }
            }
            if end == subList.count {
                subList.removeAll()
            }
            list.removeAll()
            list += subList
            subList.removeAll()
        }
        return true;
    }
//判斷是否是相同的節(jié)點(diǎn)
    func isSameTree(_ left:TreeNode?,_ right:TreeNode?) -> Bool {
        if left == nil && right == nil {
            return true;
        }else  if left == nil && right != nil {
            return false
        }else if left != nil && right == nil {
            return false
        }else if let val1 = left?.val    {
                let val2 = right?.val
            if val1 == val2 {
                return true;
            }
        }
        return false;
    }
//構(gòu)造節(jié)點(diǎn)
-(Node *)randNode{
    Node * node =[Node new];
    node.data = rand()%20 + 1;
    return node;
}

其實(shí)平時(shí)都拿來(lái)數(shù)據(jù)是數(shù)組形式,并不能夠直接當(dāng)做二叉樹(shù)直接來(lái)操作,需要把數(shù)組轉(zhuǎn)化成二叉樹(shù),那么怎么轉(zhuǎn)呢?

利用二叉樹(shù)的性質(zhì),深度為k的節(jié)點(diǎn)的左子樹(shù)為k*2+1,右子樹(shù)為k*2+2
那么滿(mǎn)二叉樹(shù)節(jié)點(diǎn)最多為2^(k)-1,最后一層葉子最多為2^(k-1)。得出最后一行的葉子的索引為2^(k-1)+1。所以假設(shè)數(shù)組有n個(gè)元素,則最后一行葉子的索引為n/2-1
得出 :

func createTree() -> Tree? {
        self.vals = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
        
        self.top = createTreeWithArray(list: self.vals);
        return top;
    }
    func createTreeWithArray(list:[Int]) -> Tree {
        let length = list.count/2-1;
        
        var tArray:[Tree] = [Tree]();
        
        //生成數(shù)組 ??
        for i in 0..<list.count{
            let tsub = Tree.loadTree(val: list[i]);
            tArray.append(tsub);
        }
        //構(gòu)造二叉樹(shù)??
        for i in 0..<length{
            let t :Tree = tArray[i];
            //構(gòu)造左孩子
            t.left = tArray[i*2+1];
            //構(gòu)造右孩子
            t.right = tArray[i*2+2];
        }
        //構(gòu)造最后一個(gè)做孩子
        tArray[length].left = tArray[length*2+1];
        if length%2 == 1{//若數(shù)組為奇數(shù)則存在右孩子
            tArray[length].right = tArray.last;
        }
        //返回 topTree
        return tArray[0];
    }

點(diǎn)我下載代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 樹(shù)的概述 樹(shù)是一種非常常用的數(shù)據(jù)結(jié)構(gòu),樹(shù)與前面介紹的線(xiàn)性表,棧,隊(duì)列等線(xiàn)性結(jié)構(gòu)不同,樹(shù)是一種非線(xiàn)性結(jié)構(gòu) 1.樹(shù)的定...
    Jack921閱讀 4,751評(píng)論 1 31
  • 基于樹(shù)實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu),具有兩個(gè)核心特征: 邏輯結(jié)構(gòu):數(shù)據(jù)元素之間具有層次關(guān)系; 數(shù)據(jù)運(yùn)算:操作方法具有Log級(jí)的平...
    yhthu閱讀 4,465評(píng)論 1 5
  • 一直以來(lái),我都很少使用也避免使用到樹(shù)和圖,總覺(jué)得它們神秘而又復(fù)雜,但是樹(shù)在一些運(yùn)算和查找中也不可避免的要使用到,那...
    24K男閱讀 6,856評(píng)論 5 14
  • 數(shù)據(jù)結(jié)構(gòu)和算法--二叉樹(shù)的實(shí)現(xiàn) 幾種二叉樹(shù) 1、二叉樹(shù) 和普通的樹(shù)相比,二叉樹(shù)有如下特點(diǎn): 每個(gè)結(jié)點(diǎn)最多只有兩棵子...
    sunhaiyu閱讀 6,695評(píng)論 0 14
  • 1.什么是二叉樹(shù)? 在計(jì)算機(jī)科學(xué)中,二叉樹(shù)是每個(gè)節(jié)點(diǎn)最多有兩個(gè)子樹(shù)的樹(shù)結(jié)構(gòu)。通常子樹(shù)被稱(chēng)作“左子樹(shù)”和“右子樹(shù)”,...
    zcaaron閱讀 1,351評(píng)論 2 15

友情鏈接更多精彩內(nèi)容