2015-09-05 55 views
0

爲什麼這個功能reverseArrayInPlace無法正常工作?我想簡單地做一下這個函數所說的內容 - 顛倒元素的順序,以便結果以相同的數組結尾arr。我選擇通過在函數中使用兩個數組來做到這一點。到目前爲止,它只是返回的元素回爲了...反向陣列到位

var arr = ["a","b","c","d","e","f"] 
    var arr2 = [] 

    var reverseArrayInPlace = function(array){ 

     var arrLength = array.length 
     for (i = 0; i < arrLength; i++) { 
     arr2.push(array.pop()) 
     array.push(arr2.shift()) 
     } 
    } 

    reverseArrayInPlace(arr) 
+1

也,JavaScript的已經有一個內置的就地陣列反向 – chiliNUT

+0

做一個陣列練習,規定我不能使用這些方法。我試圖使用push,pop,shift,unshift函數 – Sefton419

+1

https://en.wikipedia.org/wiki/In-place_algorithm –

回答

4

這裏的扭轉數組的一個更簡單的方法,使用原地算法

function reverse (array) { 
    var i = 0, 
     n = array.length, 
     middle = Math.floor(n/2), 
     temp = null; 

    for (; i < middle; i += 1) { 
    temp = array[i]; 
    array[i] = array[n - 1 - i]; 
    array[n - 1 - i] = temp; 
    } 
} 

你「分裂」了一半的陣列。呃,不是的,你只是重複了上半場。然後,使用公式n - 1 - i找到與當前索引相對於中間對稱的索引,其中i是當前索引。然後,使用臨時變量交換元素。 公式是正確的,因爲它會掉:

0 <-> n - 1 
1 <-> n - 2 

等。如果元素數量是奇數,則中間位置不會受到影響。

1

pop()將刪除數組的最後一個元素,並push()將項目追加到數組的末尾。所以你反覆彈出並推動數組的最後一個元素。

而不是使用push,你可以使用splice,您在陣列中的特定位置插入一個項目,它可以讓:

var reverseArrayInPlace = function (array) { 
    var arrLength = array.length; 
    for (i = 0; i < arrLength; i++) { 
     array.splice(i, 0, array.pop()); 
    } 
} 

(請注意,您不需要中間陣列來做到這一點。使用中間數組實際上不是一個就地反轉,只需在當前索引處彈出並插入即可。)

另外,有趣的評論 - 您可以跳過上一次迭代,因爲第一個元素總是以在length - 1迭代之後的最後位置。因此,您可以安全地重複執行arrLength - 1次。

我還想補充一點,Javascript有一個內置於reverse()方法的數組。所以["a", "b", "c"].reverse()將產生["c", "b", "a"]

一個真正原地算法將執行交換到在另一側與對應的元件的陣列的中間:

var reverseArrayInPlace = function (array) { 
    var arrLength = array.length; 
    for (var i = 0; i < arrLength/2; i++) { 
     var temp = array[i]; 
     array[i] = array[arrLength - 1 - i]; 
     array[arrLength - 1 - i] = temp; 
    } 
} 
+0

我可以看到你的意思,如果我使用相同的推流行,推流行方法,但我使用推流行,推,移。此外,我嘗試將切換轉換爲彈出,並且我仍然以'arr = [「a」,「b」,「c」,「d」,「e」,「f」,]' – Sefton419

+0

' push','pop','shift'和'unshift'只會依次移動元素。對於'[a,b,c]',想象幾次彈出和移動;你得到'[c,a,b]',然後'[b,c,a]',最後''a,b,c]'。所以你對陣列什麼都不做。 – Purag

+0

嘿@AustinSefton,我的解釋是否合理?你明白爲什麼你的代碼無法正常工作,對吧? – Purag

1

要調用與arr作爲參數的函數,因此這兩個arrarray指的是函數內的同一個數組。這意味着,該代碼不一樣:

var arr = ["a","b","c","d","e","f"] 
var arr2 = [] 

var arrLength = arr.length; 
for (i = 0; i < arrLength; i++) { 
    arr2.push(arr.pop()) 
    arr.push(arr2.shift()) 
} 

第一個語句從arr得到最後一個項目和arr2最後一個名額了。現在您有:

arr = ["a","b","c","d","e"] 
arr2 = ["f"] 

第二條語句從arr2獲得第一(也是唯一一個)項目,並把它最後在arr

arr = ["a","b","c","d","e","f"] 
arr2 = [] 

現在你回到開始的地方,同樣的事情發生在循環中的所有迭代中。最終的結果是沒有任何改變。


要使用poppush放置其他數組中顛倒的項目,你可以簡單地移動項目,直到數組爲空:

while (arr.length > 0) { 
    arr2.push(arr.pop()); 
} 

如果你想將它們移動回(而不是隻是用新的數組)的,你用shift擺脫的arr2push開始項目投入他們在arr末:

while (arr2.length > 0) { 
    arr.push(arr2.shift()); 
} 

