Prořezávej a hledej

Prořezávej a hledej (Prune and search) je typ algoritmu založený na vyřazování neperspektivních dat – redukci velikosti problému. Toto paradigma je velmi podobné algoritmům typu rozděl a panuj (divide and conquer), zásadní rozdíl je ovšem v tom, že při prořezávání neprocházíme všechny větve, ale pouze ty, které pro nás dávají smysl.

Příklad

Pokud hledáme n-té nejvyšší číslo v neseřazeném poli, tak by řešením zajisté bylo pole seřadit a podívat se na zadaný index. Toto řešení ovšem není příliš efektivní. Lepším řešením je upravit například Quicksort tak, aby se po rozdělení pole dle pivota prohledávala pouze ta část, která obsahuje řešení - Quicksort v každém svém kroku umístí pivota na korektní místo v seřazeném poli, není proto problém rozhodnout, ve které části se nachází ono hledané číslo.

Složitost

Zatímco asymptotická složitost Quicksortu je O(n^{2}) a očekáváná O(n \cdot \log(n)), tak díky eliminaci větví, které nemohou obsahovat řešení, je očekávaná složitost prune and search algoritmu O(c \cdot n), kde c je malá konstanta.

Kód

   /**
     * Prorezavej a hledej
     * @param array prohledavane pole
     * @param index kolikatou nejvyssi hodnotu hledame (cislovano od 0)
     * @param left prvni levy prvek, na ktery muzeme sahnout
     * @param right prvni prvek, na ktery uz nemuzeme sahnout
     * @return index-ta nejvyssi hodnota
     */
    public static int pruneAndSearch(int[] array, int index, int left, int right) {
        int boundary = left;
        for (int i = left + 1; i < right; i++) { 
            if (array[i] > array[left]) { //primo za pivot posleme vse vetsi, nez je on sam
                swap(array, i, ++boundary);
            }
        }
        swap(array, left, boundary);
        //konec quicksortu

        if (boundary == index) return array[boundary]; //nalezli jsme
        else if (boundary > index) return pruneAndSearch(array, index, left, boundary); //odrizneme pravou vetev
        else return pruneAndSearch(array, index, boundary + 1, right); //odrizneme levou vetev        
    }

    /**
     * Prohodi prvky v zadanem poli
     * @param array pole
     * @param left prvek 1
     * @param right prvek 2
     */
    private static void swap(int[] array, int left, int right) {
        int tmp = array[right];
        array[right] = array[left];
        array[left] = tmp;
    }

Literatura

  • Prune-and-search. In . [s.l.] : [s.n.], 2006 [cit. 2010-03-15]. Dostupné z WWW: <http://www.cs.duke.edu/courses/fall05/cps230/L-03.pdf>.
{ zpětná vazba }
Delicious Delicious
Sdílet
Hodnocení (0): 0

Přečtěte si také

Diskuse





Vojtěch Sejkora23.11.2010
Takže je to vpodstatě O(N)

v tom případě to je celkem dobrý algoritmus:D

a i pro tu konstantu 10^32 by se našli tak veklké vstupy, které by překonali svou složitostí i 0,01N^2
:D, ale to N by muselo být opravdu dosti velké:)

nicméně děkuji že si už konečně dokáži představit jak velké je to c:)
Pavel Mička23.11.2010
Podle článku v sekci literatura, je u randomizovaneho quicksortu (tento sice není randomizovaný, ale na randomizovaných datech je to relativně jedno) ta konstanta cca. 4. Z asymptotického hlediska je samozřejmě irelevantní, zde jsem ji uvedl z toho důvodu, že je nutné si uvědomit, že to neprojde výpočetně srovnatelnou rychlostí s průchodem pole (což je ale i zřejmé z povahy algoritmu, že ta konstanta nemůže být nižší než 1). Na druhou stranu je přínosem tohoto algoritmu, že je ta konstanta takto malá. Kdyby byla malá, jak uvádíte v porovnání s rozsahem double, tak by se nemělo smysl o tomto algoritmu vůbec bavit, protože by byl i přes svoji lepší složitost výpočetně zabit onou konstantou....
Vojtěch Sejkora23.11.2010
aha...takže si za c můžu dosadit vlastně jakékoli číslo, protože malá konstanta je i 10^32 když beru v potaz že třeba maximální hodnota double je 10^300 (tedy alespoň myslím že cca takto je, to že to není přesné je věc jiná) ale na druhou stranu to může být třeba i 10^-10.... to že je to malá konstanta nám moc nepomohlo(tedy alespoň mě ne), podle řeho se dá rozhodnout resp. odhadnout jak velká je? a je vůbec potřeba tam psát pokud neyávisí na vstupních datech, tak se přece schová do notace O ne?
Pavel Mička22.11.2010
na řádku 19 byl překlep (nelezli => nalezli), c je nějaká malá konstanta, přidal jsem do článku vysvětlivku. Děkuji za připomínky.
Vojtěch Sejkora22.11.2010
ta složitos O(c*N) je jako co? co značí to cčko? + máte chybu v komentáři na řádku 19. nemá tam být náhoou nalezli jsme?