我有0和1的矩阵,我需要从该矩阵中提取“形状”。形状由1个连接在8个方向组成。在最终结果中,我获得了2d形状的数组。每个形状阵列都包含原始矩阵中的单元索引。我写了脚本并且它有效,除了它与更大的矩阵崩溃。我在控制台Uncaught RangeError: Maximum call stack size exceeded
中收到错误我需要使用大型矩阵,如1000 x 1000甚至更多。
这是我的代码:
var matrixCols = 150;
var matrixRows = 150;
var matrix = [];
var shapes = [];
var checkedCels = [];
function createMatrix() {
for(var i = 0; i < matrixRows; i++) {
var row = [];
for(var j = 0; j < matrixRows; j++) {
var value = Math.round(Math.random());
row.push(value);
matrix.push(value);
}
console.log(JSON.stringify(row));
}
}
function getShapes() {
for(var i = 0; i < matrix.length; i++) {
if(checkedCels.indexOf(i) === -1 && matrix[i] === 1) {
shapes.push(formShape(i));
}
}
console.log('Total shapes:', shapes.length);
console.log(shapes);
}
function formShape(startIndex) {
return getNeighbours(startIndex);
}
function getNeighbours(index) {
if(checkedCels.indexOf(index) > -1) {
return [];
}
var cels = [index];
checkedCels.push(index);
var nwIndex = index - matrixCols - 1;
var nwCel = matrix[nwIndex];
if(typeof nwCel !== 'undefined' && nwCel === 1 && index % matrixCols > 0) {
cels = cels.concat(getNeighbours(nwIndex));
}
var nIndex = index - matrixCols;
var nCel = matrix[nIndex];
if(typeof nCel !== 'undefined' && nCel === 1) {
cels = cels.concat(getNeighbours(nIndex));
}
var neIndex = index - matrixCols + 1;
var neCel = matrix[neIndex];
if(typeof neCel !== 'undefined' && neCel === 1 && index % matrixCols < (matrixCols - 1)) {
cels = cels.concat(getNeighbours(neIndex));
}
var wIndex = index - 1;
var wCel = matrix[wIndex];
if(typeof wCel !== 'undefined' && wCel === 1 && index % matrixCols > 0) {
cels = cels.concat(getNeighbours(wIndex));
}
var eIndex = index + 1;
var eCel = matrix[eIndex];
if(typeof eCel !== 'undefined' && eCel === 1 && index % matrixCols < (matrixCols - 1)) {
cels = cels.concat(getNeighbours(eIndex));
}
var swIndex = index + matrixCols - 1;
var swCel = matrix[swIndex];
if(typeof swCel !== 'undefined' && swCel === 1 && index % matrixCols > 0) {
cels = cels.concat(getNeighbours(swIndex));
}
var sIndex = index + matrixCols;
var sCel = matrix[sIndex];
if(typeof sCel !== 'undefined' && sCel === 1) {
cels = cels.concat(getNeighbours(sIndex));
}
var seIndex = index + matrixCols + 1;
var seCel = matrix[seIndex];
if(typeof seCel !== 'undefined' && seCel === 1 && index % matrixCols < (matrixCols - 1)) {
cels = cels.concat(getNeighbours(seIndex));
}
return cels;
}
createMatrix();
getShapes();
我如何优化它?
答案 0 :(得分:3)
您可以通过维护要检查的单元格列表(最初只包含getNeighbours
)并在每次迭代时避免startIndex
函数中的递归:
当没有更多单元格要检查时,此循环停止。
通过不使用递归,程序将不会耗尽堆栈空间,并且算法将能够处理更大的矩阵(只要当前要检查的列表不超过可用内存)。
除此之外,还有另一种可能的优化:checkedCells
目前是一个数组,要查看某个单元格是否已被分析,请使用.indexOf()
(这是一个O( n)操作)。将checkedCells
更改为保持已分析单元格的索引作为键的对象将此查找减少为O(1)。
根据以上两点修改您的代码:
console.clear();
var matrixCols = 7;
var matrixRows = 7;
var matrix = [];
var shapes = [];
var checkedCels = {};
function createMatrix() {
for (var i = 0; i < matrixRows; i++) {
var row = [];
for (var j = 0; j < matrixRows; j++) {
var value = Math.round(Math.random());
// value = Math.random() > 0.75 ? 1 : 0; // to change the probability of a cell being "set"
row.push(value);
matrix.push(value);
}
console.log(row.map(function(x) {
return " X" [x]
}).join(''));
}
}
function getShapes() {
for (var i = 0; i < matrix.length; i++) {
if (!checkedCels[i] && matrix[i] === 1) {
shapes.push(formShape(i));
}
}
console.log('Total shapes:', shapes.length);
console.log(shapes);
}
function formShape(startIndex) {
var cels = [];
var toCheck = [startIndex];
while (toCheck.length) {
var index = toCheck.pop();
if (checkedCels[index]) {
continue;
}
if (matrix[index] !== 1) {
continue;
}
cels.push(index);
checkedCels[index] = 1;
var neighbours = [];
if (index % matrixCols > 0) {
neighbours.push(index - matrixCols - 1); // NW
neighbours.push(index - 1); // W
neighbours.push(index + matrixCols - 1); // SW
}
if (index % matrixCols < (matrixCols - 1)) {
neighbours.push(index - matrixCols + 1); // NE
neighbours.push(index + 1); // E
neighbours.push(index + matrixCols + 1); // SE
}
neighbours.push(index - matrixCols); // N
neighbours.push(index + matrixCols); // S
neighbours.forEach(function(n) {
if (typeof matrix[n] !== 'undefined') {
toCheck.push(n);
}
});
}
return cels;
}
createMatrix();
getShapes();
&#13;
为了便于阅读,我将矩阵大小限制在7x7,但上面的代码应在几秒钟内解决1000x1000矩阵。