2015-02-21 2 views
0

Я знаю, что означает call stack size exceeded, но мне нужно обойти его.Избегайте ошибки стека вызовов

я получаю, когда я называю эту рекурсивную функцию

function fill(x_y) { 
    var locColor = getPx(x_y[0], x_y[1]); 
    if (locColor != pref.color) { 
     setPx(x_y[0], x_y[1], pref.color); 
     if (getPx(x_y[0] - 1, x_y[1]) == locColor) { 
      fill([x_y[0] - 1, x_y[1]]); 
     } 
     if (getPx(x_y[0], x_y[1] - 1) == locColor) { 
      fill([x_y[0], x_y[1] - 1]); 
     } 
     if (getPx(x_y[0] + 1, x_y[1]) == locColor) { 
      fill([x_y[0] + 1, x_y[1]]); 
     } 
     if (getPx(x_y[0], x_y[1] + 1) == locColor) { 
      fill([x_y[0], x_y[1] + 1]); 
     } 
    } 
} 

Это для применения холста.

x_y - это просто координаты x и y, где вызывается заполнение.

setPx печатает прямоугольник на холсте с заданными координатами.

getPx приобретает цвет прямоугольника холста дал это координаты

pref.color цвет, который пользователь выбрал для setPx

Может ли эта функция быть сделано без рекурсии?

+0

Да, я думаю, что каждая рекурсивная функция может быть переписана без рекурсии, хотя это не всегда лучше. Кстати, ваш код будет работать неопределенно (то есть до переполнения стека), если цвет 'getPx (x_y [0], x_y [1])' такой же, как 'pref.color'. – GolezTrol

+0

О, спасибо. Я не понимал, что – Kerndog73

+0

BTW. Если это кому угодно. Предел размера стека вызовов для хром - 20915. Я получил это от выполнения нескольких тестов с очень простой рекурсивной функцией. – Kerndog73

ответ

1

Это заполняет в следующем порядке:

  • слева,
  • сверху,
  • право,
  • дно

(если я не получил систему координат неправильно).

Вы можете сделать решение без рекурсии, используя список x_y для обработки; и вместо использования стека для рекурсии вы используете список для хранения параметров для следующих вызовов.

function fill(x_y) { 
    var todo = [x_y]; 
    var iniColor = getPx(x_y[0], x_y[1]); 
    while (todo.length) { 
     var curr = todo[0]; 
     var locColor = getPx(curr[0], curr[1]); 
     todo = todo.slice(1); 
     if (locColor != iniColor) { continue; } 
     if (locColor == pref.color) { continue; } 
     setPx(curr[0], curr[1], pref.color); 

     todo.push([curr[0]-1,curr[1] ]); 
     todo.push([curr[0], curr[1]-1]); 
     todo.push([curr[0]+1,curr[1] ]); 
     todo.push([curr[0], curr[1]+1]); 
    } 
} 

UPDATE: 2015-03-01

Из комментариев, это не так хорошо, как алгоритм в этом вопросе из-за количества итераций. В этом блоке я не проверял условие раньше, а это значит, что они добавлены в список todo, хотя они могут быть не хорошими кандидатами. И когда точка обрабатывается позже, условие проверяется.

 todo.push([curr[0]-1,curr[1] ]); 
     todo.push([curr[0], curr[1]-1]); 
     todo.push([curr[0]+1,curr[1] ]); 
     todo.push([curr[0], curr[1]+1]); 

Решение: проверьте как можно скорее; перед вызовом push.

+0

Отлично! Я никогда бы не подумал об этом! – Kerndog73

+0

Я заметил, что 'numTimesLooped == (x * 2) * ((y * 2) - 1) + 1/* если вызывается в верхнем левом углу * /', но код в моем вопросе 'numTimesLooped == x * y/* абсолютный минимум */'есть способ сделать его более эффективным. ** Пожалуйста, не воспринимайте это как критику. Я очень ценю ваш ответ. ** – Kerndog73

Смежные вопросы