Bagaimana cara menghitung waktu linear terburuk?

8

Pertanyaan ini dan pertanyaan ini membuat saya berpikir sedikit. Untuk menyortir array panjangndengan elemen unik di , kita harus dapat menyimpan jumlah nilai dalam array. Ada beberapa saran, tapi saya sedang mencari cara untuk melakukan ini dalam kasus linear terburuk. Lebih spesifik:kHAI(n+kcatatank)

Mengingat daftar dari unsur dengan unsur yang berbeda, menentukan daftar tupel dari semua elemen yang unik sehingga adalah hitungan elemen di .SEBUAHnkU={(xsaya,csaya)}kxsayaSEBUAHcixiA

Berikut adalah beberapa (gagal) ide yang saya miliki dan telah disarankan:

  1. Balanced Binary Search Tree - Dengan ini akan membutuhkan untuk memasukkan ke dalam pohon dan meningkatkan nilai. Setelah memasukkan kita bisa melakukan traversal pohon di . Jadi, total waktu keluar ke yang terlalu lambat.O(logk)O(k)O(nlogk)
  2. Hash Map - Dengan ini kita bisa mendapatkan sisipan yang diharapkan dan dengan demikian perkiraan waktu. Namun, ini masih bukan kasus terburuk.O(1) O(n) O(n)
  3. Mengosongkan ruang Pemetaan - Cari minimum dan elemen maksimum di . Mengalokasikan (tapi jangan tidak menginisialisasi) cukup memori untuk menutupi kisaran ini. Gunakan memori ini pada dasarnya sebagai peta hash dan sertakan hash acak sehingga kami tidak mencoba mengakses memori yang rusak. Strategi ini menghadirkan masalah. (1) Ini probabilistik dengan kemungkinan kegagalan yang sangat sangat sangat rendah, tetapi masih belum dijamin. Menggunakan memori seperti ini membatasi kita pada batasan floating-point atau integer.A
  4. Array Asosiatif - Ada banyak array asosiatif lainnya yang dapat digunakan, mirip dengan peta hash dan BST, tetapi saya tidak menemukan yang cocok dengan batasan ini.

Mungkin ada beberapa metode yang jelas saya lewatkan, tetapi saya juga berpikir itu bisa berpotensi tidak mungkin. Apa yang kamu pikirkan?

ryan
sumber
3
Ini tidak dapat dilakukan dalam model perbandingan karena masalah perbedaan elemen memiliki batas bawahΩ(nlogn)kompleksitas pohon keputusan.
John L.
@ Apass. Jack, oh benar itu benar. Pengurangan sepele yang tidak saya pertimbangkan. Jika Anda menuliskannya sebagai jawaban singkat, saya akan menerimanya.
ryan
Mengapa HashMap tidak dijamin diamortisasi O (n) ?
javadba
1
@javadba Misalnya, anggap semua elemen di hash dengan nilai yang sama.
John L.
Ah ok jadi kalau itu hashing yang tidak sempurna.
javadba

Jawaban:

6

Ini pertanyaan yang bagus.

Dalam model perbandingan atau, yang lebih umum, model pohon keputusan aljabar, masalah perbedaan elemen memiliki batas yang lebih rendah. Θ(ncatatann)kompleksitas waktu dalam kasus terburuk seperti yang dikatakan dalam artikel Wikipedia ini . Jadi tidak ada algoritma untuk menghitung elemen yang berbeda dalam waktu linier dalam kasus terburuk, bahkan tanpa menghitung duplikat.

Namun, tidak jelas apakah itu dapat dilakukan dalam model komputasi lain. Tampaknya tidak mungkin dalam model komputasi deterministik yang masuk akal.

John L.
sumber
Apakah ini benar-benar contoh masalah perbedaan elemen? Hanya menghasilkan tupel tidak memerlukan pemeriksaan untuk perbedaan. Bukan tidak setuju, hanya ingin tahu.
mascoj
2
Apa yang saya katakan adalah, jika Anda dapat menghasilkan tupel elemen yang berbeda, maka Anda juga dapat menyelesaikan masalah perbedaan elemen dengan memeriksa apakah ukuran tuple tersebut n.
John L.
Panggilan yang bagus. Terima kasih
mascoj
1

Ada algoritma acak yang waktu berjalannya diharapkan HAI(n); atau di mana probabilitas bahwa waktu berjalan lebih lama daricn secara eksponensial kecil c.

Secara khusus, secara acak memilih fungsi hash 2-universal, kemudian menggunakannya untuk hash semua elemen array. Ini mencapai waktu berjalan yang dinyatakan, jika Anda memilih panjang output hash 2-universal dengan tepat.

Sebagai contoh lain, Anda dapat membangun algoritma acak yang waktu menjalankannya paling buruk HAI(n) (Selalu berjalan dalam waktu linier, tidak peduli apa) dan memiliki kemungkinan kesalahan paling banyak 1/2100. (Bagaimana? Jalankan algoritma di atas, dan hentikan jika berjalan lebih lama daricn langkah-langkah untuk beberapa dipilih dengan tepat c.) Dalam praktiknya, itu cukup baik, karena kemungkinan komputer Anda mengeluarkan jawaban yang salah karena sinar kosmik sudah jauh lebih tinggi daripada 1/2100.

DW
sumber
1

Pendekatan Anda 3 dapat dibuat aman menggunakan solusi untuk latihan 2.12 dari Aho, Hopcroft, dan Ullman (1974) Desain dan Analisis Algoritma Komputer seperti yang dijelaskan, misalnya, dalam Menggunakan memori yang tidak diinisialisasi untuk kesenangan dan keuntungan .

Pada dasarnya, selain array N elemen Anda dengan jumlah Anda memiliki dua array elemen N dan satu jumlah tambahan untuk membuat set jarang yang menunjukkan jumlah mana yang valid.

Dalam pseudocode mirip-C:

uint* a = malloc(n);
uint* b = malloc(n);
uint* c = malloc(n);
uint len = 0;

get_count(uint x) {
    uint idx = a[x];
    return idx >= 0 && idx < len && b[idx] == x ? c[idx] : 0;
}

increment_count(uint x) {
    uint idx = a[x];
    if (idx < 0 || idx >= len || b[idx] != x) {
        idx = len;
        len++;
        a[x] = idx;
        b[idx] = x;
        c[idx] = 0;
    }
    c[idx]++;
}

Implementasi praktis dari set jarang dibahas dalam jawaban StackOverflow ini .

Peter Taylor
sumber
PS cdapat diindeks pada xatau idx, tapi saya menggunakan idxuntuk cache lokalitas yang lebih baik.
Peter Taylor
Saya suka jawabannya, tetapi saya bingung tentang apa yang membuat ini aman. Sementara, sepenuhnya mustahil, Anda tidak dapat mengakses sel memori, yang oleh beberapa keajaiban memiliki entri "valid" di dalamnya meskipun tidak pernah diletakkan di sana. Jika Anda beruntung dengan malloc?
ryan
1
Solusi ini hanya berfungsi jika Anda memiliki memori yang cukup besar: jika semua elemen array berada dalam jangkauan 1 ..kamu, maka Anda membutuhkan memori ukuran setidaknya kamu. Dalam praktiknya ini sangat membatasi. Cara kami membuat ruang alamat virtual besar dalam praktiknya adalah menggunakan tabel halaman, yang merupakan struktur data berbasis pohon; perangkat keras secara tak terlihat mengikuti tabel halaman untuk kita. Akibatnya, sementara kami menganggap akses memori sebagai pengambilanHAI(1)waktu, jika Anda bekerja di ruang alamat memori yang besar, setiap akses memori sebenarnya membutuhkan waktu logaritmik (untuk melintasi struktur struktur tabel tabel).
DW
@ryan, lihat research.swtch.com/sparse untuk mengetahui apa yang membuatnya aman. Ini jelas trik yang sangat pintar.
DW
@ DW, 3kamu+1, tapi jika kamusangat besar maka Anda bisa melakukan ini pada beberapa level, menggunakan array {a,b,c,len}struct untuk cbukan array counts. Misalnya, jika Anda menggunakan radix 512 sehingga masing-masing array cocok dalam satu halaman (dengan pointer 8-byte), maka Anda dapat naik kekamu=5123=134217728 paling banyak menggunakan (3×512+1)(1+2k) memori dimana kadalah jumlah elemen berbeda yang terlihat.
Peter Taylor