Ini adalah pertanyaan wawancara google:
Ada sekitar seribu nomor telepon yang harus disimpan masing-masing memiliki 10 digit. Anda dapat mengasumsikan 5 digit pertama dari masing-masing angka sama di ribuan angka. Anda harus melakukan operasi berikut: a. Cari jika ada nomor tertentu. b. Cetak semua nomor
Apa cara hemat ruang yang paling efisien untuk melakukan ini?
Saya menjawab tabel hash dan kemudian pengkodean huffman tetapi pewawancara saya mengatakan saya tidak menuju ke arah yang benar. Tolong bantu saya di sini.
Bisakah menggunakan bantuan sufiks trie?
Idealnya, penyimpanan 1000 nomor membutuhkan 4 byte per nomor sehingga dalam semua itu dibutuhkan 4000 byte untuk menyimpan 1000 nomor. Secara kuantitatif, saya ingin mengurangi penyimpanan menjadi <4000 byte, inilah yang dijelaskan pewawancara saya kepada saya.
sumber
Jawaban:
Berikut perbaikan dari jawaban aix . Pertimbangkan untuk menggunakan tiga "lapisan" untuk struktur data: yang pertama adalah konstanta untuk lima digit pertama (17 bit); jadi mulai saat ini, setiap nomor telepon hanya memiliki sisa lima digit. Kami melihat lima digit yang tersisa ini sebagai bilangan bulat biner 17-bit dan menyimpan k dari bit tersebut menggunakan satu metode dan 17 - k = m dengan metode yang berbeda, menentukan k pada akhirnya untuk meminimalkan ruang yang diperlukan.
Pertama-tama kami mengurutkan nomor telepon (semuanya dikurangi menjadi 5 digit desimal). Kemudian kita hitung ada berapa nomor telepon yang mana bilangan biner yang terdiri dari m bit pertama semuanya 0, untuk berapa nomor telepon m bit pertama paling banyak 0 ... 01, untuk berapa nomor telepon m pertama bit paling banyak 0 ... 10, dan sebagainya, hingga hitungan nomor telepon yang m bit pertamanya adalah 1 ... 11 - hitungan terakhir ini adalah 1000 (desimal). Ada 2 ^ m hitungan seperti itu dan setiap hitungan maksimal 1000. Jika kita menghilangkan yang terakhir (karena kita tahu itu 1000), kita dapat menyimpan semua angka ini dalam blok yang berdekatan (2 ^ m - 1) * 10 bit. (10 bit cukup untuk menyimpan angka kurang dari 1024.)
K bit terakhir dari semua nomor telepon (dikurangi) disimpan berdekatan dalam memori; jadi jika k adalah, katakanlah, 7, maka 7 bit pertama dari blok memori ini (bit 0 hingga 6) sesuai dengan 7 bit terakhir dari nomor telepon pertama (dikurangi), bit 7 hingga 13 sesuai dengan 7 bit terakhir nomor telepon kedua (dikurangi), dan sebagainya. Ini membutuhkan 1000 * k bit dengan total 17 + (2 ^ (17 - k ) - 1) * 10 + 1000 * k , yang mencapai minimum 11287 untuk k = 10. Jadi kita bisa menyimpan semua nomor telepon di langit-langit ( 11287/8) = 1411 byte.
Ruang tambahan dapat dihemat dengan mengamati bahwa tidak ada bilangan kita yang dapat dimulai dengan misalnya 1111111 (biner), karena bilangan terendah yang dimulai dengan itu adalah 130048 dan kita hanya memiliki lima digit desimal. Hal ini memungkinkan kita untuk memotong beberapa entri dari blok memori pertama: alih-alih 2 ^ m - 1 hitungan, kita hanya membutuhkan ceil (99999/2 ^ k ). Artinya rumusnya menjadi
17 + ceil (99999/2 ^ k ) * 10 + 1000 * k
yang luar biasa mencapai minimum 10997 untuk keduanya k = 9 dan k = 10, atau ceil (10997/8) = 1375 byte.
Jika kita ingin mengetahui apakah nomor telepon tertentu ada di himpunan kita, pertama kita periksa apakah lima digit biner pertama cocok dengan lima digit yang telah kita simpan. Kemudian kita membagi lima digit yang tersisa menjadi m = 7 bit teratas (yaitu, katakanlah, angka m- bit M ) dan k = 10 bit yang lebih rendah (angka K ). Sekarang kita menemukan nomor a [M-1] dari nomor telepon yang dikurangi yang m digit pertamanya paling banyak M - 1, dan nomor a [M] dari nomor telepon yang dikurangi yang m digit pertamanya paling banyak M , keduanya dari blok bit pertama. Kami sekarang memeriksa antara a [M-1] dan a [M] th urutan k bit pada blok kedua memori untuk melihat apakah kita menemukan K ; dalam kasus terburuk ada 1000 urutan seperti itu, jadi jika kita menggunakan pencarian biner kita dapat menyelesaikan operasi O (log 1000).
Pseudocode untuk mencetak semua 1000 nomor berikut, di mana saya mengakses K 'th k -bit masuknya blok pertama dari memori sebagai sebuah [K] dan M ' th m entri-bit dari blok kedua dari memori b [M] (keduanya akan membutuhkan sedikit operasi yang membosankan untuk ditulis). Lima digit pertama ada di bilangan c .
Mungkin ada yang salah dengan kasus batas untuk K = ceil (99999/2 ^ k ), tapi itu cukup mudah untuk diperbaiki.
Akhirnya, dari sudut pandang entropi, tidak mungkin untuk menyimpan bagian dari 10 ^ 3 bilangan bulat positif yang semuanya kurang dari 10 ^ 5 dalam kurang dari ceil (log [2] (binomial (10 ^ 5, 10 ^ 3)) ) = 8073. Termasuk 17 yang kita butuhkan untuk 5 digit pertama, masih ada selisih 10997 - 8090 = 2907 bit. Merupakan tantangan yang menarik untuk melihat apakah ada solusi yang lebih baik di mana Anda masih dapat mengakses nomor dengan relatif efisien!
sumber
Berikut ini, saya memperlakukan angka sebagai variabel integer (sebagai lawan string):
Ringkasnya: 17 bit pertama adalah awalan umum, 1000 grup berikutnya yang terdiri dari 17 bit adalah lima digit terakhir dari setiap nomor yang disimpan dalam urutan menaik.
Secara total kami melihat 2128 byte untuk 1000 nomor, atau 17.017 bit per 10 digit nomor telepon.
Pencarian adalah
O(log n)
(pencarian biner) dan enumerasi lengkap adalahO(n)
.sumber
k
tidak relevan.http://en.wikipedia.org/wiki/Acyclic_deterministic_finite_automaton
Saya pernah melakukan wawancara dimana mereka menanyakan tentang struktur data. Saya lupa "Array".
sumber
Saya mungkin akan mempertimbangkan untuk menggunakan beberapa versi terkompresi dari Trie (mungkin DAWG seperti yang disarankan oleh @Misha).
Itu secara otomatis akan memanfaatkan fakta bahwa mereka semua memiliki awalan yang sama.
Pencarian akan dilakukan dalam waktu konstan, dan pencetakan akan dilakukan dalam waktu linier.
sumber
Saya pernah mendengar masalah ini sebelumnya (tetapi tanpa asumsi 5 digit pertama sama), dan cara termudah untuk melakukannya adalah Pengkodean Beras :
1) Karena urutannya tidak masalah, kita dapat mengurutkannya, dan hanya menyimpan perbedaan antara nilai yang berurutan. Dalam kasus kami, perbedaan rata-rata adalah 100.000 / 1000 = 100
2) Menyandikan perbedaan menggunakan kode Beras (basis 128 atau 64) atau bahkan kode Golomb (basis 100).
EDIT: Perkiraan untuk pengkodean Beras dengan basis 128 (bukan karena akan memberikan hasil terbaik, tetapi karena lebih mudah untuk dihitung):
Kami akan menyimpan nilai pertama apa adanya (32 bit).
999 nilai lainnya adalah perbedaan (kami berharap nilainya kecil, rata-rata 100) akan berisi:
nilai unary
value / 128
(jumlah variabel bit + 1 bit sebagai terminator)nilai biner untuk
value % 128
(7 bit)Kita harus memperkirakan entah bagaimana batasnya (sebut saja
VBL
) untuk jumlah bit variabel:batas bawah: anggap kita beruntung, dan tidak ada perbedaan yang lebih besar dari basis kita (128 dalam kasus ini). ini berarti memberikan 0 bit tambahan.
batas tinggi: karena semua perbedaan yang lebih kecil dari basis akan dikodekan dalam bagian bilangan biner, jumlah maksimum yang perlu kita enkode dalam unary adalah 100000/128 = 781.25 (bahkan lebih kecil lagi, karena kita tidak mengharapkan sebagian besar perbedaan menjadi nol ).
Jadi, hasilnya adalah 32 + 999 * (1 + 7) + variabel (0..782) bits = 1003 + variabel (0..98) byte.
sumber
32 + 999 * (1 + 7 + variable(0..782))
potongan - potongan? Masing-masing dari 999 angka membutuhkan representasivalue / 128
.Ini adalah masalah yang diketahui dengan baik dari Bentley's Programming Pearls.
Solusi: Hapus lima digit pertama dari angka-angka tersebut karena sama untuk setiap angka. Kemudian gunakan operasi bitwise untuk mewakili 9999 kemungkinan nilai yang tersisa. Anda hanya membutuhkan 2 ^ 17 Bit untuk mewakili angka-angka tersebut. Setiap Bit mewakili angka. Jika bit disetel, nomornya ada di buku telepon.
Untuk mencetak semua angka, cukup cetak semua angka yang bitnya diset dengan awalan. Untuk mencari angka tertentu, lakukan aritmatika bit yang diperlukan untuk memeriksa representasi bitwise dari angka tersebut.
Anda dapat mencari angka dalam O (1) dan efisiensi ruang maksimal karena representasi bit.
HTH Chris.
sumber
Penyimpanan tetap 1073 byte untuk 1.000 nomor:
Format dasar metode penyimpanan ini adalah menyimpan 5 digit pertama, hitungan untuk setiap grup, dan offset untuk setiap angka di setiap grup.
Awalan: Awalan
5 digit kami menempati 17 bit pertama .
Pengelompokan:
Selanjutnya, kita perlu mencari pengelompokan ukuran yang baik untuk angka. Mari kita coba memiliki sekitar 1 nomor per kelompok. Karena kita tahu ada sekitar 1000 nomor untuk disimpan, kita membagi 99.999 menjadi sekitar 1000 bagian. Jika kita memilih ukuran grup sebagai 100, akan ada bit yang terbuang, jadi mari kita coba ukuran grup 128, yang dapat direpresentasikan dengan 7 bit. Ini memberi kita 782 grup untuk dikerjakan.
Hitungan:
Selanjutnya, untuk masing-masing dari 782 grup, kita perlu menyimpan jumlah entri di setiap grup. Hitungan 7-bit untuk setiap grup akan menghasilkan
7*782=5,474 bits
, yang sangat tidak efisien karena jumlah rata-rata yang diwakili adalah sekitar 1 karena cara kami memilih grup kami.Jadi, sebagai gantinya kita memiliki jumlah ukuran variabel dengan 1 untuk setiap nomor dalam kelompok diikuti oleh 0. Jadi, jika kita memiliki
x
angka dalam kelompok, kita akanx 1's
diikuti oleh a0
untuk mewakili hitungan. Misalnya, jika kita memiliki 5 angka dalam satu grup, hitungannya akan diwakili111110
. Dengan metode ini, jika ada 1.000 bilangan kita berakhir dengan 1000 1 dan 782 0 dengan total 1000 + 782 = 1.782 bit untuk hitungan .Offset:
Terakhir, format setiap angka hanya akan menjadi offset 7-bit untuk setiap grup. Misalnya, jika 00000 dan 00001 adalah satu-satunya bilangan dalam grup 0-127, bit untuk grup itu adalah
110 0000000 0000001
. Dengan asumsi 1.000 angka, akan ada 7.000 bit untuk offset .Jadi penghitungan akhir kita dengan asumsi 1.000 angka adalah sebagai berikut:
Sekarang, mari kita periksa apakah pemilihan ukuran grup kami dengan membulatkan ke 128 bit adalah pilihan terbaik untuk ukuran grup. Memilih
x
jumlah bit untuk mewakili setiap grup, rumus ukurannya adalah:Meminimalkan persamaan ini untuk nilai integer dari
x
memberix=6
, yang menghasilkan 8580 bit = 1073 byte . Jadi, penyimpanan ideal kami adalah sebagai berikut:Penyimpanan total:
1017 (prefix plus 1's) + 1563 (0's in count) + 6*1000 (offsets) = 8,580 bits = 1,073 bytes
sumber
Mengambil ini sebagai masalah teoritis murni dan meninggalkan asas implementasi, satu-satunya cara paling efisien adalah dengan hanya mengindeks semua set yang mungkin dari 10.000 digit terakhir dalam tabel pengindeksan raksasa. Dengan asumsi Anda memiliki tepat 1000 angka, Anda akan membutuhkan lebih dari 8000 bit untuk mengidentifikasi set saat ini secara unik. Tidak ada kemungkinan kompresi yang lebih besar, karena Anda akan memiliki dua set yang diidentifikasi dengan status yang sama.
Masalah dengan ini adalah, bahwa Anda harus mewakili masing-masing dari 2 ^ 8000 set dalam program Anda sebagai lut, dan bahkan google tidak akan mampu melakukan ini dari jarak jauh.
Pencarian akan menjadi O (1), mencetak semua nomor O (n). Penyisipan akan menjadi O (2 ^ 8000) yang secara teori adalah O (1), tetapi dalam praktiknya tidak dapat digunakan.
Dalam sebuah wawancara saya hanya akan memberikan jawaban ini, jika saya yakin, bahwa perusahaan sedang mencari seseorang yang mampu banyak berpikir di luar kotak. Jika tidak, ini mungkin membuat Anda terlihat seperti ahli teori tanpa masalah dunia nyata.
EDIT : Ok, ini salah satu "implementasi".
Langkah-langkah untuk membangun implementasi:
Ini bukan program, tetapi semacam program meta, yang akan membangun LUT raksasa yang sekarang dapat digunakan dalam program. Hal konstan dari program biasanya tidak dihitung saat menghitung efisiensi ruang, jadi kami tidak peduli dengan larik ini, saat melakukan penghitungan akhir.
Berikut cara menggunakan LUT ini:
Artinya untuk penyimpanan kita hanya membutuhkan 8091 bits, yang telah kita buktikan disini sebagai encoding yang optimal. Namun menemukan bongkahan yang benar membutuhkan O (100000 * (100 000 pilih 1000)), yang menurut aturan matematika adalah O (1), tetapi dalam praktiknya akan selalu memakan waktu lebih lama daripada waktu alam semesta.
Pencariannya sederhana:
Mencetak semua angka juga sederhana (dan membutuhkan O (100000) = O (1) sebenarnya, karena Anda selalu harus memeriksa semua bit dari potongan saat ini, jadi saya salah menghitung ini di atas).
Saya tidak akan menyebut ini sebagai "implementasi", karena mengabaikan batasan secara terang-terangan (ukuran alam semesta dan waktu alam semesta ini hidup atau bumi ini akan ada). Namun secara teori ini adalah solusi optimal. Untuk masalah yang lebih kecil, ini sebenarnya bisa dilakukan, dan terkadang akan dilakukan. Misalnya jaringan pengurutan adalah contoh untuk cara pengkodean ini, dan dapat digunakan sebagai langkah terakhir dalam algoritma pengurutan rekursif, untuk mendapatkan percepatan yang besar.
sumber
Ini sama dengan menyimpan seribu bilangan bulat non-negatif masing-masing kurang dari 100.000. Kita dapat menggunakan sesuatu seperti pengkodean aritmatika untuk melakukan ini.
Akhirnya, nomor-nomor itu akan disimpan dalam daftar yang diurutkan. Saya perhatikan bahwa perbedaan yang diharapkan antara nomor yang berdekatan dalam daftar adalah 100.000 / 1000 = 100, yang dapat direpresentasikan dalam 7 bit. Ada juga banyak kasus di mana diperlukan lebih dari 7 bit. Cara sederhana untuk merepresentasikan kasus yang kurang umum ini adalah dengan mengadopsi skema utf-8 di mana satu byte mewakili integer 7-bit kecuali bit pertama disetel, dalam hal ini byte berikutnya dibaca untuk menghasilkan integer 14-bit, kecuali -nya bit pertama diatur, dalam hal byte berikutnya adalah membaca untuk mewakili bilangan bulat 21-bit.
Jadi setidaknya setengah dari perbedaan antara bilangan bulat berurutan dapat direpresentasikan dengan satu byte, dan hampir semua sisanya memerlukan dua byte. Beberapa angka, dipisahkan oleh perbedaan yang lebih besar dari 16.384, akan membutuhkan tiga byte, tetapi tidak boleh lebih dari 61. Penyimpanan rata-rata kemudian akan menjadi sekitar 12 bit per nomor, atau sedikit kurang, atau paling banyak 1500 byte.
Kelemahan dari pendekatan ini adalah memeriksa keberadaan sebuah bilangan sekarang adalah O (n). Namun, tidak ada persyaratan kompleksitas waktu yang ditentukan.
Setelah menulis, saya perhatikan ruslik sudah menyarankan perbedaan metode di atas, satu-satunya perbedaan adalah skema pengkodean. Milik saya kemungkinan lebih sederhana tetapi kurang efisien.
sumber
Hanya untuk menanyakan dengan cepat alasan apa pun yang kami tidak ingin mengubah angka menjadi basis 36. Ini mungkin tidak menghemat banyak ruang tetapi pasti akan menghemat waktu dalam pencarian karena u akan melihat jauh kurang dari 10 digit. Atau saya akan membaginya menjadi beberapa file tergantung pada masing-masing kelompok. jadi saya akan memberi nama file (111) -222.txt dan kemudian saya hanya akan menyimpan nomor yang sesuai dengan grup itu di sana dan kemudian membuatnya dapat dicari dalam urutan numerik dengan cara ini saya selalu dapat memeriksa untuk melihat apakah file tersebut keluar. sebelum saya melakukan pencarian yang lebih besar. atau agar benar saya akan menjalankan pencarian biner satu untuk file untuk melihat apakah itu keluar. dan pencarian bonary lain pada konten file
sumber
Mengapa tidak tetap sederhana? Gunakan array struct.
Jadi kita bisa menyimpan 5 digit pertama sebagai konstanta, jadi lupakan itu untuk saat ini.
65535 adalah yang paling banyak yang dapat disimpan dalam nomor 16-bit, dan jumlah maksimum yang dapat kita miliki adalah 99999, yang sesuai dengan nomor bit ke-17 dengan jumlah maksimum 131071.
Menggunakan tipe data 32-bit adalah pemborosan karena kita hanya membutuhkan 1 bit dari 16-bit ekstra itu ... oleh karena itu, kita dapat mendefinisikan struktur yang memiliki boolean (atau karakter) dan bilangan 16-bit ..
Dengan asumsi C / C ++
Struct ini hanya membutuhkan 3-byte, dan kita membutuhkan array 1000, jadi total 3000 byte. Kami telah mengurangi total ruang sebesar 25%!
Sejauh menyimpan angka, kita bisa melakukan matematika bitwise sederhana
Dan kebalikannya
Untuk mencetak semuanya, kita dapat menggunakan loop sederhana di atas array. Mengambil nomor tertentu tentu saja terjadi dalam waktu konstan, karena ini adalah larik.
Untuk mencari nomor, kita menginginkan array yang diurutkan. Jadi, ketika nomor disimpan, urutkan array (saya akan memilih jenis gabungan secara pribadi, O (nlogn)). Sekarang untuk mencari, saya akan menggunakan pendekatan semacam gabungan. Pisahkan array, dan lihat di antara nomor mana kita berada. Kemudian panggil fungsi hanya pada larik itu. Lakukan ini secara berulang hingga Anda memiliki kecocokan dan mengembalikan indeks, jika tidak, indeks tidak ada dan mencetak kode kesalahan. Pencarian ini akan cukup cepat, dan kasus terburuk masih lebih baik daripada O (nlogn) karena ini benar-benar akan dieksekusi dalam waktu yang lebih singkat daripada jenis gabungan (hanya mengulangi 1 sisi pemisahan setiap kali, bukan kedua sisi :)), yang mana adalah O (nlogn).
sumber
Solusi saya: kasus terbaik 7,025 bit / angka, kasus terburuk 14,193 bit / angka, rata-rata kasar 8,551 bit / angka. Stream-encoded, tidak ada akses acak.
Bahkan sebelum membaca jawaban ruslik, saya langsung terpikir untuk menyandikan perbedaan antara tiap angka, karena jumlahnya akan kecil dan harus relatif konsisten, tetapi solusinya juga harus dapat mengakomodasi skenario terburuk. Kami memiliki ruang 100000 angka yang hanya berisi 1000 angka. Dalam buku telepon yang sangat seragam, setiap angka akan lebih besar dari angka sebelumnya sebesar 100:
55555-12 3 45
55555-12 4 45
55555-12 5 45
Jika itu masalahnya, itu akan membutuhkan penyimpanan nol untuk menyandikan perbedaan antara angka, karena ini adalah konstanta yang diketahui. Sayangnya, angka mungkin berbeda dari langkah ideal 100. Saya akan menyandikan perbedaan dari kenaikan ideal 100, sehingga jika dua angka yang berdekatan berbeda 103, saya akan menyandikan angka 3 dan jika dua angka yang berdekatan berbeda 92, saya akan menyandikan -8. Saya menyebut delta dari kenaikan ideal 100 sebagai " varians ".
Varians dapat berkisar dari -99 (yaitu dua angka berurutan) hingga 99000 (seluruh buku telepon terdiri dari angka 00000… 00999 dan tambahan nomor terjauh 99999), yang merupakan kisaran 99100 nilai yang memungkinkan.
Saya akan bertujuan untuk mengalokasikan penyimpanan minimal untuk mengkodekan perbedaan yang paling umum dan memperluas penyimpanan jika saya menemukan perbedaan besar (seperti protobuf ‘s
varint
). Saya akan menggunakan potongan tujuh bit, enam untuk penyimpanan dan bit bendera tambahan di bagian akhir untuk menunjukkan bahwa varian ini disimpan dengan potongan tambahan setelah yang sekarang, hingga maksimum tiga potongan (yang akan memberikan maksimum 3 * 6 = 18 bit penyimpanan, yang merupakan 262144 nilai yang mungkin, lebih dari jumlah kemungkinan varians (99100). Setiap potongan tambahan yang mengikuti bendera yang ditinggikan memiliki bit dengan signifikansi lebih tinggi, sehingga potongan pertama selalu memiliki bit 0- 5, potongan kedua opsional memiliki bit 6-11, dan potongan ketiga opsional memiliki bit 12-17.Satu potongan menyediakan enam bit penyimpanan yang dapat menampung 64 nilai. Saya ingin memetakan 64 varian terkecil agar sesuai dalam potongan tunggal itu (yaitu varian -32 hingga +31) jadi saya akan menggunakan pengkodean ProtoBuf ZigZag, hingga varian -99 hingga +98 (karena tidak perlu untuk varian negatif di luar -99), di mana saya akan beralih ke pengkodean biasa, diimbangi dengan 98:
Beberapa contoh bagaimana varians akan dikodekan sebagai bit, termasuk bendera untuk menunjukkan potongan tambahan:
Jadi, tiga nomor pertama dari buku telepon contoh akan dikodekan sebagai aliran bit sebagai berikut:
Skenario kasus terbaik , buku telepon tersebar agak seragam dan tidak ada dua nomor telepon yang memiliki varian lebih besar dari 32, sehingga akan menggunakan 7 bit per nomor ditambah 32 bit untuk nomor awal dengan total 32 + 7 * 999 = 7025 bit .
Skenario campuran , di mana varian nomor telepon 800 cocok dalam satu bagian (800 * 7 = 5600), 180 nomor masuk dalam dua bagian masing-masing (180 * 2 * 7 = 2520) dan 19 nomor cocok dalam tiga bagian masing-masing (20 * 3 * 7 = 399), ditambah 32 bit awal, totalnya 8551 bit .
Skenario kasus terburuk , 25 angka masuk dalam tiga potongan (25 * 3 * 7 = 525 bit) dan 974 angka yang tersisa masuk dalam dua potongan (974 * 2 * 7 = 13636 bit), ditambah 32 bit untuk angka pertama untuk grand jumlah dari14193 bit .
Saya dapat melihat empat pengoptimalan tambahan yang dapat dilakukan untuk lebih mengurangi ruang yang diperlukan:
sumber
Pertanyaan sebenarnya adalah salah satu cara menyimpan nomor telepon lima digit.
Triknya adalah Anda memerlukan 17 bit untuk menyimpan kisaran angka dari 0..99.999. Tetapi menyimpan 17-bit pada batas kata 8-byte konvensional merepotkan. Itulah mengapa mereka menanyakan apakah Anda dapat melakukannya dalam waktu kurang dari 4k dengan tidak menggunakan integer 32-bit.
Pertanyaan: apakah semua kombinasi angka mungkin?
Karena sifat dari sistem telepon, mungkin terdapat kurang dari 65k kemungkinan kombinasi. Saya akan berasumsi bahwa ya karena kita berbicara tentang lima posisi terakhir di nomor telepon, yang bertentangan dengan kode area atau awalan pertukaran.
Pertanyaan: apakah daftar ini akan statis atau perlu mendukung pembaruan?
Jika statis , maka ketika tiba saatnya untuk mengisi database, hitung jumlah digit <50.000 dan jumlah digit> = 50.000. Alokasikan dua array dari
uint16
panjang yang tepat: satu untuk bilangan bulat di bawah 50.000 dan satu untuk set yang lebih tinggi. Saat menyimpan bilangan bulat dalam larik yang lebih tinggi, kurangi 50.000 dan saat membaca bilangan bulat dari larik tersebut, tambahkan 50.000. Sekarang Anda telah menyimpan 1.000 bilangan bulat Anda dalam 2.000 kata 8-byte.Membuat buku telepon akan membutuhkan dua input traversal, tetapi pencarian seharusnya dilakukan dalam waktu setengah, rata-rata, daripada jika menggunakan satu larik. Jika waktu pencarian sangat penting, Anda dapat menggunakan lebih banyak array untuk rentang yang lebih kecil tetapi saya pikir pada ukuran ini, kinerja Anda pasti akan menarik array dari memori dan 2k mungkin akan disimpan ke dalam cache CPU jika tidak mendaftarkan ruang pada apa pun yang Anda gunakan. hari.
Jika dinamis , alokasikan satu larik berisi 1000 atau lebih
uint16
, dan tambahkan angka dalam urutan yang diurutkan. Setel byte pertama menjadi 50.001, dan setel byte kedua ke nilai null yang sesuai, seperti NULL atau 65.000. Saat Anda menyimpan nomor, simpan dalam urutan yang diurutkan. Jika sebuah angka di bawah 50.001 maka simpanlah sebelum penanda 50.001. Jika suatu bilangan adalah 50.001 atau lebih besar, simpan setelah penanda 50.001, tetapi kurangi 50.000 dari nilai yang disimpan.Array Anda akan terlihat seperti:
Jadi, saat Anda mencari nomor di buku telepon, Anda akan melintasi larik dan jika Anda telah mencapai nilai 50.001, Anda mulai menambahkan 50.000 ke nilai larik Anda.
Ini membuat sisipan menjadi sangat mahal, tetapi pencariannya mudah, dan Anda tidak akan menghabiskan lebih dari 2k untuk penyimpanan.
sumber