【數據結構與算法】遞歸轉棧

前言

  • 以前學數據結構學的很盲目,特別是後面學遞歸dp感覺腦子完全不夠用,好像自己完全不是這塊料一樣。後來羣裏吹牛以及找各種資料發現能用遞歸的都可以用棧實現,遞歸本質是讓系統幫你維護個棧,而你不遞歸,那麼就自己手動維護棧,這樣就能達到同樣效果。

簡單例題

  • leecode 144. 二叉樹的前序遍歷
輸入: [1,null,2,3]  
   1
    \
     2
    /
   3 

輸出: [1,2,3]

遞歸思路

var preorderTraversal = function(root) {
    let result = []
    var preOrderTraverseNode = (node) => {
        if(node) {
            // 先根節點
            result.push(node.val)
            // 然後遍歷左子樹
            preOrderTraverseNode(node.left)
            // 再遍歷右子樹
            preOrderTraverseNode(node.right)
        }
    }
    preOrderTraverseNode(root)
    return result
};
  • 這個遞歸模式是個套路寫法,和深度優先一樣:
let num=0//記錄深度,上面那個題目不需要記錄深度。
function depth(node){
	num++
	if(node.left){
		dosomething...
		depth(node.left)
	}
	if(node.right){
		dosomething...
		depth(node.right)
	}
	num--
	if(num===0){//出口,也可用來返回結果之類,上面那題結果在外面收集,不記錄深度,有判斷條件的遞歸不會無限遞歸。
		return 
	}
}
  • 還有個廣度優先的寫法,也是個套路,思路是維護一個隊列:
function bfs(root){
	const q=[root]//根節點先入隊
	while(q.length>0){
		const n=shift()//出隊並讀取
		n.children.forEach(child=>q.push(child))//孩子放入隊列。
	}
}
  • 先中後序遍歷也是套路:
function inorder(root){
	if(!root)return//左中右就是中序,先序是根左右,後續是左右根
	inorder(root.left)前
	root.val//中
	inorder(root.right)}

轉棧思路

var preorderTraversal = function(root) {
    let result = []
    let stack=[]
    if(root)stack.push(root)//下面while循環裏要從棧裏拿出來
    while(stack.length!==0){
        let node= stack.pop()
        result.push(node.val)
        if(node.right){//右節點在前,左節點在後,這樣先拿左節點的再拿出右節點的
            stack.push(node.right)
        }
        if(node.left){
            stack.push(node.left)
        }
    }
    return result
};
  • 本來遞歸的是節點,弄個棧自己維護,就變成把節點往棧裏放,然後按順序拿就行。
  • 先中後遍歷轉棧根上面思路一樣。先序就是上面那個,中序需要先左子樹,就是需要先把左子樹的所有節點推到棧裏。
const inorder=(root)=>{
	if(!root)return
	const stack=[]
	let p=root
	while(stack.length||p){
		while(p){
			stack.push(p)
			p=p.left
		}
		const n=stack.pop()
		console.log(n.val)
		p=n.right
	}
}
  • 後序遍歷是先序的改版,把根拿個棧存起來,左右出完了出根。
const postorder=(root)=>{
	const stack=[root]
	const outputStack=[]
	while(stack.length){
		const n=stack.pop()
		outputStack.push(n)
		if(n.left)stack.push(n.left)
		if(n.right)stack.push(n.right)
		
	}
	while(outputStack.length){
		const n=outputStack.pop()
		console.log(n)
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章