2017-02-17 1 views
-2

サイズkの配列が与えられ、最初のn個の要素にnull以外の参照が割り当てられているとすると、最初のn Javaのサイズnの要素O(1)の時刻にakサイズの配列の最初のn個の要素を返す

明らかに、新しいkサイズの配列を作成して最初のn回繰り返して、各反復で要素を転送することで深いコピーを実行できますが、それはO(n)操作になります。

配列がメモリにどのように格納されるかを理解することで、配列の長さプロパティをkからnに変更してから、最初の配列の参照を返すことができたと思ったのです。

擬似法として:

public Foo[] head(Foo[] arr, int n) { 
    arr.length = n; 
    return arr; 
} 

何かが一定時間操作としてこれを生成するために行うことができる場合、私は思っていたが、私は、Javaがポインタ演算のようなものをサポートしていないとして、それが不可能であり得ることを恐れています。

これが不可能な場合は、同じ結果を提供する最も簡単な方法は何でしょうか?

+1

O(1)の時間にこれを行うことはできません。 Javaの配列の長さは変更できないため、新しい配列を作成する必要があります。 Jarrodの答えはこれを正しく行う方法の詳細を提供します。 –

+0

@マスおかげさまで、それがもっと速くできるかどうか疑問に思っていました。 –

答えて

2

あなたは生の配列で動作していないArrayListしなければならない場合は、Arraysはあなたが必要なものを持っています。ソースコードを見ると、配列のコピーを得るための最良の方法です。 System.arraycopy()メソッドは、非論理的なパラメータを入力すると、チェックされていない例外を多くスローするため、防衛プログラミングの優れた点があります。

Arrays.copyOf()のいずれかを使用して、最初の部分からNth要素を新しい短い配列にコピーできます。

public static <T> T[] copyOf(T[] original, int newLength) 

コピー指定された配列、ヌル( 必要であれば)と切り捨てまたはパディングので、コピーは、指定された長さを有します。 が元の配列とコピーの両方で有効なすべてのインデックスに対して、2つの配列は同じ値を含む になります。 のコピーで有効なインデックスの場合、コピーはnullを含みます。指定された長さが元の配列 の長さより大きい場合にのみ、そのようなインデックスは になります。結果の配列は元の配列 とまったく同じクラスです。

public static <T> T[] copyOfRange(T[] original, int from, int to) 

新しい配列にコピー指定された配列の指定された範囲:

2770 
2771 public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 
2772  T[] copy = ((Object)newType == (Object)Object[].class) 
2773   ? (T[]) new Object[newLength] 
2774   : (T[]) Array.newInstance(newType.getComponentType(), newLength); 
2775  System.arraycopy(original, 0, copy, 0, 
2776       Math.min(original.length, newLength)); 
2777  return copy; 
2778 } 

またはArrays.copyOfRange()もトリックを行います。 範囲の最初のインデックス(from)は、ゼロと original.length(両端を含む)の間にある必要があります。元の[from]の値は、コピーの最初の要素である に配置されます(ただし、== original.lengthまたは ==から)。元の配列の後続の要素の値は、コピー内の次の要素に配置された です。 の範囲の最終インデックス(to)は、 (original.length)より大きい場合があります。この場合、インデックスが大きいか等しいインデックスのすべての 要素にnullが格納されます〜 original.length - from。返される配列の長さは〜 からです。結果の配列は元の 配列とまったく同じクラスです。あなたが見ることができるように

3035 public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) { 
3036  int newLength = to - from; 
3037  if (newLength < 0) 
3038   throw new IllegalArgumentException(from + " > " + to); 
3039  T[] copy = ((Object)newType == (Object)Object[].class) 
3040   ? (T[]) new Object[newLength] 
3041   : (T[]) Array.newInstance(newType.getComponentType(), newLength); 
3042  System.arraycopy(original, from, copy, 0, 
3043       Math.min(original.length - from, newLength)); 
3044  return copy; 
3045 } 

、これらの両方が何をやろうとしていることは有効であると守備のロジックとSystem.arraycopy以上の単なるラッパーの機能があります。

System.arraycopyは、配列をコピーする最も速い方法です。

+0

ありがとうございます。どちらのユーティリティ関数も、新しい配列サイズに関して線形のSystem.arraycopyを使用します。この場合、一定の時間は不可能ですか? –

+1

これは正解です。一定の時間は不可能です。これはそれが得られるほど良いです。 –

+0

あなたが望むものを得るための唯一の方法は、Guavaの 'Iterators.filter(iterable、Predicate)'関数のようなものを使うことです。彼らは怠け者であり、アクセスされたときの処理アイテムだけです。しかし、それらは生の配列ではありません。これは、効率的な(時間と空間)サブ配列を取得し、生の配列として保持する唯一の方法です。 –

2

あなたはsublistを探しています。 (配列ではなくリスト)

しかし、ポイントは常に同じです。 nと配列の値を保存します。あなたはすでに完了しています。異なるサイズのふりをする別の偽の配列を使うのと同じものを使うことができます。ちょうど配列がサイズnのふりをして、配列を使うだけです。

けれども、あなたがしなければならない場合は、

List<MyClass> subArray = Arrays.asList(array).subList(index, index2); 
+0

ありがとうございます。私はList.subList()を認識していますが、残念ながら、メソッドの最後に配列を返すことに制限されています。 :/ –

+0

それから1つではありません。 Array.CopyOf(n)を使用するだけで妥当な唯一の解決策です。内部コピールーチンは本当に高速です。これまでは、内部的にcopyofが使用するSystem.arrayCopy()を使用してデータを移動する最も速い方法です。 – Tatarize

関連する問題