簡體   English   中英

JavaScript中數組的螺旋遍歷

[英]Spiral traversal of an array in JavaScript

我正在解決編碼問題並編寫一個函數,該函數將以類似蝸牛的模式遍歷嵌套數組( 此處為示例)。

例如,給定[[1,2,3], [8,9,4], [7,6,5]] ,函數應輸出[1,2,3,4,5,6,7,8,9]

在我的main函數中,我創建了4個函數來遍歷所有方向的數組。 在每個步驟中,我將值推到當前網格位置並檢查標志數組以確定是否已訪問下一個位置。

我有兩個問題:

  1. 我無法成功克隆作為參數傳遞的數組。 即使我使用了array.slice(0) ,新的flagsArray似乎也可以作為指向array的指針,當我修改flagsArray ,更改會反映在array 這是為什么?

我運行此測試時,我的克隆方法似乎有效:

var array = [0, 1];
var array_clone = array.slice(0);
array_clone[2] = 3;
console.log(array); // No changes to array
  1. 我在執行traverseDown()時得到flagsArray[(i + 1)] is undefined錯誤。 這看起來像嘗試讀取flagsArray之外的索引。 但是,如果我在while循環中檢查flagsArray[i + 1][j] === false && i < flagsArray.length ,那么一旦它嘗試讀取數組之外while循環是否應該停止? 因為flagsArray[flags.Array.length]是未定義的,因此不等於false ,另一個原因是我也檢查了i是否在flagsArray范圍內。

這是我的功能:

snail = function(array) {
  console.log(array);
  var output = [];

  var flagsArray = array.slice(0);

  // Populating flagsArray with false values
  // False = index not visited yet
  for (var i = 0; i < flagsArray.length; i++) {
    for (var j = 0; j < flagsArray[i].length; j++) {
      flagsArray[i][j] = false;
    }
  }
  var i = 0;
  var j = 0;

    var traverseRight = function() {
    while (flagsArray[i][j + 1] === false && j < flagsArray[i].length) {
      console.log(flagsArray[i][j].length + 'Traversing right Index traversed: [' + i + '][' + j +'] Flag before: ' + flagsArray[i][j] + 'Element pushed: ' + array[i][j]);
      output.push(array[i][j]);
      flagsArray[i][j] = true;
      j++;
    } 
  }

  var traverseDown = function() {
    while (flagsArray[i + 1][j] === false && i < flagsArray.length) {
      console.log('Traversing Down Index traversed: [' + i + '][' + j +'] Flag before: ' + flagsArray[i][j] + 'Element pushed: ' + array[i][j]);
      output.push(array[i][j]);
      flagsArray[i][j] = true;
      i++;
    }
  }

  var traverseLeft = function() {
    while (array[i][j - 1] === false && j >= 0) {
      console.log('Traversing left Index traversed: [' + i + '][' + j +'] Flag before: ' + flagsArray[i][j] + 'Element pushed: ' + array[i][j]);
      output.push(array[i][j]);
      flagsArray[i][j] = true;
      j--;
    }
  }

  var traverseUp = function() {
    while (array[i][j] === false && j >= 0) {
      console.log('Traversing Up Index traversed: [' + i + '][' + j +'] Flag before: ' + flagsArray[i][j] + 'Element pushed: ' + array[i][j]);
      output.push(array[i][j]);
      flagsArray[i][j] = true;
      i--;
    }
  }

  while (flagsArray[i][j + 1] === false) {
    traverseRight();
    traverseDown();
    traverseLeft();
    traverseUp();
  } 
  return output;
}

console.log(snail([[1,2,3],[8,9,4],[7,6,5]]));

問題1

我無法成功克隆作為參數傳遞的數組。 即使我使用了array.slice(0) ,新的flagsArray似乎也可以作為指向array的指針,當我修改flagsArray ,更改會反映在array 這是為什么?

這是因為你有一個二維數組而且你只制作了外部數組的副本。 它的每個元素都是一個原始的內部數組。

要制作我們可以在不改變原始數據的情況下操作的array的深層副本,我們必須復制每個內部數組:

var flags = new Array(array.length);
for (var i = 0; i < array.length; ++i) {
  flags[i] = array[i].slice();
}

