简体   繁体   English

将递归函数转换为while循环

[英]Convert recursive function to while loop

I have a potential stack overflow issue with a recursive function. 我有一个递归函数潜在的堆栈溢出问题。 Usually I can solve this with a while loop and a condition, but I cannot figure out the condition to based this while loop on. 通常,我可以使用while循环和条件来解决此问题,但是我无法弄清楚基于while循环的条件。

Here is the current recursive function which counts the number of handlers in an object of unknown # of nested objects. 这是当前的递归函数,它计算未知嵌套对象数的对象中处理程序的数量。

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;
}

Can this be converted to a non-recursive function? 可以将其转换为非递归函数吗?

The way I usually get around recursive functions is to use a stack or a queue to maintain the data that needs to be processed. 我通常绕过递归函数的方法是使用堆栈或队列来维护需要处理的数据。 Stacks are easier in JavaScript, so we'll go with that. 在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;
}

Problem arises in such recursive function when you have circular reference. 当您有循环引用时,在这种递归函数中会出现问题。 You have to keep track of what objects you already parsed. 您必须跟踪已解析的对象。

Let's say we have this object : 假设我们有这个对象:

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
            }
        }
    }
}

Total handlers count should be 20. 处理程序总数应为20。

And then we add a circular reference : 然后我们添加一个循环引用:

test.child1.member3 = test;

Here is how I would handle it without thinking of performances : 这是我不考虑表演就如何处理的方法:

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));

In javascript, unless you have setup a mapping logic, you can't retrive the parent object of a member. 在javascript中,除非您设置了映射逻辑,否则您将无法检索成员的父对象。 With a circular reference in the object, you will probably end up with the total amount of handlers in the object tree, unless you select a branch with no circular reference. 在对象中使用循环引用时,除非选择没有循环引用的分支,否则您可能最终将获得对象树中的处理程序总数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM