6

値の配列(すでに事前に並べ替えられている)を再並べ替えて、複数(N)列に表示し、垂直方向に読み取ることができるようにするための優れたアルゴリズムを持っている人はいますか?これは.Netに実装されますが、魔法の関数ではなく、移植性のあるものを好みます。

それが機能する良い例は、方向が垂直に設定されたテーブルとしてレンダリングされるASP.NetCheckBoxListコントロールです。

入力と出力の例を次に示します。

入力:

列=4
配列={"A"、 "B"、 "C"、 "D"、 "E"、 "F"、 "G"}

出力:

ACEG
BDF

ありがとう!

更新(詳細):

私がやろうとしていることについてもう少し情報を提供する必要があると思います...ほとんどの場合、この問題は、CheckBoxListの自動バインディング(出力する列と方向を指定でき、出力される)を使用することから発生しました。正しい順序のアイテムのテーブル)jQuery/AJAXを使用してチェックボックスグリッドを作成します。そのため、指定された幅のdivブロック(既知の幅のコンテナーdiv内)を持つcssを使用してそのレイアウトを複製しようとしているので、N個のアイテム(または列)の後にラップされます。これは、テーブルにレンダリングすることもできます(ASPのように) .Netがそれを行います。)

順序が水平であり、リストに多数のアイテムが含まれている場合は、垂直の列が読みやすくなることを除いて、すべてがうまく機能します。

配列に均等なグリッドを作成するのに十分なアイテムがない場合は、グリッドの正しい行/列に空のスポットを出力する必要があります。

また、配列に1行でも作成するのに十分なアイテムがない場合は、アイテムを元の順序で1行に出力するだけです。

その他の入力/出力は次のとおりです。

列=3
配列={"A"、 "B"、 "C"、 "D"}

ACD
B

列=5
配列={"A"、 "B"、 "C"、 "D"、 "E"、 "F"、 "G"、 "H"}

ACEGH
BDF

列=5
配列={"A"、 "B"、 "C"、 "D"}

あいうえお

4

3 に答える 3

6

わかりました、最初の発言で申し訳ありませんが、最初の回答へのコメントで説明したように機能させたい場合は、実際にはデータを再ソートする必要があります...まあまあ。ヘルパー マトリックスがなくても実行できるかもしれませんが、結果のコードは非常に複雑になる可能性があり、マトリックスが数バイトのメモリしか使用しない限り、この小さなヘルパー コンストラクトを使用しないのはなぜでしょうか?

以下の私のコードは、マトリックスを作成しています。行列を上から下に書き、次に左から右に書きます (そして、最初の行のすべての列を埋める要素がなくなると、最初の行以外は埋めなくなります)。次に、左から右、上から下の別の順序で読みます。基本的にここで行っているのは行列の転置です、ある順序で書き、別の順序で読むことによって。行列の転置は非常に初歩的な数学的操作です (多くの 3D プログラミングは行列計算を使用して動作しますが、転置は実際には単純な操作です)。秘訣は、最初にマトリックスを埋める方法です。どのような場合でも最初の列を埋めることができるようにするために、必要な列の数と配列のサイズに関係なく、要素を使い果たした場合は通常の順序で行列を埋めるのをやめ、残りのすべての要素を最初の行。これにより、コメントで提案した出力が生成されます。

正直なところ、全体は少し複雑ですが、その背後にある理論は正気であり、うまく機能するはずです:-D

int Columns;
char * Array[] = {"A", "B", "C", "D", "E", "F", "G"};

