System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
является нативным методом.
Какова временная сложность этого метода?
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
является нативным методом.
Какова временная сложность этого метода?
Для этого потребуется пройти через все элементы массива. Массив - это уникальная структура данных, где вы должны указать размер при его инициализации. Заказ будет иметь размер исходного массива или в Big O - его O (длина).
Infact это происходит внутри в ArrayList. ArrayList обертывает массив. Хотя ArrayList похож на динамически растущую коллекцию, внутри она делает артериоскопию, когда ей приходится расширяться.
Я провел некоторое расследование и позже решил написать тестовый код, вот что у меня есть.
Мой тестовый код приведен ниже:
import org.junit.Test;
public class ArrayCopyTest {
@Test
public void testCopy() {
for (int count = 0; count < 3; count++) {
int size = 0x00ffffff;
long start, end;
Integer[] integers = new Integer[size];
Integer[] loopCopy = new Integer[size];
Integer[] systemCopy = new Integer[size];
for (int i = 0; i < size; i++) {
integers[i] = i;
}
start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
loopCopy[i] = integers[i];
}
end = System.currentTimeMillis();
System.out.println("for loop: " + (end - start));
start = System.currentTimeMillis();
System.arraycopy(integers, 0, systemCopy, 0, size);
end = System.currentTimeMillis();
System.out.println("System.arrayCopy: " + (end - start));
}
}
}
Он дает результат, показанный ниже
for loop: 47
System.arrayCopy: 24
for loop: 31
System.arrayCopy: 22
for loop: 36
System.arrayCopy: 22
Итак, Брэгбой прав.
Просто подведем соответствующие комментарии к другому вопросу (помечен как дубликат этого).
Конечно, это просто добавление к новому массиву со всеми записями Другие? Который был бы O (n), где n - количество добавляемых значений.
bragboy отвечает, конечно, но потом я подумал, что единственный способ получить верный ответ - найти исходный код для получения канонического ответа, но это невозможно. Вот объявление для System.arraycopy();
public static native void arraycopy(Object src, int src_position,
Object dst, int dst_position,
int length);
It native
, написанный на языке операционной системы, что означает, что реализация arraycopy()
зависит от платформы.
Итак, в заключение это скорее O (n), но, возможно, нет.
Вот какой-то соответствующий исходный код из OpenJDK 8 (openjdk-8-src-b132-03_mar_2014). Я нашел его с помощью исходного кода Java на родном языке (примечание: инструкции запутаны, я просто искал источник для соответствующих идентификаторов). Я думаю, комментарий капитана Ford правильный; то есть (много) случаев, когда итерация каждого элемента не требуется. Обратите внимание, что не повторение каждого элемента не обязательно означает O (1), это просто означает "быстрее". Я думаю, что, независимо от того, копия массива должна быть в основном O (x), даже если x не является числом элементов в массиве; то есть, однако, вы делаете это, копирование становится дороже с большим количеством элементов в массиве, и если у вас есть очень большой массив, он будет линейно длинным. Предостережение: я не знаю наверняка, что это фактический исходный код для Java, на котором вы работаете; только то, что это единственная реализация, которую я смог найти в источнике OpenJDK 8. Я думаю, что это кросс-платформенная реализация, но я могу ошибаться - я определенно не понял, как создать этот код. См. Также: Различия между Oracle JDK и Open JDK. Ниже приводятся:/openjdk/hotspot/src/share/vm/oops/objArrayKlass.cpp
// Either oop or narrowOop depending on UseCompressedOops.
template <class T> void ObjArrayKlass::do_copy(arrayOop s, T* src,
arrayOop d, T* dst, int length, TRAPS) {
BarrierSet* bs = Universe::heap()->barrier_set();
// For performance reasons, we assume we are that the write barrier we
// are using has optimized modes for arrays of references. At least one
// of the asserts below will fail if this is not the case.
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");
if (s == d) {
// since source and destination are equal we do not need conversion checks.
assert(length > 0, "sanity check");
bs->write_ref_array_pre(dst, length);
Copy::conjoint_oops_atomic(src, dst, length);
} else {
// We have to make sure all elements conform to the destination array
Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
if (stype == bound || stype->is_subtype_of(bound)) {
// elements are guaranteed to be subtypes, so no check necessary
bs->write_ref_array_pre(dst, length);
Copy::conjoint_oops_atomic(src, dst, length);
} else {
// slow case: need individual subtype checks
// note: don't use obj_at_put below because it includes a redundant store check
T* from = src;
T* end = from + length;
for (T* p = dst; from < end; from++, p++) {
// XXX this is going to be slow.
T element = *from;
// even slower now
bool element_is_null = oopDesc::is_null(element);
oop new_val = element_is_null ? oop(NULL)
: oopDesc::decode_heap_oop_not_null(element);
if (element_is_null ||
(new_val->klass())->is_subtype_of(bound)) {
bs->write_ref_field_pre(p, new_val);
*p = *from;
} else {
// We must do a barrier to cover the partial copy.
const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize);
// pointer delta is scaled to number of elements (length field in
// objArrayOop) which we assume is 32 bit.
assert(pd == (size_t)(int)pd, "length field overflow");
bs->write_ref_array((HeapWord*)dst, pd);
THROW(vmSymbols::java_lang_ArrayStoreException());
return;
}
}
}
}
bs->write_ref_array((HeapWord*)dst, length);
}
Я не понимаю, как Каузер отвечает на свой вопрос. Я решил проверить временную сложность алгоритма. Вам нужно сравнить время его работы для входов разных размеров, например:
import org.junit.Test;
public class ArrayCopyTest {
@Test
public void testCopy() {
int size = 5000000;
for (int count = 0; count < 5; count++) {
size = size * 2;
long start, end;
Integer[] integers = new Integer[size];
Integer[] systemCopy = new Integer[size];
start = System.currentTimeMillis();
System.arraycopy(integers, 0, systemCopy, 0, size);
end = System.currentTimeMillis();
System.out.println(end - start);
}
}
}
Вывод:
10
22
42
87
147