Mengapa saya lebih suka menggunakan vektor daripada deque

87

Sejak

  1. keduanya adalah wadah memori yang berdekatan;
  2. Dari segi fitur, deque memiliki hampir semua yang dimiliki vektor tetapi lebih, karena lebih efisien untuk dimasukkan di depan.

Mengapa whould orang lebih memilih std::vectoruntuk std::deque?

Leon
sumber
2
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 ).

Juga, seperti yang ditunjukkan di tempat lain di StackOverflow , ada lebih banyak diskusi bagus di sini: http://www.gotw.ca/gotw/054.htm .

phooji
sumber
3
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:

  1. Saat menumbuhkan atau menyusut koleksi dari kedua ujungnya
  2. Saat Anda berurusan dengan ukuran koleksi yang sangat besar.
  3. Saat berhadapan dengan bools dan Anda benar-benar menginginkan bools daripada bitset.

Yang kedua kurang dikenal, tetapi untuk ukuran koleksi yang sangat besar:

  1. Biaya realokasi besar
  2. 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 ...)

CashCow
sumber
30

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.

Howard Hinnant
sumber
3
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".

Erik
sumber
14
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.)

pattivacek
sumber
5
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.

Sean
sumber
0

Saya pikir itu ide yang bagus untuk menguji kinerja setiap kasus. Dan buatlah keputusan dengan mengandalkan tes ini.

Saya lebih suka std::dequedaripada std::vectordi kebanyakan kasus.

George Gaál
sumber
1
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.
underscore_d
0

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.

BenGoldberg
sumber
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 ...)").

Edit: ubah 'deque' menjadi 'vector'

Pierre
sumber
-1: Sisipkan dan hapus di awal atau akhir TIDAK membatalkan referensi dan penunjuk ke elemen lain. (Meskipun memasukkan dan menghapus di tengah)
Sjoerd
@Sjoerd Saya mengubahnya menjadi 'vektor'.
Pierre