配列回転問題の議論
3196 ワード
質問:配列aの要素を左にi個の位置に回転します.
この問題は比較的簡単に見える.しかし、多くのアプリケーションでは、さまざまな偽装が行われています.この機能もベクトルの基本的な動作である.この問題について,本稿では3つの解決方法を提示する.
方法1
まず、aの前のi個の要素を一時配列にコピーし、残りのn−i個の要素を左にi個の位置を移動し、最後に最初のi個の要素を一時配列からaの残りの位置にコピーする.
この方法で使用されるi個の追加の位置は、過大な記憶領域の消費を生じる.この方法は、メモリ容量が非常に貴重な場合には実行できません.
方法2
a[0]を一時変数tempに移動し、a[0+i]をa[0]に移動し、a[0+2*i]をa[0+i]に移動し、順次類推する.配列の下付き文字が配列の長さより大きい場合、現在の下付き文字から配列の長さを減算し、a[0]の値を取るまで戻り、tempから値を取るように変更して現在のループを終了します.このプロシージャがすべての要素を移動しない場合は、a[1]からすべての要素がすべて移動されるまで再び移動します.
この方法では、メモリ消費量が短く、実行時間も長くありません.しかし,プログラムを記述する過程では困難であり,記述されたコードは比較的長い.
方法3
配列aの前のi個の要素をベクトルmと見なし,残りの要素をベクトルnと見なし,配列aをmnと表すことができる.では,配列aをiビット左にシフトすることは,実はmnをnmに変換することである.mnについては,まずnに対して逆を求め,次にmに対して逆を求め,最後に全体に対して逆を求めるとmnをnmに変換できる.
この方法は時間的にも空間的にも効率的で、コードが非常に短く、エラーが発生しにくい.
反転の理解については、非常に古典的な例を参照することができる:Doug McIlroyが与えた10元配列を5つの位置に上方に選択する反転例.
ソースダウンロードリンク:https://github.com/XiaoYaoNet/Array-Convert
この問題は比較的簡単に見える.しかし、多くのアプリケーションでは、さまざまな偽装が行われています.この機能もベクトルの基本的な動作である.この問題について,本稿では3つの解決方法を提示する.
方法1
まず、aの前のi個の要素を一時配列にコピーし、残りのn−i個の要素を左にi個の位置を移動し、最後に最初のi個の要素を一時配列からaの残りの位置にコピーする.
void convert1(int a[], int n, int m)
{
int *b = new int[m]; //
for (int i = 0; i < m; i++) // m
*(b + i) = a[i];
for (int i = m; i < n; i++) // n-m m
a[i - m] = a[i];
for (int i = 0; i < m; i++) // m a
a[n-m + i] = b[i];
delete[]b; //
}
int main()
{
int a[10];
for (int i = 0; i < 10; i++)
a[i] = i;
convert1(a, 10, 5);
for (int i = 0; i < 9; i++)
cout << a[i] << ",";
cout << a[9] << endl;
return 0;
}
この方法で使用されるi個の追加の位置は、過大な記憶領域の消費を生じる.この方法は、メモリ容量が非常に貴重な場合には実行できません.
方法2
a[0]を一時変数tempに移動し、a[0+i]をa[0]に移動し、a[0+2*i]をa[0+i]に移動し、順次類推する.配列の下付き文字が配列の長さより大きい場合、現在の下付き文字から配列の長さを減算し、a[0]の値を取るまで戻り、tempから値を取るように変更して現在のループを終了します.このプロシージャがすべての要素を移動しない場合は、a[1]からすべての要素がすべて移動されるまで再び移動します.
int gcd(int a, int b) // i a
{
int c;
c = (a>b) ? b : a;
while (a%c != 0 || b%c != 0)
{
c--;
}
return c;
}
void convert2(int a[],int n,int m)
{
int temp; // temp
for (int i = 0; i < gcd(m,n); i++)
{
int temp = a[i]; // a[0] temp
int j=i;
for (; ;)
{
int k = j + m;
if (k>=n) // ,
k -= n;
if (k == i) // a[0] ,
break;
a[j] = a[k]; // a[0+i] a[0]
j = k;
}
a[j] = temp; // temp a[0+n*i]
}
}
int main()
{
int a[10];
for (int i = 0; i < 10; i++)
a[i] = i;
convert2(a, 10, 5);
for (int i = 0; i < 9; i++)
cout << a[i] << ",";
cout << a[9] << endl;
return 0;
}
この方法では、メモリ消費量が短く、実行時間も長くありません.しかし,プログラムを記述する過程では困難であり,記述されたコードは比較的長い.
方法3
配列aの前のi個の要素をベクトルmと見なし,残りの要素をベクトルnと見なし,配列aをmnと表すことができる.では,配列aをiビット左にシフトすることは,実はmnをnmに変換することである.mnについては,まずnに対して逆を求め,次にmに対して逆を求め,最後に全体に対して逆を求めるとmnをnmに変換できる.
void convert3(int a[], int n, int m)
{
if ((m - n) % 2 == 0)
{
for (int i = 0; i < (m - n) / 2; i++)
{
a[m - i] = a[m - i] ^ a[n + i];
a[n + i] = a[n + i] ^ a[m - i];
a[m - i] = a[m - i] ^ a[n + i];
}
}
else{
for (int i = 0; i <=(m - n) / 2; i++)
{
a[m - i] = a[m - i] ^ a[n + i];
a[n + i] = a[n + i] ^ a[m - i];
a[m - i] = a[m - i] ^ a[n + i];
}
}
}
int main()
{
int a[10];
for (int i = 0; i < 10; i++)
a[i] = i;
convert3(a, 0, 4); // m
convert3(a, 5, 9); // n
convert3(a, 0, 9); //
for (int i = 0; i < 9; i++)
cout << a[i] << ",";
cout << a[9] << endl;
return 0;
}
この方法は時間的にも空間的にも効率的で、コードが非常に短く、エラーが発生しにくい.
反転の理解については、非常に古典的な例を参照することができる:Doug McIlroyが与えた10元配列を5つの位置に上方に選択する反転例.
ソースダウンロードリンク:https://github.com/XiaoYaoNet/Array-Convert