簡體   English   中英

將遞歸函數轉換為while循環

[英]Convert recursive function to while loop

我有一個遞歸函數潛在的堆棧溢出問題。 通常,我可以使用while循環和條件來解決此問題,但是我無法弄清楚基於while循環的條件。

這是當前的遞歸函數,它計算未知嵌套對象數的對象中處理程序的數量。

countHandlers(obj){
    let count = 0;
    for(let k in obj){
        if(k === "_handlers"){
            count += obj[k].length;
        }
        else if(typeof obj[k] === 'object') {
            count += this.countHandlers(obj[k])
        }
    }
    return count;
}

可以將其轉換為非遞歸函數嗎?

我通常繞過遞歸函數的方法是使用堆棧或隊列來維護需要處理的數據。 在JavaScript中使用堆棧更容易,因此我們將繼續介紹。 :)

function countHandlers(obj) {
    let stack = [];
    stack.push(obj);

    let count = 0;
    while (stack.length > 0) {
        let currentObj = stack.pop();   

        for (let k in currentObj) {
            if (k === "_handlers") {
                count += currentObj[k].length;
            }
            else if (typeof currentObj[k] === 'object') {
                stack.push(currentObj[k]);
            }
        }
    }

    return count;
}

當您有循環引用時,在這種遞歸函數中會出現問題。 您必須跟蹤已解析的對象。

假設我們有這個對象:

var test = {
    _handlers: {
        length: 1
    }, 
    child1: {
        member1: {
            _handlers: [7, 9, 12], 
            child: {
                morehandlers: {
                    _handlers: {
                        length: 7
                    }
                }, 
                _handlers: [1]
            }
        }, 
        member2: {
            _handlers: {
                length: 1
            }
        }
    }, 
    child2: {
        value: 2
    }, 
    child3: {
        last: {
            _handlers: {
                length: 7
            }
        }
    }
}

處理程序總數應為20。

然后我們添加一個循環引用:

test.child1.member3 = test;

這是我不考慮表演就如何處理的方法:

let parsedHandlers = null;
let handlersCountLaunched = false;
function countHandlers(obj) { // Cannot be async
    let countObj = obj;
    let count = 0;
    for (let i = 0; i < parsedHandlers.length; i++) {
        if (countObj === parsedHandlers[i]) {
            countObj = null;
            break;
        }
    }
    if (countObj !== null) {
        parsedHandlers.push(countObj);
        for (let k in obj) {
            if (k === "_handlers") {
                count += obj[k].length;
            } else if (typeof obj[k] === 'object') {
                count += this.countHandlers(obj[k]);
            }
        }
    }
    return count;
}
function getHandlersCount(mainObj) {
    if (!handlersCountLaunched) {
        parsedHandlers = [];
        handlersCountLaunched = true;
        let count = countHandlers(mainObj);
        handlersCountLaunched = false;
        parsedHandlers = null;
        return count;
    } else {
        console.error('TimingError : getHandlersCount() has been called and has not yet finished counting');
        return -1;
    }
}

console.log(getHandlersCount(test));

在javascript中,除非您設置了映射邏輯,否則您將無法檢索成員的父對象。 在對象中使用循環引用時,除非選擇沒有循環引用的分支,否則您可能最終將獲得對象樹中的處理程序總數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM