Graaf

Definitsioon

Graaf (ingl. k. graph) on andmestruktuur, mis on oma olemuselt ning esituselt sarnane graafiteoorias uuritavale matemaatilisele objektile graaf.

Graaf on objekt, millel on minimaalselt:

  • mittetühi hulk tippe (ingl. k. vertex või node)

  • hulk servasid (ingl. k. edge), mis on 2-ennikud graafis olevatest tippudest

Ülevaatlikult võib öelda, et graaf on üks üldisemaid struktuure, mis võimaldab väljendada elemetide hulka ning nendevaheliseid suhteid.

Näiteks:

  • Autoteesid, ning kuidas need omavahel on ühendatud

  • Inimesi, ning nende sõprussuhteid (nt. sotsiaalvõrgustikus)

  • Faile, ning nende asukohta failisüsteemi kaustades

  • Programmi loogilist struktuuri abstraktse süntaksipuu näol

Graafi definitsiooni sageli täiendatakse, et olla spetsiifilistes kontekstides kasulikum. Mõni sellistest täiendustest on väga levinud ning hästi tuntud (vt. servade suunatus, tipude väärtustamine).

Näide

Siin on tekstiline esitus graafile DOT keeles:

graph G {
    v1 -- v2;
    v2 -- v3;
    v3 -- v4;
}

Ülaltoodud tekstist saab välja lugeda definitsioonile vastava graafi:

  • Tippude hulk: {v1, v2, v3, v4}

  • Servade (tippude 2-ennikute) hulk: {(v1, v2), (v2, v3), (v2, v4)}

Ning visuaalselt võib seda selliselt kujutada:

../_images/undirected-graph.svg

Servade suunatus

Eelnevalt eeldasime, et servades sisalduvate tippude järjekord on ebaoluline - sellises kontekstis on graafid **suunamata graafid.

Kui ütleme, et servades sisalduvate tippude järjekord on oluline, siis vaatleme suunatud graafe.

Võimalikud kasutusjuhud:

  • Jälgib suhted sotsiaalvõrgustikus (kasutaja A jälgib kasutajat B, aga mitte vastupidi)

  • Autoteede puhul ühe- või kahesuunalisuse tähistamiseks

Näide

digraph G {
    v1 -> v2;
    v2 -> v3;
    v3 -> v2;
}

Erinevalt eelmisest suunamata graafi näitest, ei ole siin võimalik "liikuda" tipust v2 tippu v1.

../_images/directed-graph.svg

Servade väärtustamine

Servade väärtustamise puhul omistame igale servale mingi (tüüpiliselt skalaarse) väärtuse.

Need väärtused võivad kujutada:

  • Teede pikkust

  • Teede läbimisaega

  • Autoteede "mugavust" (laius, teekate)

Servade väärtustamine võimaldab lahendada probleeme nagu "leia lühim tee ühest punktist teise teede võrgustikus".

Näide

digraph Eesti {
    Tallinn -> Tartu [weight=179; label=179]
    Tartu -> Tallinn [weight=179; label=179]
    Tartu -> Pärnu [weight=176; label=176]
    Pärnu -> Tartu [weight=176; label=176]
    Tallinn -> Pärnu [weight=127; label=127]
    Pärnu -> Tallinn [weight=127; label=127]
}
../_images/maantee-graaf.svg

Esitamine mälus

Graafi võib mälus esitada mitmeti. Vaatleme kõige lihtsamat varianti, kus:

  • Graaf on hulk tippe

  • Igal tipul on hulk naabreid

Javas võib seda esitada niiviisi:

public class Vertex {
    private final List<Vertex> neighbours;

    public Vertex() {
        this.neighbours = new ArrayList<>();
    }

    public Vertex(List<Vertex> neighbours) {
        this.neighbours = neighbours;
    }

    public List<Vertex> getNeighbours() {
        return neighbours;
    }
}
public class Graph {
    private final List<Vertex> vertices;

    public Graph() {
        this.vertices = new ArrayList<>();
    }

    public Graph(List<Vertex> vertices) {
        this.vertices = vertices;
    }

    public void add(Vertex vertex) {
        this.vertices.add(vertex);
    }

    public List<Vertex> getVertices() {
        return vertices;
    }
}

Warning

Kui on vajadus programmis graafidega ümber käia, on tõenäoliselt mõistlikum kasutada mõnda selleks mõeldud teeki, milles on juba graafid ning otsingualgoritmid tõhusalt implementeeritud.

Ning kasutamine võib välja näha selline:

var graph = new Graph();
var v1 = new Vertex();
var v2 = new Vertex(List.of(v1));
var v3 = new Vertex(List.of(v2));
digraph G {
    v2 -> v1
    v3 -> v2
}

Eeltoodud esitused on samaväärsed.