Hoppa till innehållet

Graftraversering

Från Wikipedia

Inom datavetenskap avser graftraversering (även kallat grafsökning) processen att besöka, kontrollera och/eller uppdatera varje nod i en graf. Sådana traverseringar klassificeras efter i vilken ordning noderna besöks. Trädtraversering är ett specialfall av graftraversering.

Till skillnad från trädtraversering kan graftraversering kräva att vissa noder besöks mer än en gång, eftersom det inte nödvändigtvis är känt innan man går vidare till en nod att den redan har undersökts. När grafer blir mer täta blir denna redundans vanligare, vilket ökar beräkningstiden. När grafer blir glesare gäller det motsatta.

Därför är det oftast nödvändigt att komma ihåg vilka noder som redan har undersökts av algoritmen, så att noder återbesöks så sällan som möjligt eller, i värsta fall, för att förhindra att traverseringen fortsätter oändligt. Detta kan göras genom att varje nod i grafen kopplas till ett "färg"- eller "besökstillstånd" under traverseringen, som sedan kontrolleras och uppdateras när algoritmen besöker noden. Om noden redan har besökts ignoreras den och den vägen följs inte vidare. Annars kontrollerar eller uppdaterar algoritmen noden och fortsätter längs den aktuella vägen.

Flera specialfall av grafer innebär att besök av andra noder redan framgår av deras struktur, och då behöver besök inte registreras uttryckligen under traverseringen. Ett viktigt exempel är ett träd: under en traversering kan man anta att alla "förfäder" till den aktuella noden, och ibland även andra noder beroende på algoritm, redan har besökts. Både djup-först-sökning och bredd-först-sökning är anpassningar av trädbaserade algoritmer, som främst skiljer sig genom avsaknaden av en strukturellt bestämd rot samt tillägget av en datastruktur för att registrera traversalens besökstillstånd.

Algoritmer för graftraversering

[redigera | redigera wikitext]

Om varje nod i en graf ska traverseras med en trädbaserad algoritm, såsom DFS eller BFS, måste algoritmen anropas minst en gång för varje sammanhängande komponent i grafen. Detta kan enkelt göras genom att iterera över alla grafens noder och utföra algoritmen på varje nod som fortfarande är obesökt när den granskas.

Djupet först-sökning

[redigera | redigera wikitext]
Huvudartikel: Djup-först-sökning

Djupet först-sökning (DFS, av engelskans depth-first search) är en algoritm för traversering av en ändlig graf. DFS besöker barnnoder före syskonnoder; den följer alltså djupet i en viss väg innan den undersöker dess bredd. En stack, ofta programmets anropsstack via rekursion, används vanligen vid implementationen.

Algoritmen börjar med en vald startnod. Därefter går den stegvis från den aktuella noden till en angränsande, obesökt nod, tills det inte längre finns någon oupptäckt nod att gå vidare till från den aktuella positionen. Algoritmen går då tillbaka längs tidigare besökta noder tills den hittar en nod som är förbunden med ännu oupptäckt område. Därefter fortsätter den längs den nya vägen på samma sätt som tidigare, backar när den når återvändsgränder och avslutas först när algoritmen har backat förbi den ursprungliga startnoden.

DFS ligger till grund för många grafalgoritmer, bland annat topologisk sortering och testning av planaritet.

  • Indata: En graf G och en nod v i G.
  • Utdata: En märkning av kanterna i den sammanhängande komponenten till v som upptäcktskanter och bakåtkantar.
procedur DFS(G, v)
    märk v som utforskad
    för alla kanter e i G.incidentEdges(v) gör
        om kanten e är outforskat då
            w ← G.adjacentVertex(v, e)
            om noden w är outforskat då
                märk e som en upptäcktskant
                anropa rekursivt DFS(G, w)
            annars
                märk e som en bakåtkant

Bredden först-sökning

[redigera | redigera wikitext]
Huvudartikel: Bredd-först-sökning

Bredden först-sökning (BFS, av engelskans breadth-first search) är en annan teknik för traversering av en ändlig graf. BFS besöker syskonnoder före barnnoder och använder en kö under sökprocessen. Algoritmen används ofta för att hitta den kortaste vägen från en nod till en annan i en oviktad graf.

  • Indata: En graf G och en nod v i G.
  • Utdata: Den närmaste noden till v som uppfyller vissa villkor, eller null om ingen sådan nod finns.
procedur BFS(G, v)
    skapa en kö Q
    lägg v sist i Q
    markera v
    så länge Q inte är tom gör
        w ← Q.dequeue()
        om w är det vi söker då
            returnera w
        för alla kanter e i G.adjacentEdges(w) gör
            x ← G.adjacentVertex(w, e)
            om x inte är markerad då
                markera x
                lägg x sist i Q
    returnera null

