什麼是遍歷二叉樹,JavaScript實現二叉樹的遍歷(遞迴,非遞迴)

前端張小明發表於2020-03-05

遍歷二叉樹:

遍歷的定義指順著一條搜尋路徑巡防二叉樹的結點,使得每個結點均被訪問一次,而且僅被訪問一次(又稱周遊)
複製程式碼

遍歷方法:

依次遍歷二叉樹中的三個組成部分,便是遍歷了整個二叉樹
複製程式碼

L:遍歷左子樹
D: 訪問根結點
R: 遍歷右子樹 若規定先左後右,則遍歷二叉樹就有三種情況
DLR ———— 先(根)序遍歷
LDR ———— 中(根)序遍歷
LRD ———— 後(根)序遍歷

遍歷二叉樹的演算法描述:

先序遍歷二叉樹:若二叉樹為空,則空操作,否則(1)訪問根結點;(2)先序遍歷左子樹;(3)先序遍歷右子樹
中序遍歷二叉樹:若二叉樹為空,則空操作,否則(1)中序遍歷左子樹;(2)訪問根結點;(3)中序遍歷右子樹
後序遍歷二叉樹:若二叉樹為空,則空操作,否則(1)後序遍歷左子樹;(2)後序遍歷右子樹;(3)訪問根結點

由二叉樹的遞迴定義可知,遍歷左子樹和遍歷右子樹可如同遍歷二叉樹一樣“遞迴”進行。

下面我們用JavaScript實現一下二叉樹的遍歷

給定一個二叉樹物件

var root = {
id: 1,

left: {
    id: 2,
    left: {
        id: 4,
    },
    right:{
        id:5
    }
},
right: {
    id: 3,
    left: {
        id: 6
    },
    right: {
        id: 7
    }
}
複製程式碼

}

遞迴先序遍歷

var res = []

function DLR(root) {

if(root != null) {
    res.push(root.id)
    if(root.left) {
        DLR(root.left)
    }
    if(root.right) {
        DLR(root.right)
    }
}
return res
複製程式碼

}

console.log('遞迴先序遍歷', DLR(root))

遞迴中序遍歷

var res = []

function LDR(root) {

if(root != null) {
    if(root.left) {
        LDR(root.left)
    }
    res.push(root.id)
    if(root.right) {
        LDR(root.right)
    }
}
return res
複製程式碼

}

console.log('遞迴中序遍歷', DLR(root))

遞迴後序遍歷

var res = []

function LRD(root) {

if(root != null) {
    if(root.left) {
        LRD(root.left)
    }
    if(root.right) {
        LRD(root.right)
    }
    res.push(root.id)
}
return res
複製程式碼

}

console.log('遞迴後序遍歷', LRD(root))
看完上面的遞迴遍歷,下面對比一下非遞迴的二叉樹遍歷。

非遞迴先序遍歷

就是把遞迴的遍歷改成迴圈模式,將需要遍歷的樹放入陣列arr中,在利用陣列的pop()方法,返回這個大樹,取出樹的根,將樹的右子樹放入arr中,  
再將樹的左子樹放入arr中(這樣的話pop出來的就是先左後右),然後迴圈上面操作,pop arr陣列,取出根,然後右子樹push arr中, 左子樹  
push arr中。。。迴圈
複製程式碼

function DLR(root) {

var res = [] , arr =[]
if (root != null){
    arr.push(root)
}
while (arr.length > 0) {
    var temp = arr.pop()
    res.push(temp.id)
    if(temp.right){ // 先放右子樹再放左子樹  取出來的時候才是先左後右
        arr.push(temp.right)
    }
    if(temp.left){
        arr.push(temp.left)
    }
}
return res
複製程式碼

}

console.log('非遞迴先序遍歷', DLR(root))

非遞迴中序遍歷

先把左邊的,全部放進arr再輸出
複製程式碼

function LDR(root) {

var res = [] , arr =[]
while (true){
    while (root != null){
        arr.push(root)
        root = root.left
    }
    //終止條件:最後樹遍歷完了自然就結束
    if(arr.length===0) {
        break;
    }
    let temp = arr.pop()
    res.push(temp.id)
    root = temp.right
}
return res
複製程式碼

}

console.log('非遞迴中序遍歷', LDR(root))

非遞迴後序遍歷

其實就是先根右左(和先序方法一樣) 然後在反過來
複製程式碼

function LRD(root) {

var res = [] , arr =[]
if (root != null){
    arr.push(root)
}
while (arr.length > 0) {
    var temp = arr.pop()
    res.push(temp.id)
    if(temp.left){
        arr.push(temp.left)
    }
    if(temp.right){
        arr.push(temp.right)
    }
}
return res.reverse()
複製程式碼

}

console.log('非遞迴後序遍歷', LRD(root))

相關文章