Lebih
Mengapa mulai ArrayList dengan kapasitas awal?
Biasa konstruktor ArrayList
adalah:
ArrayList<?> list = new ArrayList<>();
Tapi ada juga yang overload constructor dengan satu parameter untuk kapasitas awal:
ArrayList<?> list = new ArrayList<>(20);
Mengapa ini berguna untuk membuat sebuah ArrayList
dengan kapasitas awal ketika kita dapat menambahkan untuk itu seperti yang kita tolong?
147
11
Jika anda tahu terlebih dahulu apa ukuran
ArrayList
ini akan terjadi, hal ini lebih efisien untuk menentukan kapasitas awal. Jika anda don't melakukan hal ini, internal array harus berulang kali dialokasikan sebagai daftar tumbuh.Yang lebih besar daftar akhir, semakin banyak waktu yang anda simpan dengan menghindari realokasi.
Yang mengatakan, bahkan tanpa pra-alokasi, memasukkan
n
elemen di bagian belakang sebuahArrayList
dijamin untuk mengambil totalO(n) waktu. Dengan kata lain, menambahkan sebuah elemen yang diamortisasi konstan-waktu operasi. Hal ini dicapai oleh masing-masing memiliki realokasi meningkatkan ukuran dari array secara eksponensial, biasanya dengan faktor
1.5. Dengan pendekatan ini, total jumlah operasi [dapat ditunjukkan untuk menjadi
O(n)`]1.Karena
ArrayList
adalah secara dinamis mengubah ukuran array struktur data, yang berarti hal ini diimplementasikan sebagai array dengan awal (default) ukuran tetap. Ketika hal ini akan diisi, array akan diperpanjang untuk ganda berukuran satu. Operasi ini lebih mahal, sehingga anda ingin sesedikit mungkin.Jadi, jika anda tahu anda terikat atas adalah 20 item, kemudian membuat array dengan panjang awal 20 lebih baik daripada menggunakan default dari, katakanlah, 15 dan kemudian mengubah ukuran ke
15*2 = 30
dan gunakan hanya 20 sementara buang siklus untuk ekspansi.P. S. - Sebagai AmitG mengatakan, perluasan faktor implementasi tertentu (dalam hal ini
(oldCapacity * 3)/2 + 1
)Default ukuran Arraylist adalah 10.
Jadi jika anda akan menambahkan 100 atau lebih catatan, anda dapat melihat overhead memori realokasi.
Jadi jika anda memiliki gagasan tentang jumlah elemen yang akan disimpan dalam Arraylist yang lebih baik untuk membuat Arraylist dengan ukuran yang bukannya mulai dengan 10 dan kemudian akan meningkat.
Saya benar-benar menulis blog post pada topik 2 bulan yang lalu. Artikel ini adalah untuk C#'s
Daftar<T>
tapi Java'sArrayList
sangat mirip implementasi. SejakArrayList
ini diimplementasikan menggunakan dynamic array, meningkatkan ukuran sesuai permintaan. Jadi alasan kapasitas constructor adalah untuk optimalisasi tujuan.Ketika salah satu dari ini resizings operasi terjadi, ArrayList salinan isi dari array ke array baru yang dua kali kapasitas dari yang lama. Operasi ini berjalan di O(n) waktu.
Contoh
Berikut adalah contoh bagaimana
ArrayList
akan meningkat dalam ukuran:Jadi daftar dimulai dengan kapasitas
10
, ketika 11 item ditambahkan itu meningkat50% + 1
ke16
. Pada tanggal 17 itemArrayList
lebih meningkat lagi untuk25
dan sebagainya. Sekarang perhatikan contoh di mana kita're menciptakan sebuah daftar di mana kapasitas yang diinginkan sudah dikenal sebagai1000000
. MenciptakanArrayList
tanpa ukuran konstruktor akan memanggilArrayList.tambahkan
1000000
kali yang memakan waktu O(1) normal atau O(n) di resize.Bandingkan ini dengan menggunakan constructor dan kemudian memanggil
ArrayList.tambahkan
yang dijamin untuk menjalankan di O(1).Jawa vs C#
Jawa adalah seperti di atas, mulai pukul
10
dan meningkatkan masing-masing ukuran di50% + 1
. C# dimulai pada4
dan meningkat jauh lebih agresif, dua kali lipat pada masing-masing ukuran. The1000000
menambahkan contoh di atas untuk C# menggunakan3097084
operasi.Referensi
Pengaturan awal ukuran ArrayList, misalnya untuk
ArrayList<>(100)
, mengurangi jumlah kali re-alokasi memori internal yang telah terjadi.Contoh:
Seperti yang anda lihat dalam contoh di atas - sebuah
ArrayList
dapat diperluas jika perlu. Apa ini doesn't menunjukkan bahwa ukuran Arraylist biasanya ganda (meskipun catatan yang baru ukuran tergantung pada implementasi). Berikut ini dikutip dari Oracle:Jelas, jika anda tidak memiliki ide seperti apa jenis dari jangkauan anda akan memegang, pengaturan size mungkin tidak't menjadi ide yang baik - namun, jika anda memiliki kisaran tertentu dalam pikiran, pengaturan kapasitas awal akan meningkatkan efisiensi memori.
ArrayList dapat mengandung banyak nilai-nilai dan ketika melakukan awal yang besar insersi anda dapat memberitahu ArrayList untuk mengalokasikan penyimpanan yang lebih besar untuk mulai dengan tidak membuang-buang siklus CPU ketika mencoba untuk mengalokasikan lebih banyak ruang untuk item berikutnya. Dengan demikian untuk mengalokasikan beberapa ruang di awal lebih effiecient.
Hal ini untuk menghindari kemungkinan upaya untuk realokasi untuk setiap objek tunggal.
secara internal
new Object[]
dibuat.JVM perlu upaya untuk membuat
new Object[]
ketika anda menambahkan elemen dalam arraylist. Jika anda don't memiliki kode di atas(setiap algo yang anda pikirkan) untuk realokasi maka setiap kali ketika anda memanggilarraylist.add()
kemudiannew Object[]
harus dibuat yang sia-sia dan kita kehilangan waktu untuk meningkatkan ukuran dengan 1 untuk setiap objek yang akan ditambahkan. Jadi lebih baik untuk meningkatkan ukuranObject[]
dengan rumus berikut.(JSL telah digunakan forcasting rumus yang diberikan di bawah ini untuk tumbuh secara dinamis arraylist bukannya tumbuh sebesar 1 setiap waktu. Karena untuk menumbuhkan dibutuhkan upaya oleh JVM)
I'd mengatakan optimasi. ArrayList tanpa kapasitas awal akan memiliki ~10 baris kosong dan akan memperluas ketika anda melakukan add.
Untuk memiliki daftar dengan persis jumlah item yang anda butuhkan untuk memanggil trimToSize()
Saya pikir masing-masing ArrayList dibuat dengan init nilai kapasitas dari "10". Jadi, jika anda membuat ArrayList tanpa pengaturan kapasitas di dalam constructor ini akan dibuat dengan nilai default.
Sesuai pengalaman saya dengan
ArrayList
, memberikan kapasitas awal adalah cara yang bagus untuk menghindari realokasi biaya. Tapi ini beruang peringatan. Semua saran yang disebutkan di atas mengatakan bahwa salah satu harus menyediakan kapasitas awal hanya ketika perkiraan kasar dari jumlah unsur-unsur yang diketahui. Tetapi ketika kita mencoba untuk memberikan kapasitas awal tanpa ide, jumlah memori yang dilindungi dan yang tidak terpakai akan menjadi sia-sia seperti itu mungkin tidak akan pernah diperlukan sekali daftar ini diisi dengan jumlah yang diperlukan dari unsur-unsur. Apa yang saya katakan adalah, kita dapat pragmatis pada awal sementara mengalokasikan kapasitas, dan kemudian menemukan cara cerdas untuk mengetahui diperlukan minimal kapasitas pada saat runtime. ArrayList menyediakan sebuah metode yang disebutensureCapacity(int murah untuk kontainer ukuran)
. Tapi kemudian, satu telah menemukan cara cerdas...Saya telah diuji ArrayList dengan dan tanpa initialCapacity dan saya mendapat hasil mengejutkan
Ketika saya set LOOP_NUMBER 100.000 atau kurang hasilnya adalah bahwa pengaturan initialCapacity lebih efisien.
Tapi ketika saya set LOOP_NUMBER 1.000.000 hasil perubahan:
Akhirnya, saya tidak't tahu bagaimana cara kerjanya?!
Contoh kode:
Saya telah diuji pada windows8.1 dan jdk1.7.0_80