2013-03-10 113 views
0

在pascal中,我想隨機組織一個數組。因此,大部分時間數組應該以不同的方式組織。隨機數組?

考慮這個陣列設置

const 
    ARRAY_ELEMENTS = 3; 

SetLength(iIndex, ARRAY_ELEMENTS); 

for i := Low(iIndex) to High(iIndex) do 
begin 
    case i of 
    0: iIndex[i] := 0; 
    1: iIndex[i] := 1; 
    2: iIndex[i] := 2; 
    end; 
end; 

怎麼可能對於包含值0不總是在所述陣列的所述第一元件和用於包含值2 iIndex[]應不總是iIndex[]數組的最後一個值,但隨機生成數組的順序,以便初始化時數組的順序不總是相同的?

+0

你可以隨機交換/洗牌陣列中的元素。 – kobik 2013-03-10 16:11:45

+2

所以你的問題是[如何洗牌數組值](http://delphi.about.com/cs/adptips2003/a/bltip1003_4.htm)? – TLama 2013-03-10 16:12:58

+1

您的代碼沒有意義... – 2013-03-10 16:13:59

回答

4

此代碼置換整數數組,但我不確定它是否最優(可能不是)。

type 
    TDynIntegerArray = array of integer; 

procedure PermuteArray(A: TDynIntegerArray); 
var 
    B: TDynIntegerArray; 
    Z: TDynIntegerArray; 
    π: TDynIntegerArray; 
    i: Integer; 
    j: Integer; 
    k: Integer; 
begin 
    B := Copy(A); 
    SetLength(Z, Length(A)); 
    SetLength(π, Length(A)); 
    for i := 0 to High(Z) do 
    Z[i] := i; 
    for i := 0 to High(π) do 
    begin 
    π[i] := RandomFrom(Z); 
    for j := 0 to High(Z) do 
    begin 
     if Z[j] = π[i] then 
     begin 
     for k := j to High(Z) - 1 do 
      Z[k] := Z[k+1]; 
     SetLength(Z, length(Z) - 1); 
     break; 
     end; 
    end; 
    end; 
    for i := 0 to High(A) do 
    A[i] := B[π[i]]; 
end; 

快得多,但不冷靜的做法是簡單地隨機交換項目,一對在一個時間:

procedure FastPermuteArray(A: TDynIntegerArray); 
    procedure Swap(n, m: integer); 
    var 
    tmp: integer; 
    begin 
    tmp := A[n]; 
    A[n] := A[m]; 
    A[m] := tmp; 
    end; 
var 
    i: Integer; 
begin 
    for i := High(A) downto 1 do 
    Swap(i, RandomRange(0, i)); 
end; 
+0

「π」......知道你,這意味着一個笑話,我不明白。 – kobik 2013-03-10 16:31:53

+0

@kobik:好的,它在Delphi 2009+中編譯。但是,當然,您可以將變量重命名爲Pi或其他東西。 (在數學中,排列常常用*π*表示)。[我想可以想象,真正糟糕的笑話是這種算法的糟糕表現。我從來沒有真正學過實用的算法,所以這個問題可能會有一個更好的'教科書'算法。] – 2013-03-10 16:32:57

+1

+1,你的第二種方法實際上很「酷」,並且足夠簡單,可以完成這項工作。只需在開頭添加「Randomize」。 – kobik 2013-03-10 17:34:23

0

嘗試是這樣的:

uses 
    System.Generics.Collections; 

const 
    ARRAY_ELEMENTS = 3; 
var 
    iArray: array of Integer; 
    iIndex: TList<Integer>; 
    I, j: Integer; 
begin 
    Randomize; 

    SetLength(iArray, ARRAY_ELEMENTS); 

    iIndex := TList<Integer>.Create; 
    try 
    iIndex.Count := ARRAY_ELEMENTS; 
    for i := 0 to Pred(ARRAY_ELEMENTS) do 
     iIndex[i] := i; 

    for i := Low(iArray) to High(iArray) do 
    begin 
     j := Random(iIndex.Count); 
     iArray[iIndex[j]] := i; 
     iIndex.Delete(j); 
    end; 
    finally 
    iIndex.Free; 
    end; 
end; 

如果您在您的Delphi版本中沒有TList<T>可用,您可以使用普通的TList代替:

uses 
    Classes; 

const 
    ARRAY_ELEMENTS = 3; 
var 
    iArray: array of Integer; 
    iIndex: TList; 
    I, j: Integer; 
begin 
    Randomize; 

    SetLength(iArray, ARRAY_ELEMENTS); 

    iIndex := TList.Create; 
    try 
    iIndex.Count := ARRAY_ELEMENTS; 
    for i := 0 to Pred(ARRAY_ELEMENTS) do 
     iIndex[i] := Pointer(I); 

    for i := Low(iArray) to High(iArray) do 
    begin 
     j := Random(iIndex.Count); 
     iArray[Integer(iIndex[j])] := i; 
     iIndex.Delete(j); 
    end; 
    finally 
    iIndex.Free; 
    end; 
end; 
+1

這與我的第一個算法基本相同。所以我猜它可行,但比Fisher-Yates慢得多。 – 2013-03-10 19:49:37

+0

堆分配?!!爲什麼? – 2013-03-10 21:10:47

+0

在你看來,這個算法產生了一個均勻分佈的洗牌。我不明白你爲什麼沒這麼說。但是這裏真的沒有理由重新發明車輪。混洗是如此重要。當然,您的第一個停靠點是通過網絡搜索來找出關於該主題已經存在的知識體系? – 2013-03-10 21:23:26