Implementasi Visual C ++ std::dequememiliki ukuran blok maksimum yang sangat kecil (~ 16 byte, jika saya ingat dengan benar; mungkin 32), dan karena itu tidak bekerja dengan baik untuk aplikasi yang realistis. A di deque<T>mana sizeof(T) > 8(atau 16? Ini adalah angka kecil) memiliki karakteristik kinerja yang hampir sama dengan a vector<T*>, di mana setiap elemen dialokasikan secara dinamis. Implementasi lain memiliki ukuran blok maksimum yang berbeda, sehingga sulit untuk menulis kode yang memiliki karakteristik kinerja yang relatif sama pada platform yang berbeda deque.
James McNellis
13
Deque bukanlah wadah memori berkelanjutan.
Mohamed El-Nakib
@ravil Tidak, itu adalah duplikatnya, menunjuk ke pertanyaan ini.
1
Sulit dipercaya, sebuah pertanyaan dengan kesalahan faktual yang tidak tetap berada pada keseimbangan 34 suara
underscore_d
2
@underscore_d itulah mengapa ini menjadi pertanyaan. Cerita yang berbeda jika itu adalah sebuah jawaban;)
Assimilater
Jawaban:
115
Elemen dalam dequeyang tidak bersebelahan di memori; vectorelemen dijamin. Jadi, jika Anda perlu berinteraksi dengan pustaka C biasa yang membutuhkan larik yang berdekatan, atau jika Anda peduli (sangat) tentang lokalitas spasial, Anda mungkin lebih suka vector. Selain itu, karena ada beberapa pembukuan tambahan, operasi lain mungkin (sedikit) lebih mahal daripada vectoroperasi yang setara . Di sisi lain, menggunakan banyak / contoh besar dari vectordapat menyebabkan fragmentasi heap yang tidak perlu (memperlambat panggilan kenew ).
Tampaknya tautan ke "di tempat lain" sekarang sudah mati (karena moderasi?).
esilk
37
Untuk mengetahui perbedaannya, seseorang harus mengetahui bagaimana dequepenerapannya secara umum. Memori dialokasikan dalam blok dengan ukuran yang sama, dan mereka dirangkai bersama (sebagai array atau mungkin vektor).
Jadi untuk menemukan elemen ke-n, Anda menemukan blok yang sesuai kemudian mengakses elemen di dalamnya. Ini adalah waktu yang konstan, karena selalu persis 2 pencarian, tetapi itu masih lebih banyak daripada vektor.
vectorjuga berfungsi dengan baik dengan API yang menginginkan buffer berdekatan karena keduanya merupakan C API atau lebih fleksibel dalam mengambil pointer dan panjang. (Dengan demikian Anda dapat memiliki vektor di bawah atau array biasa dan memanggil API dari blok memori Anda).
Dimana dequekeuntungan terbesarnya adalah:
Saat menumbuhkan atau menyusut koleksi dari kedua ujungnya
Saat Anda berurusan dengan ukuran koleksi yang sangat besar.
Saat berhadapan dengan bools dan Anda benar-benar menginginkan bools daripada bitset.
Yang kedua kurang dikenal, tetapi untuk ukuran koleksi yang sangat besar:
Biaya realokasi besar
Overhead karena harus menemukan blok memori yang berdekatan bersifat membatasi, sehingga Anda dapat kehabisan memori lebih cepat.
Ketika saya berurusan dengan koleksi besar di masa lalu dan berpindah dari model yang berdekatan ke model blok, kami dapat menyimpan sekitar 5 kali lebih banyak koleksi sebelum kami kehabisan memori dalam sistem 32-bit. Hal ini sebagian karena, ketika mengalokasikan ulang, sebenarnya diperlukan untuk menyimpan blok lama serta yang baru sebelum menyalin elemen.
Karena itu, Anda bisa mendapatkan masalah dengan std::dequesistem yang menggunakan alokasi memori "optimis". Sementara upayanya untuk meminta ukuran buffer yang besar untuk realokasi a vectormungkin akan ditolak di beberapa titik dengan a bad_alloc, sifat optimis dari pengalokasi kemungkinan akan selalu mengabulkan permintaan untuk buffer yang lebih kecil yang diminta oleh a.deque dan itu mungkin menyebabkan sistem operasi untuk menghentikan proses untuk mencoba memperoleh beberapa memori. Mana pun yang dipilihnya mungkin tidak terlalu menyenangkan.
Solusi dalam kasus seperti itu adalah menyetel tanda tingkat sistem untuk mengganti alokasi optimis (tidak selalu dapat dilakukan) atau mengelola memori secara lebih manual, misalnya menggunakan pengalokasi Anda sendiri yang memeriksa penggunaan memori atau yang serupa. Jelas tidak ideal. (Yang mungkin menjawab pertanyaan Anda tentang memilih vektor ...)
Saya telah menerapkan vektor dan deque beberapa kali. deque jauh lebih rumit dari sudut pandang implementasi. Komplikasi ini diterjemahkan menjadi lebih banyak kode dan kode yang lebih kompleks. Jadi, Anda biasanya akan melihat ukuran kode yang dipukul saat Anda memilih deque daripada vektor. Anda mungkin juga mengalami sedikit kecepatan hit jika kode Anda hanya menggunakan hal-hal yang unggul di vektor (yaitu push_back).
Jika Anda membutuhkan antrian berujung ganda, deque adalah pemenang yang jelas. Tetapi jika Anda melakukan sebagian besar penyisipan dan penghapusan di bagian belakang, vektor akan menjadi pemenang yang jelas. Jika Anda tidak yakin, nyatakan container Anda dengan typedef (agar mudah beralih), dan ukur.
Pertanyaan - apakah panitia telah mempertimbangkan untuk menambahkan gabungan keduanya (katakanlah, "dek") ke C ++? (Yaitu berujung ganda vector.) Saya telah menulis implementasi yang ditautkan di bawah ini dalam jawaban saya . Ini bisa secepat vectortapi lebih banyak diterapkan (misalnya, saat membuat antrian cepat).
pengguna541686
5
std::dequetidak memiliki jaminan memori berkelanjutan - dan seringkali agak lebih lambat untuk akses yang diindeks. Deque biasanya diimplementasikan sebagai "daftar vektor".
Menurut saya "daftar vektor" tidak benar: pemahaman saya adalah bahwa sebagian besar implementasi adalah "vektor penunjuk ke larik", meskipun itu tergantung pada definisi Anda tentang "daftar" (saya membaca "daftar" sebagai "daftar tertaut , "yang tidak akan memenuhi persyaratan kompleksitas.)
James McNellis
2
Menurut http://www.cplusplus.com/reference/stl/deque/ , "tidak seperti vektor, deque tidak dijamin memiliki semua elemennya di lokasi penyimpanan yang berdekatan, sehingga menghilangkan kemungkinan akses yang aman melalui aritmatika penunjuk."
Deque sedikit lebih rumit, sebagian karena tidak selalu memiliki tata letak memori yang berdekatan. Jika Anda membutuhkan fitur itu, sebaiknya jangan gunakan deque.
(Sebelumnya, jawaban saya menunjukkan kurangnya standardisasi (dari sumber yang sama seperti di atas, "deques dapat diimplementasikan oleh perpustakaan tertentu dengan cara yang berbeda"), tetapi itu sebenarnya berlaku untuk hampir semua tipe data perpustakaan standar.)
std::dequetidak kurang standar dari std::vector. Saya tidak percaya persyaratan kompleksitas untuk std::dequedapat dipenuhi dengan penyimpanan yang berdekatan.
Jerry Coffin
1
Mungkin ungkapan saya buruk: meskipun benar bahwa standardisasi tidak menyeluruh, seperti yang saya pahami, vektor distandarisasi menjadi urutan berbelit-belit, dan deques tidak. Tampaknya itulah satu-satunya faktor penentu.
pattivacek
1
@JerryCoffin: Persyaratan kompleksitas mana yang dequetidak dapat dipenuhi dengan penyimpanan yang berdekatan?
pengguna541686
1
@Mehrdad: Sejujurnya, saya tidak ingat apa yang ada dalam pikiran saya. Saya belum melihat bagian standar itu belakangan ini sehingga saya merasa nyaman menyatakan dengan pasti bahwa komentar saya sebelumnya salah, tetapi melihatnya sekarang, saya juga tidak bisa memikirkan bagaimana itu akan benar.
Jerry Coffin
3
@JerryCoffin: Persyaratan kompleksitas sebenarnya sepele: Anda dapat mengalokasikan array besar dan mulai mendorong urutan Anda dari tengah ke luar (saya rasa inilah yang dilakukan implementasi Mehrdad), lalu alokasikan kembali ketika Anda sampai ke akhir. Masalah dengan pendekatan ini adalah bahwa ia tidak memenuhi salah satu persyaratan deque, yaitu bahwa penyisipan di ujung tidak akan membatalkan referensi ke elemen yang ada. Persyaratan ini menyiratkan memori terputus-putus.
Yakov Galka
0
Deque adalah penampung urutan yang memungkinkan akses acak ke elemennya, tetapi tidak dijamin memiliki penyimpanan yang berdekatan.
Pertanyaannya, jika ada yang bisa disaring dari antara kesalahan faktual dan kata-kata yang hilang, adalah mengapa seseorang lebih suka vector. Kita dapat menyimpulkan bahwa mengapa tidak wajar. Mengatakan bahwa Anda lebih suka deque, untuk alasan yang tidak diketahui, dari tes yang tidak ditentukan, bukanlah jawaban.
Di satu sisi, vektor sering kali hanya lebih cepat daripada deque. Jika Anda tidak benar-benar membutuhkan semua fitur deque, gunakan vektor.
Di sisi lain, terkadang Anda memang membutuhkan fitur yang tidak diberikan oleh vektor, dalam hal ini Anda harus menggunakan deque. Misalnya, saya menantang siapa pun untuk mencoba menulis ulang kode ini , tanpa menggunakan deque, dan tanpa mengubah algoritme secara drastis.
Sebenarnya, pada rangkaian push_backdan pop_backoperasi yang sama, deque<int>selalu setidaknya 20% lebih cepat daripada vector<int>pada pengujian saya (gcc dengan O3). Saya rasa itulah mengapa dequepilihan standar untuk hal-hal seperti std::stack...
igel
-1
Perhatikan bahwa memori vektor dialokasikan kembali saat array bertambah. Jika Anda memiliki pointer ke elemen vektor, mereka akan menjadi tidak valid.
Selain itu, jika Anda menghapus elemen, iterator menjadi tidak valid (tetapi tidak "untuk (otomatis ...)").
std::deque
memiliki ukuran blok maksimum yang sangat kecil (~ 16 byte, jika saya ingat dengan benar; mungkin 32), dan karena itu tidak bekerja dengan baik untuk aplikasi yang realistis. A dideque<T>
manasizeof(T) > 8
(atau 16? Ini adalah angka kecil) memiliki karakteristik kinerja yang hampir sama dengan avector<T*>
, di mana setiap elemen dialokasikan secara dinamis. Implementasi lain memiliki ukuran blok maksimum yang berbeda, sehingga sulit untuk menulis kode yang memiliki karakteristik kinerja yang relatif sama pada platform yang berbedadeque
.Jawaban:
Elemen dalam
deque
yang tidak bersebelahan di memori;vector
elemen dijamin. Jadi, jika Anda perlu berinteraksi dengan pustaka C biasa yang membutuhkan larik yang berdekatan, atau jika Anda peduli (sangat) tentang lokalitas spasial, Anda mungkin lebih sukavector
. Selain itu, karena ada beberapa pembukuan tambahan, operasi lain mungkin (sedikit) lebih mahal daripadavector
operasi yang setara . Di sisi lain, menggunakan banyak / contoh besar darivector
dapat menyebabkan fragmentasi heap yang tidak perlu (memperlambat panggilan kenew
).Juga, seperti yang ditunjukkan di tempat lain di StackOverflow , ada lebih banyak diskusi bagus di sini: http://www.gotw.ca/gotw/054.htm .
sumber
Untuk mengetahui perbedaannya, seseorang harus mengetahui bagaimana
deque
penerapannya secara umum. Memori dialokasikan dalam blok dengan ukuran yang sama, dan mereka dirangkai bersama (sebagai array atau mungkin vektor).Jadi untuk menemukan elemen ke-n, Anda menemukan blok yang sesuai kemudian mengakses elemen di dalamnya. Ini adalah waktu yang konstan, karena selalu persis 2 pencarian, tetapi itu masih lebih banyak daripada vektor.
vector
juga berfungsi dengan baik dengan API yang menginginkan buffer berdekatan karena keduanya merupakan C API atau lebih fleksibel dalam mengambil pointer dan panjang. (Dengan demikian Anda dapat memiliki vektor di bawah atau array biasa dan memanggil API dari blok memori Anda).Dimana
deque
keuntungan terbesarnya adalah:Yang kedua kurang dikenal, tetapi untuk ukuran koleksi yang sangat besar:
Ketika saya berurusan dengan koleksi besar di masa lalu dan berpindah dari model yang berdekatan ke model blok, kami dapat menyimpan sekitar 5 kali lebih banyak koleksi sebelum kami kehabisan memori dalam sistem 32-bit. Hal ini sebagian karena, ketika mengalokasikan ulang, sebenarnya diperlukan untuk menyimpan blok lama serta yang baru sebelum menyalin elemen.
Karena itu, Anda bisa mendapatkan masalah dengan
std::deque
sistem yang menggunakan alokasi memori "optimis". Sementara upayanya untuk meminta ukuran buffer yang besar untuk realokasi avector
mungkin akan ditolak di beberapa titik dengan abad_alloc
, sifat optimis dari pengalokasi kemungkinan akan selalu mengabulkan permintaan untuk buffer yang lebih kecil yang diminta oleh a.deque
dan itu mungkin menyebabkan sistem operasi untuk menghentikan proses untuk mencoba memperoleh beberapa memori. Mana pun yang dipilihnya mungkin tidak terlalu menyenangkan.Solusi dalam kasus seperti itu adalah menyetel tanda tingkat sistem untuk mengganti alokasi optimis (tidak selalu dapat dilakukan) atau mengelola memori secara lebih manual, misalnya menggunakan pengalokasi Anda sendiri yang memeriksa penggunaan memori atau yang serupa. Jelas tidak ideal. (Yang mungkin menjawab pertanyaan Anda tentang memilih vektor ...)
sumber
Saya telah menerapkan vektor dan deque beberapa kali. deque jauh lebih rumit dari sudut pandang implementasi. Komplikasi ini diterjemahkan menjadi lebih banyak kode dan kode yang lebih kompleks. Jadi, Anda biasanya akan melihat ukuran kode yang dipukul saat Anda memilih deque daripada vektor. Anda mungkin juga mengalami sedikit kecepatan hit jika kode Anda hanya menggunakan hal-hal yang unggul di vektor (yaitu push_back).
Jika Anda membutuhkan antrian berujung ganda, deque adalah pemenang yang jelas. Tetapi jika Anda melakukan sebagian besar penyisipan dan penghapusan di bagian belakang, vektor akan menjadi pemenang yang jelas. Jika Anda tidak yakin, nyatakan container Anda dengan typedef (agar mudah beralih), dan ukur.
sumber
vector
.) Saya telah menulis implementasi yang ditautkan di bawah ini dalam jawaban saya . Ini bisa secepatvector
tapi lebih banyak diterapkan (misalnya, saat membuat antrian cepat).std::deque
tidak memiliki jaminan memori berkelanjutan - dan seringkali agak lebih lambat untuk akses yang diindeks. Deque biasanya diimplementasikan sebagai "daftar vektor".sumber
Menurut http://www.cplusplus.com/reference/stl/deque/ , "tidak seperti vektor, deque tidak dijamin memiliki semua elemennya di lokasi penyimpanan yang berdekatan, sehingga menghilangkan kemungkinan akses yang aman melalui aritmatika penunjuk."
Deque sedikit lebih rumit, sebagian karena tidak selalu memiliki tata letak memori yang berdekatan. Jika Anda membutuhkan fitur itu, sebaiknya jangan gunakan deque.
(Sebelumnya, jawaban saya menunjukkan kurangnya standardisasi (dari sumber yang sama seperti di atas, "deques dapat diimplementasikan oleh perpustakaan tertentu dengan cara yang berbeda"), tetapi itu sebenarnya berlaku untuk hampir semua tipe data perpustakaan standar.)
sumber
std::deque
tidak kurang standar daristd::vector
. Saya tidak percaya persyaratan kompleksitas untukstd::deque
dapat dipenuhi dengan penyimpanan yang berdekatan.deque
tidak dapat dipenuhi dengan penyimpanan yang berdekatan?deque
, yaitu bahwa penyisipan di ujung tidak akan membatalkan referensi ke elemen yang ada. Persyaratan ini menyiratkan memori terputus-putus.Deque adalah penampung urutan yang memungkinkan akses acak ke elemennya, tetapi tidak dijamin memiliki penyimpanan yang berdekatan.
sumber
Saya pikir itu ide yang bagus untuk menguji kinerja setiap kasus. Dan buatlah keputusan dengan mengandalkan tes ini.
Saya lebih suka
std::deque
daripadastd::vector
di kebanyakan kasus.sumber
vector
. Kita dapat menyimpulkan bahwa mengapa tidak wajar. Mengatakan bahwa Anda lebih sukadeque
, untuk alasan yang tidak diketahui, dari tes yang tidak ditentukan, bukanlah jawaban.Anda tidak akan memilih vektor daripada menghapus menurut hasil tes ini (dengan sumber).
Tentu saja, Anda harus menguji di aplikasi / lingkungan Anda, tetapi secara ringkas:
Beberapa renungan lagi, dan catatan untuk dipertimbangkan circular_buffer.
sumber
Di satu sisi, vektor sering kali hanya lebih cepat daripada deque. Jika Anda tidak benar-benar membutuhkan semua fitur deque, gunakan vektor.
Di sisi lain, terkadang Anda memang membutuhkan fitur yang tidak diberikan oleh vektor, dalam hal ini Anda harus menggunakan deque. Misalnya, saya menantang siapa pun untuk mencoba menulis ulang kode ini , tanpa menggunakan deque, dan tanpa mengubah algoritme secara drastis.
sumber
push_back
danpop_back
operasi yang sama,deque<int>
selalu setidaknya 20% lebih cepat daripadavector<int>
pada pengujian saya (gcc dengan O3). Saya rasa itulah mengapadeque
pilihan standar untuk hal-hal sepertistd::stack
...Perhatikan bahwa memori vektor dialokasikan kembali saat array bertambah. Jika Anda memiliki pointer ke elemen vektor, mereka akan menjadi tidak valid.
Selain itu, jika Anda menghapus elemen, iterator menjadi tidak valid (tetapi tidak "untuk (otomatis ...)").
Edit: ubah 'deque' menjadi 'vector'
sumber