(注意:我已經自由地將flagsArray重命名為flags 。另請注意,可以調用slice()而不使用參數來從索引0開始復制數組。)

我們可以使用Array.map更簡潔地做同樣的事情:

var flags = array.map(function (subarray) {
  return subarray.slice();
});

但如果我們立即用false覆蓋它們,那么復制數組值是沒有意義的:

for (var i = 0; i < flags.length; i++) {
  for (var j = 0; j < flags[i].length; j++) {
    flags[i][j] = false;
  }
}

如果我們在制作它時將false值放入flag數組中,我們可以刪除那個雙循環:

var flags = array.map(function (subarray) {
  return subarray.map(function () {
    return false;
  });
});

問題2

我在執行traverseDown()時得到flagsArray[(i + 1)] is undefined錯誤。 這看起來像嘗試讀取flagsArray之外的索引。 但是,如果我在while循環中檢查flagsArray[i + 1][j] === false && i < flagsArray.length ,那么一旦它嘗試讀取數組之外while循環是否應該停止?

不,JavaScript沒有做任何事情來阻止越界數組訪問。 發生了什么事

while (flagsArray[i + 1][j] === false && i < flagsArray.length) {

flagsArray[i + 1]計算為undefined因為i + 1超出了數組的最后一個元素。 然后你試着查找[j] ,程序崩潰,因為undefined沒有屬性。

你甚至無法評估i < flagsArray.length 此外,該測試不會阻止無效索引,因為如果i是最后一個元素的索引, flagsArray[i + 1]超出范圍。

一般觀察

該測試有兩個問題:

while (flagsArray[i][j + 1] === false && j < flagsArray[i].length) {

首先,在訪問數組之前,您忽略了檢查數組索引。 其次,你沒有測試正確的價值。 你應該在訪問flagsArray[i][j + 1]之前測試j + 1

while (j + 1 < flagsArray[i].length && flagsArray[i][j + 1] === false) {

其他三個測試也有類似的問題。

作為編寫四個函數的替代方法,我建議您編寫遍歷邏輯一次,並使其依賴於具有03值的orientation變量。 與移動方向不同的唯一因素是增加網格索引的數量。 您可以在一對數組中查找這些增量值,其orientation為數組索引。

增量數組如下所示:

var dr = [ -1, 0, 1, 0 ],  // North, east, south, west.
    dc = [ 0, 1, 0, -1 ];

給定網格位置r, c ,您可以計算下一個位置,如下所示:

var R = r + dr[orientation],
    C = c + dc[orientation];

以下代碼段演示了這種方法。

 function print(line) { document.getElementById('message').innerHTML += line + '<br><br>'; } var snail = function(array) { var result = []; var flags = array.map(function (subarray) { return subarray.map(function () { return false; }); }); print(JSON.stringify(array)); var numRows = flags.length, numCols = flags[0].length, numElements = numRows * numCols, dr = [ -1, 0, 1, 0 ], // North, east, south, west. dc = [ 0, 1, 0, -1 ], r = 0, c = 0, orientation = 1; // Start heading east. var count = 0; while (result.length < numElements) { result.push(array[r][c]); flags[r][c] = true; var R = r + dr[orientation], // Calculate the next grid position. C = c + dc[orientation]; if (R >= 0 && R < numRows && C >= 0 && C < numCols && !flags[R][C]) { r = R; // If the position is valid, go ahead. c = C; } else { orientation = (orientation + 1) % 4; r = r + dr[orientation]; // Otherwise, turn clockwise and recalculate. c = c + dc[orientation]; } } return result; } window.onload = function () { print(snail([ [1, 2, 3], [8, 9, 4], [7, 6, 5] ])); }; 
 body { font-family: sans-serif; } 
 <div id="message"></div> 

螺旋陣列(ES6)

試試這個:

function spiral(array) {
    const matrix = [...array];
    const arr = [];

    while (matrix.length) {
        arr.push(
            ...matrix.shift(),
            ...matrix.map(a => a.pop()),
            ...matrix.pop().reverse(),
            ...matrix.map(a => a.shift()).reverse()
        );
    }
    return arr;
}

暫無
暫無

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

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