固定サイズの配列のすべての可能な値を作成します
-
18-09-2019 - |
質問
私は、配列のすべての可能な順列を通じていくつかの非常に基本的なものという意志サイクルを作るしようとしています。
本当にこれはアセンブリで行われているが、私はCでそれを説明します。
基本的に、我々は、配列uint8_t *data=malloc(10);
を持っていると言う。
私は、配列data
のバイトのすべての組み合わせを印刷しますアルゴリズムを作成したい。
はい、私はちょうど私のように自分のコンピュータ上で実行されている残すことができます何かを探しています..私はそれが遅くなることがわかっている(と多くの値があります)、と私は本当に複雑な最適化されたバージョンを求めていませんよ特定の条件に従う特定の値を見つけるための強引なタイプのものの一種..
([0,1,2]が[2,1,0]と同じでカウントすべきではないので、メモ、私は順列を言います)
編集: また、私は唯一の512バイトの自立型のブートローダにこれを変換されますので、あまりにも多くのlibc関数を使用しないようにしてください。
私はこれを行う方法を知っている知っているが、私の人生のために私はちょうど私の頭の中でアルゴリズムの仕事をすることはできません!
解決
あなたの質問は奇妙な用語の重複が整理に苦しんでいます。あなたが記述するものから、あなたが、符号なし8ビット値のすべての可能な10タプルを生成することが表示されます。これらは、「順列」ではありませんし、このすべては、生成順列とは何の関係もありません。
uint8_t
値のすべての可能な10タプルを生成するコードを思い付くことは容易です。たとえば、次の簡単なコードでは、それを行います。
#define N 10u
uint8_t data[N] = { 0 };
unsigned i;
do {
/* Process the current 10-typle in `data` array */
/* in any way you want do */
/* Generate next tuple */
for (i = 0; i < N && ++data[i] == 0; ++i);
} while (i < N);
これは80ビットのリトルエンディアン数だけ巡回増加よりも何もありません。
他の人がすでに述べたように、はもちろん、これは取るために起こっている時間の量は、ビューの任意の実用的な観点から、絶対に無用全部を行います。
他のヒント
さて、全体のことは無益な運動(私のコメントは、質問に添付参照)であるが、ここであなたは、とにかく行く(x86_64のAT&Tスタイルの組み立て、AMDシステムVの呼び出し規約を想定します)。私はテストを行わず、ここでこれを書いているので、それはそれはバグを持っていることは完全に可能です。それにもかかわらず、コードの基本的な動作は、完全に透明であるべきである。
代わりに、メモリ内の80ビット・バッファ上で動作する、私は単に2つの64ビットレジスタを横切って80ビットのフィールド分割のあらゆる可能性を介して実行しています。あなたの条件はメモリにそれらを保存し、あなたが本当にしたい場合はuint8_t
ように、そのメモリにアクセスすることができますチェックあなたの日常ます。
push r12
push r13
xor r12, r12 // zero out low 64 bits of our "buffer" in register
xor r13, r13 // zero out high 16 bits of our "buffer"
loop:
// Copy the current array value into rsi:rdi and call whatever routine you're
// using to check for magic conditions. This routine's copy (in r13:r12)
// should be unaffected if you're obeying the System V calling conventions.
mov r12, rdi
mov r13, rsi
call _doSomethingWithValue
// Increment r13:r12 to get the next value. We only need to worry about r13
// if the increment of r12 wraps around to zero.
inc r12
jnz loop
inc r13
// Check for the termination condition, though you'll never hit it =)
cmp $0x10000, r13
jne loop
// We don't actually need to clean up; the apocalypse will come and there
// won't be electricity to run the computer before it reaches this point of
// the program. Nonetheless, let's be exhaustively correct.
pop r13
pop r12
私はあなたが読んでいることを示唆している、
ドナルド・クヌース。コンピュータプログラミングのアート、4巻、分冊2:生成すべてのタプルと順列
次のような問題への古典的な再帰的なアプローチがあります:
#include <stdio.h>
void print(const uint8_t *v, const int size)
{
if (v != 0) {
for (int i = 0; i < size; i++) {
printf("%4d", v[i] );
}
printf("\n");
}
} // print
void visit(uint8_t *Value, int N, int k)
{
static level = -1;
level = level+1; Value[k] = level;
if (level == N)
print(Value, N);
else
for (int i = 0; i < N; i++)
if (Value[i] == 0)
visit(Value, N, i);
level = level-1; Value[k] = 0;
}
main()
{
const int N = 4;
uint8_t Value[N];
for (int i = 0; i < N; i++) {
Value[i] = 0;
}
visit(Value, N, 0);
}
の例は、他のアプローチが存在するリンクするから取られます。あなたは、私はさらに、アルゴリズムを説明できる必要がある場合は、その背後にある理論は...非常に簡単ですが、それはかなり自己explainatoryです。
Mの項目のうち、Nの組み合わせを生成するためのこのアルゴリズムのnoreferrer"> Nするからk個の要素の全ての組み合わせを返すアルゴリズム
あなたがC ++で作業していた場合、
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
int main() {
int N;
std::cin >> N;
std::vector<int> data(N);
std::fill(data.begin(), data.end(), 1);
std::partial_sum(data.begin(), data.end(), data.begin());
do {
std::copy(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
} while (std::next_permutation(data.begin(), data.end()));
return 0;
}
あなたが入力3
、それが出力された場合、
1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1
次の順列を参照してください:C ++はどのようにstd::next_permutation
作品の権利にそれを取得します。
普通Cにこれを翻訳
#include <stdio.h>
#include <stdlib.h>
int main() {
int i, N, *data;
scanf("%d", &N);
data = malloc(N);
for (i = 0; i < N; i++) data[i] = i + 1;
while (1) {
int j, temp;
for (i = 0; i < N; i++) printf("%d ", data[i]);
printf("\n");
for (i = N - 1; i > 0 && data[i] < data[i - 1]; i--);
if (i <= 0) break;
for (j = N; data[i - 1] >= data[--j];);
temp = data[i - 1], data[i - 1] = data[j], data[j] = temp;
for (j = N - 1; i < j; i++, j--)
temp = data[i], data[i] = data[j], data[j] = temp;
}
return 0;
}
<時間>
質問は既存の配列の順列を求めるのではなく、すべての可能な配列の内容を生成していない場合は、これは非常に多くの方が簡単です。 (また、多くの組み合わせがあります。)
memset(data, 0, N);
do {
for (i = 0; i < N; i++) printf("%d ", data[i]);
printf("\n");
for (i = 0; i < N && !++data[i++];);
} while (i < N);