通常不會使用堆棧/隊列操作完成反轉,只需將項目從頭開始與結束項目交換即可。這是快了很多,而且你不需要另一個數組作爲緩衝區:

for (var i = 0, j = arr.length - 1; i < j; i++, j--) { 
    var temp = arr[i]; 
    arr[i] = arr[j]; 
    arr[j] = temp; 
} 

這是交換對這樣的:

["a","b","c","d","e"] 
    | |  | | 
    | +-------+ | 
    +---------------+ 
+0

爲了避免必須做最後一個'while'循環,你也可以先做一個'arr2 = arr.splice(0,n)',然後用'倒'角色來做'while'(while(arr2.length )arr.push(arr2.pop())'。 – cars10m

+0

@ cars10:重點在於展示如何使用堆棧/隊列操作進行操作,就像操作系統嘗試的那樣。當然有幾個簡單的方法來做到這一點。 – Guffa

1

隨着我對這項任務的約束,這是方法我想通了,如何解決這個問題:

var arr = ["a","b","c","d","e","f"] 
var arr2 = [] 

var reverseArrayInPlace = function(array){ 

     var arrLength = array.length 
     for (i = 0; i < arrLength; i++) { 
     arr2.push(array.pop()) 
     } 
     for (i = 0; i < arrLength; i++) { 
     array[i] = arr2.shift() 
     } 
    } 

     reverseArrayInPlace(arr) 

感謝您對您的幫助!



*****編輯******

對於所有的你仍然有興趣,我重寫它使用此線程,從我自己的心理設備一些幫助。 ..在這一點上是有限的。這是它:

arr = [1,2,3,4,5,6,7,8,9,10,11,12,13] 
    arr2 = ["a","b","c","d","e","f"] 
    arr3 = [1,2,3] 
    arr4 = [1,2,3,4] 
    arr5 = [1,2,3,4,5] 


    var reverseArrayInPlace2 = function(array) { 

     var arrLength = array.length 
     var n = arrLength - 1 
     var i = 0 
     var middleTop = Math.ceil(arrLength/2) 
     var middleBottom = Math.floor(arrLength/2) 

     while (i < Math.floor(arrLength/2)) { 

     array[-1] = array[i] 
     array[i] = array[n] 
     array[n] = array[-1] 
     // console.log(array) 
     i++ 
     n-- 

     } 

     return array 
    } 

    console.log(reverseArrayInPlace2(arr)) 
    console.log(reverseArrayInPlace2(arr2)) 
    console.log(reverseArrayInPlace2(arr3)) 
    console.log(reverseArrayInPlace2(arr4)) 
    console.log(reverseArrayInPlace2(arr5)) 

P.S.改變全局變量有什麼問題?替代方案會是什麼?

+0

我不確定它是否真的算作「就地」,但我很高興你已經解決了你的問題 –

+0

通常不是一個好主意,讓一個函數改變一個全局變量(在你的情況下'arr2' )。閱讀@Guffa在他的回答中寫的內容。他很好地覆蓋了它! – cars10m

+0

我對三種主要方法(JS內置,彈出/推送和交換位置)的速度差異感到驚訝,請參閱此處:http://jsperf.com/reverse-builtin-vs-optimised#run – cars10m

0
  • 該解決方案使用簡寫

var arr = ["a","b","c","d","e","f"]

const reverseInPlace = (array) => { 
    let end = array.length; 

    while(end--) 
    array.unshift(array.pop()); 

    return array; 
} 

reverseInPlace(arr)

+0

所有這些都是通過循環遍歷數組並最終返回相同的數組。 – Aaron

1

這是我沒有臨時陣列的解決方案。沒有什麼突破性的,只是一些提出的解決方案的縮短版本。

let array = [1, 2, 3, 4, 5]; 

for(let i = 0; i<Math.floor((array.length)/2); i++){ 
    var pointer = array[i]; 
    array[i] = array[ (array.length-1) - i]; 
    array[(array.length-1) - i] = pointer; 
} 

console.log(array); 
//[ 5, 4, 3, 2, 1 ] 
1

如果您在使用Eloquent Javascript,練習明確指出不要使用新的數組作爲臨時值存儲。本書後面的線索呈現瞭解決方案的結構,就像Stefan Baiu的回答。

我在這裏發佈的答案使用的行數少於Stefan's,因爲我認爲將函數中的變量array.length存儲在變量中是多餘的。這也使我們的初學者更容易閱讀。

function reverseArrayInPlace(array) { 

    for (var z = 0; z < Math.floor(array.length/2); z++) { 

     var temp = array[z]; 
     array[z] = array[array.length-1-z]; 
     array[array.length-1-z] = temp; 

    } 

    return array; 
} 
0

我想你想要一個簡單的方法來扭轉數組。希望這將有助於你

var yourArray = ["first", "second", "third", "...", "etc"] 
var reverseArray = yourArray.slice().reverse() 

console.log(reverseArray) 

你會得到

["etc", "...", "third", "second", "first"]