Inkonsistensi dalam Big-O dalam menghapus dari ArrayList vs Tabel Hash?

Saya sedang melihat situs web ini yang mencantumkan kompleksitas Big O untuk berbagai operasi. Untuk Array Dinamis, kompleksitas penghapusannya adalah O(n), sedangkan untuk Tabel Hash adalah O(1).

Untuk Array Dinamis seperti ArrayLists menjadi O(n), itu berarti operasi menghilangkan beberapa nilai dari pusat dan kemudian menggeser setiap indeks ke atas satu untuk menjaga blok data tetap berdekatan. Karena jika kita hanya menghapus nilai yang tersimpan di indeks k dan tidak menggesernya, maka itu adalah O(1).

Namun dalam Tabel Hash dengan probing linier, penghapusan adalah hal yang sama, Anda cukup menjalankan nilai Anda melalui fungsi Hash, masuk ke Array Dinamis yang menyimpan data Anda, dan menghapus nilai yang disimpan di dalamnya.

Jadi mengapa Tabel Hash mendapatkan kredit O(1) sementara Array Dinamis mendapatkan O(n)?


person user1956609    schedule 11.12.2013    source sumber
comment
Mengapa mereka harus 'konsisten'? Sudahkah Anda mempertimbangkan kemungkinan asumsi Anda salah?   -  person user207421    schedule 11.12.2013
comment
Saya sarankan Anda menghapus tag java, dan penyebutan ArrayList, dan menggantinya dengan bahasa-agnostic jika Anda benar-benar menginginkannya, tetapi hanya data -struktur juga baik-baik saja, kecuali pertanyaan ini secara khusus tentang implementasi tabel hash Java API (perhatikan bahwa ini tidak menggunakan pemeriksaan linier, melainkan menggunakan rangkaian terpisah, seperti Stephen menunjukkan).   -  person Bernhard Barker    schedule 11.12.2013


Jawaban (4)


Hal ini dijelaskan di sini. Kuncinya adalah jumlah nilai per Array Dinamis dijaga pada nilai konstan.

Sunting: Seperti yang ditunjukkan Dukeling, jawaban saya menjelaskan mengapa Tabel Hash dengan rangkaian terpisah memiliki kompleksitas penghapusan O(1). Saya harus menambahkan bahwa, di situs web yang Anda lihat, Tabel Hash dikreditkan dengan kompleksitas penghapusan O(1) karena tabel tersebut menganalisis Tabel Hash dengan rangkaian terpisah dan bukan pemeriksaan linier.

person Jelle Fresen    schedule 11.12.2013
comment
Pertanyaannya menanyakan tentang penyelidikan linier, bukan rangkaian terpisah. Yah, saya berasumsi Anda sedang berbicara tentang rangkaian terpisah, jika tidak, apa yang Anda katakan tidak masuk akal. - person Bernhard Barker; 11.12.2013

Inti dari tabel hash adalah tabel tersebut mendekati kasus terbaik, dimana kasus terbaik berarti satu entri per keranjang. Jelasnya, Anda tidak kesulitan menerima bahwa untuk menghapus satu-satunya entri dari ember membutuhkan waktu O(1).

person Marko Topolnik    schedule 11.12.2013
comment
Sulit untuk mengetahui apakah yang Anda bicarakan adalah pemeriksaan linier atau rangkaian terpisah (tampaknya merupakan rangkaian terpisah, namun di sisi lain, masuk akal jika ini juga merupakan pemeriksaan linier). Pertanyaannya menanyakan tentang penyelidikan linier. Saya pikir saya akan menunjukkan hal itu saja. - person Bernhard Barker; 11.12.2013
comment
Saya sedang berbicara tentang keduanya. Karena pemeriksaan linier tidak ada hubungannya dengan HashMap, saya berasumsi OP tidak peduli dengan perbedaan detailnya. - person Marko Topolnik; 11.12.2013

Ketika banyak terjadi konflik hash, tentunya Anda perlu melakukan banyak shifting saat menggunakan linear probing.

Namun kompleksitas tabel hash berada di bawah asumsi Cukup Uniform Hashing, artinya diasumsikan bahwa akan ada konflik hash dalam jumlah minimal.

Ketika ini terjadi, kita hanya perlu menghapus beberapa nilai dan menggeser tidak ada nilai atau sejumlah kecil nilai (pada dasarnya konstan).

person Bernhard Barker    schedule 11.12.2013

Ketika Anda berbicara tentang kompleksitas suatu algoritma, Anda sebenarnya perlu membahas implementasi konkritnya.

  • Tidak ada kelas Java yang disebut "Hash Table" (tentu saja!) atau "HashTable".

  • Ada kelas Java yang disebut HashMap dan Hashtable, dan ini memang memiliki O(1) penghapusan.

Tapi mereka tidak bekerja seperti yang Anda pikirkan (semua?) Tabel hash berfungsi. Secara khusus, HashMap dan Hashtable disusun sebagai array pointer ke "rantai".

Artinya, penghapusan terdiri dari pencarian rantai yang sesuai, dan kemudian menelusuri rantai tersebut untuk menemukan entri yang akan dihapus. Langkah pertama adalah waktu konstan (termasuk waktu menghitung kode hash. Langkah kedua sebanding dengan panjang rantai hash. Namun dengan asumsi fungsi hash baik, rata-rata panjang rantai hash adalah konstanta kecil. Oleh karena itu total waktu untuk penghapusan rata-rata adalah O(1).


Alasan mengapa rantai hash rata-rata pendek adalah karena kelas HashMap dan Hashtable secara otomatis mengubah ukuran array hash utama ketika "faktor beban" (rasio ukuran array terhadap jumlah entri) melebihi nilai yang telah ditentukan. Dengan asumsi bahwa fungsi hash mendistribusikan kunci (sebenarnya) secara merata, Anda akan menemukan bahwa rantai tersebut kira-kira memiliki panjang yang sama. Dengan asumsi bahwa ukuran array sebanding dengan jumlah total entri, faktor muatan aktual akan menjadi rata-rata panjang rantai hash.

Alasan ini gagal jika fungsi hash tidak mendistribusikan kunci secara merata. Hal ini menyebabkan situasi di mana Anda mendapatkan banyak tabrakan hash. Memang benar, perilaku terburuknya adalah ketika semua kunci memiliki nilai hash yang sama, dan semuanya berakhir pada satu rantai hash dengan semua N entri. Dalam hal ini, penghapusan melibatkan pencarian rantai dengan N entri ... dan itu menjadikannya O(N).


Ternyata alasan yang sama dapat diterapkan pada bentuk tabel hash lainnya, termasuk yang entrinya disimpan dalam larik hash itu sendiri, dan tabrakan ditangani dengan pemindaian ulang. (Sekali lagi, "triknya" adalah memperluas tabel hash ketika faktor beban menjadi terlalu tinggi.)

person Stephen C    schedule 11.12.2013
comment
Kelas Java juga tidak boleh berisi spasi, jadi menurut saya OP sebenarnya tidak membicarakan kelas Java, tetapi hanya tabel hash secara umum, dengan probing linier (yang disebutkan secara eksplisit), daripada hanya membuat kesalahan pengetikan, dan tidak mengetahui bahwa kelas Java tidak menggunakan probing linier. - person Bernhard Barker; 11.12.2013