Saya tahu beberapa algoritma pencocokan string dasar seperti KMP atau Boyer-Moore, tetapi semua itu menganalisis pola sebelum mencari. Namun, jika seseorang memiliki karakter tunggal, tidak banyak yang bisa dianalisis. Jadi apakah ada algoritma yang lebih baik daripada pencarian naif membandingkan setiap karakter teks?
algorithms
string-matching
Kristen
sumber
sumber
Jawaban:
Dipahami bahwa kasus terburuknya adalah
O(N)
, ada beberapa optimasi mikro yang sangat bagus.Metode naif melakukan perbandingan karakter dan perbandingan akhir teks untuk setiap karakter.
Menggunakan sentinel (yaitu salinan karakter target di akhir teks) mengurangi jumlah perbandingan hingga 1 per karakter.
Pada level twiddling ada:
untuk mengetahui apakah byte dalam kata (
x
) memiliki nilai tertentu (n
).Subekspresi
v - 0x01010101UL
, dievaluasi menjadi bit tinggi yang diatur dalam byte mana pun setiap kali byte yang sesuai dalamv
adalah nol atau lebih besar dari0x80
.Sub-ekspresi
~v & 0x80808080UL
mengevaluasi bit tinggi yang diatur dalam byte di mana bytev
tidak memiliki bit set yang tinggi (sehingga byte kurang dari0x80
).Dengan ANDing dua sub-ekspresi ini (
haszero
) hasilnya adalah bit tinggi yang ditetapkan di mana byte dalamv
nol, karena bit tinggi yang ditetapkan karena nilai yang lebih besar daripada0x80
dalam sub-ekspresi pertama ditutup oleh yang kedua (27 April, 1987 oleh Alan Mycroft).Sekarang kita dapat XOR nilai untuk diuji (
x
) dengan kata yang telah diisi dengan nilai byte yang kita minati (n
). Karena XORing nilai dengan itu sendiri menghasilkan byte nol dan bukan nol sebaliknya, kita dapat meneruskan hasilnyahaszero
.Ini sering digunakan dalam
strchr
implementasi yang khas .(Stephen M Bennet menyarankan ini pada 13 Desember 2009. Rincian lebih lanjut dalam Bit Twiddling Hacks yang terkenal ).
PS
Retasan melewati tes brute force (bersabarlah):
Terima kasih atas komentarnya.
Jawabannya dimaksudkan untuk apa pun kecuali esai tentang pengkodean multi-byte / variabel-lebar :-) (dalam semua keadilan itu bukan bidang keahlian saya dan saya tidak yakin itu yang dicari OP).
Pokoknya menurut saya ide / trik di atas agak bisa disesuaikan dengan MBE (terutama penyandian sinkronisasi sendiri ):
strchr
/strstr
(mis. GNUlib coreutils mbschr )sumber
0x01010101UL
di satu baris dan~0UL / 255
di baris berikutnya. Ini memberi kesan bahwa mereka harus nilai yang berbeda, karena kalau tidak, mengapa menulisnya dengan dua cara yang berbeda?#define
s akan berkembang menjadi( (((x) ^ (0x01010101UL * (n)))) - 0x01010101UL) & ~((x) ^ (0x01010101UL * (n)))) & 0x80808080UL )
. Bukankah perbandingan satu byte lebih cepat?Algoritme pencarian teks apa pun yang mencari setiap kemunculan satu karakter dalam teks yang diberikan harus membaca setiap karakter teks setidaknya satu kali, itu harus jelas. Dan karena ini cukup untuk pencarian satu kali, tidak ada algoritma yang lebih baik (ketika berpikir dalam hal run time order, yang disebut "linear" atau O (N) untuk kasus ini, di mana N adalah jumlah karakter untuk mencari melalui).
Namun, untuk implementasi nyata, pasti ada banyak optimasi mikro yang dimungkinkan, yang tidak mengubah urutan waktu proses secara keseluruhan, tetapi menurunkan waktu proses yang sebenarnya. Dan jika tujuannya bukan untuk menemukan setiap kemunculan satu karakter, tetapi hanya yang pertama, Anda bisa berhenti pada kemunculan pertama, tentu saja. Namun demikian, bahkan untuk kasus itu, yang terburuk masih karakter yang Anda cari adalah karakter terakhir dalam teks, jadi urutan waktu terburuk untuk tujuan ini masih O (N).
sumber
Jika "tumpukan jerami" Anda dicari lebih dari sekali, pendekatan berbasis histogram akan menjadi sangat cepat. Setelah histogram dibuat, Anda hanya perlu pencarian pointer untuk menemukan jawaban Anda.
Jika Anda hanya perlu tahu apakah pola yang dicari ada, penghitung sederhana dapat membantu. Dapat diperluas untuk memasukkan posisi di mana setiap karakter ditemukan di tumpukan jerami, atau posisi kejadian pertama.
sumber
Jika Anda perlu mencari karakter di string yang sama ini lebih dari sekali, maka pendekatan yang mungkin adalah membagi string menjadi bagian-bagian yang lebih kecil, mungkin secara rekursif, dan menggunakan filter bloom untuk masing-masing bagian ini.
Karena filter bloom dapat memberi tahu Anda dengan pasti jika suatu karakter tidak berada di bagian string yang "diwakili" oleh filter, Anda dapat melewati beberapa bagian saat mencari karakter.
Sebagai contoh: Untuk string berikut, seseorang dapat membaginya menjadi 4 bagian (masing-masing sepanjang 11 karakter), dan mengisi setiap bagian dengan filter bloom (mungkin 4 byte besar) dengan karakter bagian itu:
Anda dapat mempercepat pencarian Anda, misalnya untuk karakter
a
: Menggunakan fungsi hash yang baik untuk filter bloom, mereka akan memberi tahu Anda bahwa - dengan probabilitas tinggi - Anda tidak perlu mencari di bagian pertama, kedua atau ketiga. Dengan demikian Anda menyelamatkan diri dari memeriksa 33 karakter dan alih-alih hanya perlu memeriksa 16 byte (untuk 4 filter mekar). Ini masihO(n)
, hanya dengan faktor konstan (fraksional) (dan agar ini menjadi efektif, Anda harus memilih bagian yang lebih besar, untuk meminimalkan overhead menghitung fungsi hash untuk karakter pencarian).Menggunakan pendekatan rekursif, seperti pohon akan membuat Anda dekat
O(log n)
:Dalam konfigurasi ini kita perlu (sekali lagi, dengan asumsi kita beruntung dan tidak mendapatkan false positive dari salah satu filter) untuk memeriksanya
untuk sampai ke bagian akhir (di mana orang perlu memeriksa 3 karakter sampai menemukan
a
).Dengan menggunakan skema subdivisi yang baik (lebih baik seperti di atas) Anda harus mendapatkan hasil yang cukup bagus dengan itu. (Catatan: Filter Bloom pada akar pohon harus lebih besar daripada dekat dengan daun, seperti yang ditunjukkan dalam contoh, untuk mendapatkan probabilitas positif palsu yang rendah)
sumber
Jika string akan dicari berkali-kali (masalah "pencarian" khas), solusinya bisa O (1). Solusi adalah membangun indeks.
Misalnya:
Peta, di mana Kunci adalah Karakter dan Nilai adalah daftar indeks untuk karakter tersebut dalam string.
Dengan ini, pencarian peta tunggal dapat memberikan jawabannya.
sumber