7.3 KiB
7.3 KiB
Vyhledávání
- Vyhledávání je velmi často prováděná činnost
- Zjišťujeme, zda je prvek určité hodnoty (též prvek s hodnotou klíče) přítomen v poli
- Někdy stačí informace, zda je či není (
true
/false
) - Většinou je potřeba zjistit index, na kterém se hledaný prvek nachází
- Někdy stačí informace, zda je či není (
- Typ vyhledávání
- Neúplné
- Nalezneme první výskyt prvku
- Úplné
- Nalezneme všechny výskyty prvku
- Neúplné
- Výsledek neúplného vyhledávání
- Typicky první index od začátku pole, na kterém se prvek nachází (prvek může být v poli obsažen vícekrát), nebo záporná hodnota, pokud se prvek v poli nenachází (typické použití, protože index prvku nemůže být záporný)
- Pokud je důležité pouze, zda prvek v poli je či není, ale není důležité kde je, je výsledek vyhledávání pouze
true
(prvek je obsažen) nebofalse
(prvek není obsažen)
- Výsledek úplného vyhledávání
- Pole (případně výpis) všech indexů, na kterých se hledaný prvek nachází, nebo prázdné pole, pokud prvek není v poli obsažen
- Pokud není důležité, na kterých indexech se prvek nachází, ale zajímá nás, kolikrát je v poli obsažen, výsledkem je počet výskytů prvku (0 pokud prvek není obsažen)
Vyhledávání v neseřazené posloupnosti (poli)
- Pokud není pole, ve kterém prvek hledáme, seřazené, je jediná možnost sekvenční vyhledávání
Neúplné sekvenční vyhledávání v poli základních datových typů
- Neúplné sekvenční vyhledávání má složitost Ο(n)
- V nejhorším případě je nutné projít celé pole, tedy všech n prvků
- Princip vyhledávání
- Procházíme pole od začátku do konce a porovnáváme hodnoty prvků pole s hodnotou hledaného prvku
- Když prvek nalezneme, ukončíme procházení pole a vrátíme index, na kterém jsme prvek nalezli
- Pokud dojdeme až do konce pole a prvek nenajdeme, vrátíme zápornou hodnotu (typicky
-1
)
Neúplné sekvenční vyhledávání v poli objektů
- Vyhledávání v poli objektů je velice podobné, jako vyhledávání v poli základních datových typů
- Pro porovnání ale nemůžeme použít operátor „
==
“, protože pro objekty vrací true pouze v případě, že se jedná o stejnou instanci- Můžeme porovnávat přímo jeden či více atributů instance
- Můžeme využít metodu
equals()
, pokud je v dané třídě správně implementovaná
- Pro porovnání ale nemůžeme použít operátor „
Úplné sekvenční vyhledávání
- Úplné sekvenční vyhledávání má složitost Ο(n)
- V každém případě je nutné projít celé pole, tedy všech n prvků
- Princip vyhledávání
- Princip je stejný jako u neúplného sekvenčního vyhledávání, pouze neukončíme procházení pole při nalezení prvního výskytu prvku, ale projdeme pole vždy až do konce
- Protože indexů s pozicemi prvků je více, nestačí vrátit jeden index místo jednoho indexu vrátíme pole s jednotlivými indexy
- Délka pole indexů může být maximálně stejná, jako je počet prvků prohledávaného pole a minimálně může být 0, pokud hledaný prvek nebyl v poli nalezen
- Počet výskytů hledaného prvku v poli (a tedy délku pole indexů) na začátku neznáme
- Délku pole indexů tedy volíme jako délku prohledávaného pole
- Délku můžeme po skončení algoritmu zkrátit vytvořením kratší kopie pole na skutečný počet indexů
Vyhledávání v seřazené posloupnosti (poli)
- Pokud je posloupnost seřazená (předpokládáme vzestupně, ale mohla by být i sestupně), je možné použít vyhledávání půlením intervalů (též binární vyhledávání)
- Sekvenční vyhledávání je možné použít také, stejně jako na neseřazenou posloupnost, ale je podstatně pomalejší, takže není důvod ho používat, pokud je posloupnost seřazená
- Pokud provádíme vyhledávání opakovaně a pořadí prvků v prohledávaném poli není důležité, vyplatí se pole jednou seřadit a následně opakovaně používat vyhledávání půlením intervalů
Neúplné vyhledávání půlením intervalů v poli základních datových typů
- Neúplné vyhledávání půlením intervalů (binární vyhledávání) má složitost Ο(log₂n)
- Čas vyhledávání tedy roste pouze s logaritmem počtu prvků prohledávaného pole pro velký počet prvků prohledávaného pole je podstatně rychlejší než sekvenční vyhledávání
- Princip vyhledávání
- V každém kroku rozdělíme prohledávaný interval na dvě poloviny a následně hledáme jen v jedné z polovin
- Zjistíme hodnotu prvku ležícího na prostředním indexu
- Pokud je rovna hledané hodnotě, algoritmus končí
- Pokud je větší než hledaná hodnota, hledáme v levé polovině
- Pokud je menší než hledaná hodnota, hledáme v pravé polovině
- V každém kroku rozdělíme prohledávaný interval na dvě poloviny a následně hledáme jen v jedné z polovin
Úplné vyhledávání půlením intervalů
- Pokud je hledaný prvek v poli obsažen vícekrát, vyhledávání půlením intervalů najde jeden z výskytů, ale není jasné, který výskyt to je
- Nalevo i napravo od nalezeného indexu se mohou vyskytovat prvky se stejnou hodnotou
- Pro úplné vyhledávání je potřeba sekvenčně prohledat pravé i levé okolí nalezeného indexu, dokud se nenarazí na jiný prvek nebo konec či začátek pole
- Protože stejné prvky jsou v seřazeném poli vždy u sebe, není třeba vracet pole všech indexů, na kterých se hledaný prvek nachází, stačí vrátit první a poslední index
Metody pro vyhledávání půlením intervalů z Java Core API
- Třída
Arrays
obsahuje metody pro vyhledávání půlením intervalů- Metoda
Arrays.binarySearch(pole, klíč)
- Prohledává celé pole
- Metoda
Arrays.binarySearch(pole, od, do, klíč)
- Prohledává pouze část pole udanou indexy
od
(včetně) ado
(vyjma)
- Prohledává pouze část pole udanou indexy
- Metody jsou překryté pro pole všech základních datových typů a pro pole objektů
- Prohledávané pole musí být seřazené, typicky vzestupně (typicky knihovní metodou
Arrays.sort()
) - Metoda vrací index nalezeného prvku, nebo zápornou hodnotu, pokud prvek nebyl nalezen
- Tato hodnota obecně není
-1
nutno testovat hodnotu, zda je menší než0
, nikoliv rovna-1
- Absolutní hodnota záporného čísla udává index, na kterém by prvek byl, kdyby v poli byl
- Tato hodnota obecně není
- Metoda
Vyhledávání půlením intervalů v poli objektů
- Pokud bychom chtěli použít binární vyhledávání v poli objektů, je nutné určit, podle čeho se mají objekty porovnávat (podle jakého atributu)
- Je nutné seřadit pole podle tohoto vybraného porovnání a stejné porovnání použít i v algoritmu binárního vyhledávání
- Nejrozumnější je použít metodu
compareTo()
, kterou jsme použili při ručním i knihovním řazení
- Pro správné použití knihovní metody
Arrays.binarySearch()
je nezbytné, aby třída, jejíž instance jsou v poli, implementovala rozhraníComparable<Třída>
- Hlavička třídy, jejíž instance jsou v prohledávaném poli, musí být
public Třída implements Comparable<Třída>
- Musí obsahovat metodu
public int compareTo(Třída třída)
- Podrobnosti viz předměty KIV/PPA2 a KIV/OOP
- Hlavička třídy, jejíž instance jsou v prohledávaném poli, musí být