Tillämpningar

[redigera | redigera wikitext]

Bredden först-sökning kan användas för att lösa många problem inom grafteori, till exempel:

Grafutforskning

[redigera | redigera wikitext]

Problemet med grafutforskning kan ses som en variant av graftraversering. Det är ett onlineproblem, vilket innebär att information om grafen endast avslöjas under algoritmens körning. En vanlig modell är följande: givet en sammanhängande graf G = (V, E) med icke-negativa kantvikter startar algoritmen vid en viss nod och känner då till alla utgående kanter från noden och de noder som ligger i slutet av dessa kanter, men inget mer. När en ny nod besöks blir åter alla utgående kanter och ändnoder kända. Målet är att besöka alla n noder och återvända till startnoden, samtidigt som summan av turens vikter ska vara så liten som möjligt. Problemet kan också förstås som en särskild version av handelsresandeproblemet, där den handelsresande måste upptäcka grafen under färdens gång.

För allmänna grafer är de bäst kända algoritmerna för både oriktade och riktade grafer en enkel girig algoritm:

  • I det oriktade fallet är den giriga turen högst O(ln n) gånger längre än en optimal tur.[1] Den bästa kända undre gränsen för varje deterministisk onlinealgoritm är 10/3.[2]
    • Oriktade grafer med enhetsvikter kan utforskas med ett konkurrensförhållande på 2 − ε,[3] vilket redan är en skarp gräns för tadpole-grafer.[4]
  • I det riktade fallet är den giriga turen högst (n − 1) gånger längre än en optimal tur. Detta motsvarar den undre gränsen (n − 1).[5] En analog konkurrensmässig undre gräns på Ω(n) gäller också för randomiserade algoritmer som känner till koordinaterna för varje nod i en geometrisk inbäddning. Om målet i stället för att besöka alla noder endast är att hitta en enda "skatt"-nod, är de konkurrensmässiga gränserna Θ(n2) på riktade grafer med enhetsvikter, både för deterministiska och randomiserade algoritmer.

Universella traverseringssekvenser

[redigera | redigera wikitext]

En universell traverseringssekvens är en sekvens av instruktioner som beskriver en graftraversering för varje reguljär graf med ett givet antal noder och för varje startnod. Aleliunas med flera använde ett probabilistiskt bevis för att visa att det existerar en universell traverseringssekvens med ett antal instruktioner proportionellt mot O(n5) för varje reguljär graf med n noder.[6] Stegen som anges i sekvensen är relativa till den aktuella noden, inte absoluta. Om den aktuella noden till exempel är vj och vj har d grannar, kommer traverseringssekvensen att ange nästa nod att besöka, vj+1, som den i:te grannen till vj, där 1 ≤ i ≤ d.

  1. ↑ Rosenkrantz, Daniel J.; Stearns, Richard E.; Lewis, II, Philip M. (1977). ”An Analysis of Several Heuristics for the Traveling Salesman Problem”. SIAM Journal on Computing 6 (3): sid. 563–581. doi:10.1137/0206041.
  2. ↑ Birx, Alexander; Disser, Yann; Hopp, Alexander V.; Karousatou, Christina (Maj 2021). ”An improved lower bound for competitive graph exploration”. Theoretical Computer Science 868: sid. 65–86. doi:10.1016/j.tcs.2021.04.003. https://arxiv.org/abs/2002.10958.
  3. ↑ Miyazaki, Shuichi; Morimoto, Naoyuki; Okabe, Yasuo (2009). ”The Online Graph Exploration Problem on Restricted Graphs”. IEICE Transactions on Information and Systems E92-D (9): sid. 1620–1627. doi:10.1587/transinf.E92.D.1620.
  4. ↑ Brandt, Sebastian; Foerster, Klaus-Tycho; Maurer, Jonathan; Wattenhofer, Roger (November 2020). ”Online graph exploration on a restricted graph class: Optimal solutions for tadpole graphs”. Theoretical Computer Science 839: sid. 176–185. doi:10.1016/j.tcs.2020.06.007. https://arxiv.org/abs/1903.00581.
  5. ↑ Foerster, Klaus-Tycho; Wattenhofer, Roger (December 2016). ”Lower and upper competitive bounds for online directed graph exploration”. Theoretical Computer Science 655: sid. 15–29. doi:10.1016/j.tcs.2015.11.017. https://zenodo.org/record/895821.
  6. ↑ Aleliunas, R.; Karp, R.; Lipton, R.; Lovász, L.; Rackoff, C. (1979). ”Random walks, universal traversal sequences, and the complexity of maze problems”. 20th Annual Symposium on Foundations of Computer Science (SFCS 1979). sid. 218–223. doi:10.1109/SFCS.1979.34