2011-09-09 6 views
1

私はO(n)で実行すると信じているコードをいくつか持っていますが、時間を計ると多項式時間で実行されるようです。私は〜200000レコードを処理しようとしているので、私はヒープスペースを使い果たしていないので、サイズMAX_COUNTのブロックでそれを行いました。すなわち、処理フェーズでは、レコードのサイズが劇的に増加するいくつかのことが起こります。Java:これはO(n)でなければなりません。多分ArrayListの問題でしょうか?

私のコードから重要な部分をコピーしました。ここで何かが起こっているように思えますが、それは私が理解していないArrayListsと関係があります。

これは物事について最も賢明な方法ではないかもしれませんが、なぜ以前のものよりも各ブロックを処理するのに時間がかかるのか分かりません。つまり、各ブロックのサイズは5000(最初のブロックを除く)ですが、処理される最初のブロックは約5秒かかり、20番目のブロックは約25秒かかります。私は彼らにはすべて同じ時間がかかると期待しています。

// Maximum block size 
final int MAX_COUNT = 5000; 

// Total number of records in need of processing 
int n = records.size(); 

// the number of blocks to process 
int numBlocks = (n/MAX_COUNT) + 1; 
if (n % MAX_COUNT == 0) numBlocks--; 

// The number of records to process in the block. 
int numRecords; 
ArrayList<Record> recordBlock = null; 


// Iterate backwards through the blocks. 
for (int i = numBlocks; i > 0; i--) { 
    // Make sure we don't process too many records. 
    if ((i == 1 && numBlocks = 1 && n % MAX_COUNT != 0) || 
     (i == numBlocks && n % MAX_COUNT != 0)) 
     numRecords = n % MAX_COUNT; 
    else numRecords = MAX_COUNT; 

    recordBlock = new ArrayList<Record>(); 

    //EDIT: Fixed loop syntax (typo!) 
    for (int j = numRecords -1; j >= 0; j--) 
     recordBlock.add(records.remove(j)); 

    recordBlock = ThreadHelper.processRecords(recordBlock,true,true); 

    while (recordBlock.size() != 0) { 
     Record r = recordBlock.remove(recordBlock.size() -1); 
     // write 'r' to MySQL 
    } 

} 
+2

なぜドライブバイダウンボートですか?質問が十分に妥当と思われ、ダウンボートが理由を残すならいいかもしれない。 –

+0

システムリソース(特にメモリ)が不足していませんか?理想的な世界で線形でなければならないことは、「n」が大きくなるにつれてリソースの競合が起きることが多いからではありません。 –

+0

しばらくしてからガベージコレクションを行う必要があることは確かですが、私は...実行中であるかどうかを確認する方法はありますか? – theangryhornet

答えて

1

すでに述べたように、実際のコードは何その後、場合、カッコなしの文に対して持っている場合

for (Record r: recordBlock) {// write 'r' to MySQL } 
recordBlock.clear(); 
+0

'clear()'はarraylistをメモリに再割り当てさせますか? – theangryhornet

+1

再割り当てはありません。割り当てられた要素はガベージとしてマークされ、リストサイズは0に設定されます。 – Jiri

1

forループがrecordBlockに追加されることに問題があります。私は間違っていないよ場合

for (int j = numRecords -1; j >= j--) 
    recordBlock.add(records.remove(j)); 

for (int j = numRecords -1; j >= 0; j--) 
    recordBlock.add(records.remove(j)); 

でなければなりません。

編集:

私が見つけた別の間違いは、if文にあります。

if ((i == 1 && numBlocks = 1 && n % MAX_COUNT != 0) || 
    (i == numBlocks && n % MAX_COUNT != 0)) 

if ((i == 1 && numBlocks == 1 && n % MAX_COUNT != 0) || 
    (i == numBlocks && n % MAX_COUNT != 0)) 

私はそれを簡素化示唆する必要があります:最初の条件は、単に特殊なケースですので、ときI = 1

+0

あなたは正しいです。私は手で自分のコードからこれらの部分をタイプアウトしました。私はコピーとペーストでそれをn00bだけにしたくなかった。誰もが処理することは大変でした。しかし、私のコードではそうです。 – theangryhornet

+0

第2の編集については、私はそれを単純化することはできないと思います。特殊なケースは 'i == 1 'であり、ブロックが1つしかないからです。明らかに、次の投稿では、構文エラーについてもっと注意を払う必要があります。 – theangryhornet

+1

私はそれができると確信しています。論理的に言えば、あなたがチェックする最初のケース(i == 1 && numBlocks == 1)は、(i == numBlocks)チェックに含まれています。私は最初の声明が冗長チェックであることを確信しています。 –

3

このセクションでは、

if(i == numBlocks && n % MAX_COUNT != 0) 

for (int j = numRecords -1; j >= j--) 
     recordBlock.add(records.remove(j)); 

は、バッキングアレイがいっぱいになるたびにバッキングアレイをrecordBlockの背後に再割り当てします。むしろ、

recordBlock = new ArrayList<Record>(numRecords); 

と宣言してください。また、ループの構文が正しくありません。

+0

'new ArrayList (numRecords)は何をするのでしょうか?それもreallocされませんか? – theangryhornet

+1

しかし、バッキング配列自体の成長は 'n^2'なので、*は' O(1) 'にかなり整理されています...傷つけることはありませんが、これは全体の問題だとは思いません。 –

+0

@theangryhornet - ループ外で宣言することで、ArrayListのサイズが再割り当てを必要とせずにすべての受信レコードを受け入れることができるようになります。 – mcfinnigan

0

によって

while (recordBlock.size() != 0) {    
    Record r = recordBlock.remove(recordBlock.size() -1);    
    // write 'r' to MySQL   
} 

を置き換え、さらに@mcfinnigan

recordBlock = new ArrayList<Record>(numRecords); 

で言及コードは実際にはそうでないかもしれないと思います。

関連する問題