int main (
    int argc,
    char ** argv
) {
    // Lets thest this with all Column sizes from 1 to 7
    for (Columns = 1; Columns <= 7; Columns++) {

        printf("Output when Columns is set to %d\n", Columns);

        // This is hacky C for quickly get the number of entries
        // in a static array, where size is known at compile time
        int arraySize = sizeof(Array) / sizeof(Array[0]);

        // How many rows we will have
        int rows = arraySize / Columns;

        // Below code is the same as (arraySize % Columns != 0), but
        // it's almost always faster
        if (Columns * rows != arraySize) {
            // We might have lost one row by implicit rounding
            // performed for integer division
            rows++;
        }

        // Now we create a matrix large enough for rows * Columns
        // references. Note that this array could be larger than arraySize!
        char ** matrix = malloc(sizeof(char *) * rows * Columns);

        // Something you only need in C, C# and Java do this automatically:
        // Set all elements in the matrix to NULL(null) references
        memset(matrix, 0, sizeof(char *) * rows * Columns );

        // We fill up the matrix from top to bottom and then from
        // left to right; the order how we fill it up is very important
        int matrixX;
        int matrixY;
        int index = 0;
        for (matrixX = 0; matrixX < Columns; matrixX++) {
            for (matrixY = 0; matrixY < rows; matrixY++) {
                // In case we just have enough elements left to only
                // fill up the first row of the matrix and we are not
                // in this first row, do nothing.
                if (arraySize + matrixX + 1 - (index + Columns) == 0 &&
                        matrixY != 0) {
                    continue;
                }

                // We just copy the next element normally
                matrix[matrixY + matrixX * rows] = Array[index];
                index++;
                //arraySize--;
            }
        }

        // Print the matrix exactly like you'd expect a matrix to be
        // printed to screen, that is from left to right and top to bottom;
        // Note: That is not the order how we have written it,
        // watch the order of the for-loops!
        for (matrixY = 0; matrixY < rows; matrixY++) {
            for (matrixX = 0; matrixX < Columns; matrixX++) {
                // Skip over unset references
                if (matrix[matrixY + matrixX * rows] == NULL)
                    continue;

                printf("%s", matrix[matrixY + matrixX * rows]);
            }
            // Next row in output
            printf("\n");
        }
        printf("\n");

        // Free up unused memory
        free(matrix);
    }   
    return 0;
}

出力は

Output when Columns is set to 1
A
B
C
D
E
F
G

Output when Columns is set to 2
AE
BF
CG
D

Output when Columns is set to 3
ADG
BE
CF

Output when Columns is set to 4
ACEG
BDF

Output when Columns is set to 5
ACEFG
BD

Output when Columns is set to 6
ACDEFG
B

Output when Columns is set to 7
ABCDEFG

この C コードは、PHP、C#、Java などに簡単に移植できる必要があります。大きな魔法は必要ないため、ほぼ普遍的で、移植可能で、クロスプラットフォームです。


追加する必要がある1つの重要なこと:

このコードは、Columns を 0 に設定するとクラッシュします (0 による除算、私はそれをチェックしません)。また、配列内の要素よりも列が多い場合にもクラッシュします。これもチェックしません。arraySize を取得した直後に、どちらかを簡単に確認できます。

if (Columns <= 0) {
   // Having no column make no sense, we need at least one!
   Columns = 1;
} else if (Columns > arraySize) {
   // We can't have more columns than elements in the array!
   Columns = arraySize;
}

さらに、arraySize が 0 であることも確認する必要があります。その場合、関数に対して何もする必要がないため、関数からすぐに飛び出すことができます:) これらのチェックを追加すると、コードが堅固になります。

配列に NULL 要素があるとうまくいきますが、その場合、結果の出力に穴はありません。NULL 要素は、存在しないかのようにスキップされます。たとえば、使用できます

char * Array[] = {"A", "B", "C", "D", "E", NULL, "F", "G", "H", "I"};

出力は次のようになります。

ADFI
BEG
CH

列の場合 == 4.が必要な場合は、穴要素を作成する必要があります。

char hole = 0;
char * Array[] = {"A", "B", &hole, "C", "D", "E", &hole, "F", "G", "H", "I"};

ペイントコードを少し変更します

    for (matrixY = 0; matrixY < rows; matrixY++) {
        for (matrixX = 0; matrixX < Columns; matrixX++) {
            // Skip over unset references
            if (matrix[matrixY + matrixX * rows] == NULL)
                continue;

            if (matrix[matrixY + matrixX * rows] == &hole) {
                printf(" ");
            } else {
                printf("%s", matrix[matrixY + matrixX * rows]);
            }
        }
        // Next row in output
        printf("\n");
    }
    printf("\n");

出力サンプル:

Output when Columns is set to 2
A 
BF
 G
CH
DI
E

Output when Columns is set to 3
ADG
BEH
  I
CF

Output when Columns is set to 4
AC H
BDFI
 EG
于 2008-10-07T10:45:19.023 に答える
3

小さな更新:

ここで使用しているアルゴリズムは、画像のペイントに使用するアルゴリズムを変更したものです。配列エントリを画像のピクセルデータのふりをして、画像を左から右(1. LtoR)および上から下(2. TtoB)にペイントしていますが、画像データは上から下(1. TtoB)、次に左から右(2. LtoR); 別の順序でIOW。画像にを付けることはできないため、これが5列または6列で機能しない理由です。4列の場合、出力は次のようになります。

ACEG
BDF

画像としてこれはこのように見えます

OOOO
OOO.

Oは画像のピクセルであり、。未定義のピクセル(欠落しているピクセル)であること。欠落しているものは、画像の中央ではなく、画像の最後にのみ存在する可能性があります。つまり、このように見えることもあります

OOO
OO.
OO.
OO.

最初に上から下に、次に左から右に読む場合、すべての欠落しているピクセルは常に最後にあります。その場合、すべての欠落しているピクセルは最後に互いに直接続くためです。ダイアグラムTtoB、次にLtoRを読むと、「Pixel、Pixel、Pixel、Pixel、...、Pixel、Missing、Missing、Missing、...、Missing」のように読む必要があります。「Pixel、 Missing、Pixel」または「Missing、Pixel、Missing」。すべてのピクセルが一緒になり、すべての欠落も一緒になります。

コメントが示すように、5列の場合、次のようになります。

ACEFG
BD

ただし、画像としては次のようになります

OOOOO
OO...

そして、これはアルゴリズムでは許可されていません。TtoB、次にLtoRと読むと、「Pixel、Pixel、Pixel、Pixel、Pixel、Missing、Pixel、Missing、Pixel、Missing」と表示されます。そして、上で述べたように、これはアルゴリズムによって許可されていません。したがって、この単純なピクセルペイントのアプローチでは、多くの列をペイントすると画像に穴ができる場合、要求された数の列はペイントされません。その場合、それは単に穴を埋めますが、これにより描画される列が少なくなります。

要求されたピクセル数を常にペイントするソリューションを考えてみましょう(別の返信で)。


そのためにメモリ内のデータを再配置する必要はまったくありません。希望の順序で印刷するだけです。

いくつかのCコード(私はそれを非常に冗長にしているので、誰もが私がそうしていることを理解しています。もちろん、これははるかにコンパクトになる可能性があります):

int Columns = 4;
char * Array[] = {"A", "B", "C", "D", "E", "F", "G"};

int main (
    int argc,
    char ** argv
) {
    // This is hacky C for quickly get the number of entries
    // in a static array, where size is known at compile time
    int arraySize = sizeof(Array) / sizeof(Array[0]);

    // How many rows are we going to paint?
    int rowsToPaint = (arraySize / Columns) + 1;

    int col;
    int row;
    
    for (row = 0; row < rowsToPaint; row++) {
        for (col = 0; col < Columns; col++) {
            int index = col * rowsToPaint + row;
            
            if (index >= arraySize) {
                // Out of bounds
                continue;
            }

            printf("%s", Array[index]);
        }
        printf("\n"); // next row
    }
    printf("\n");
    return 0;
}

注:これは、値が8(すべてが1行にペイントされる)および値が4以下(3、2、および1で正常に機能する)で正常に機能しますが、5では機能しません。これは障害ではありません。アルゴリズムの、それは制約のせいです。

ACEFG
BD

制約は、修正されたソート済みデータを取得するために列が上から下に読み取られることを示しています。ただし、「EFG」の上は並べ替えられており、上から下ではなく、左から右になっています。したがって、このアルゴリズムには問題があります。列の使用=3が機能します

ADG
BE
CF

2つ使用しても機能します

AE
BF
CG
D

そして、すべてを1つの列にまとめます。

于 2008-10-06T18:29:32.347 に答える
1

とにかくこれは宿題のように見えます

array<String^>^  sArray = {"A", "B", "C", "D", "E", "F", "G"};
double Columns = 4;
double dRowCount = Convert::ToDouble(sArray->Length) / Columns;
int rowCount = (int) Math::Ceiling(dRowCount);
int i = 0;
int shift = 0;
int printed = 0;
while (printed < sArray->Length){
    while (i < sArray->Length){
        if (i % rowCount == shift){
            Console::Write(sArray[i]);
            printed++;
        }
        i++;
    }
    Console::Write("\n");
    i = 0;
    shift++;
}
于 2008-10-06T18:15:37.350 に答える