of 58 /58
Puud Puu (programmeerimises tavaliselt järjestatud puu): - dünaamiline andmestruktuur - komponentideks nn. puu tipud: juurtipp e. juur, vahetipud ,lehed - peegeldab ranget hierarhiat: juurtipp on kõige kõrgema taseme “ülemus”, kõigil ülejäänud tippudel on täpselt üks ülemus.

tipudkodu.ut.ee/~ahtip/oop2005/loeng12.pdfPuud • Puu (programmeerimises tavaliselt järjestatud puu): - dünaamiline andmestruktuur - komponentideks nn. puu tipud: juurtipp e. juur,

  • Author
    others

  • View
    8

  • Download
    0

Embed Size (px)

Text of tipudkodu.ut.ee/~ahtip/oop2005/loeng12.pdfPuud • Puu (programmeerimises tavaliselt järjestatud...

  • Puud

    • Puu (programmeerimises tavaliselt järjestatud puu):

    - dünaamiline andmestruktuur - komponentideks nn. puu tipud:

    juurtipp e. juur, vahetipud ,lehed

    - peegeldab ranget hierarhiat:juurtipp on kõige kõrgema taseme “ülemus”, kõigil ülejäänud tippudel on täpselt üks ülemus.

  • Puud

    - alluvateta tipud = puu lehed, kõik ülejäänud (v.a. juur) tipud on vahetipud

    - sama ülemuse alluvad – kolleegid, naabrid - järjestatud puu korral on oluline iga tipu alluvate (naabrite) omavaheline järjestus

  • • Näide: aritmeetilise avaldise puu “Tavaline” kuju: ( 2 - 1 ) * 4 + 6 / 3 Pööratud poola kuju: 2 1 – 4 * 6 3 / + Prefikskuju sulgudega: + ( * ( - (2,1), 4), / (6,3)) Postfikskuju sulgudega: (((2,1) - , 4) * ,(6,3) / ) +

    *

    +

    /

    -

    Juur

    Lehed2 1 4 6 3

  • Puu läbimine

    • Eesjärjestus (pre-order):- Töödelda juur- Töödelda juure alampuud järjestuses vasakult

    paremale• Lõppjärjestus (post-order, end-order):

    - Töödelda juure alampuud järjestuses vasakult paremale

    - Töödelda juur

    Millises järjestuses toimub aritmeetilise avaldise väärtuse arvutamine?

  • Puu läbimine

    Pre: ABDGHEFICJPost: GHDEIFBJCA

    B

    A

    C

    J

    D E F

    IG H

  • Puu esitlusviisid

    • Graafiline (joonisel)• Vasakpoolne suluesitus

    A(B(D(G,H),E,F(I)),C(J))• Parempoolne suluesitus

    (((G,H)D,E(I)F)B,(J)C)A• Tekstiline “treppimine”

  • Puu esitlusviisid

    •Tekstiline “treppimine”A

    BD

    HE

    IF

    JC

    G

  • Puu esitlusviisid

    • Tippudele viitamine liitnimedega A, A.B, A.C, A.B.D, A.B.E, A.B.F,

    A.B.D.G, A.B.D.H, A.B.F.I, A.C.J

    • Mittejärjestatud puu esitamiseks sobivad ka graafi esitlusviisid (vajadusel fikseerida juurtipp) – näit. külgnevusmaatriks vms.

  • Puu esitlusviisid

    • Puu esitlusviisid töötlemiseks arvutis sõltuvad lahendatavast ülesandest – universaalset “parimat” kujutlusviisi ei leidu:- tekstilised esitlused- viidastruktuurid- peitmine muude mehhanismide sisse - …

  • Puu kujutamine ahelate abil

    • Igas tipus on viit tema ülemusele (juurtipus nullviit).

    • Puudus: puu tippe ei saa lähtudes juurtipust süstemaatiliselt “läbi käia”. Saab teha töötlust “alt üles”, kui on korraldatud juurdepääs lehtede hulgale

  • Puu kujutamine ahelate abil

    • Igast tipust lähtub selle tipu vahetute alluvate ahel (lehtede korral tühi ahel) ning viit (parempoolsele) naabrile.

    • Puudus: antud tipust ei pääse lisavõimalusi (näit. magasini) kasutama “üles”.

    • Kasulik rekursiivsete töötlusprogrammide korral.

  • Puu kujutamine arvutis

    • Nn. kahendpuu tipus on viit vasakule alampuule ning viit paremale alampuule.

    • Läbimiseks kasutada magasini või rekursiivset algoritmi.

  • I

    import java.util.*;

    /** Puu tipp. Käsitleme puu tippu ka alampuu juurena ning

    * naabrite loetelu elemendina.

    */

    public class Tipp implements java.util.Enumeration {

    /** tippu identifitseeriv sõne. */

    String nimi;

    /** viit tipu parempoolsele naabrile või null. */

    Tipp paremNaaber;

    /** viit tipu esimesele alluvale või null. */

    Tipp esimAlluv;

  • /** tipu konstruktor. */

    Tipp (String s, Tipp p, Tipp a) {

    paneNimi (s);

    paneParemNaaber (p);

    paneEsimAlluv (a);

    }

    Tipp() { /** teisene konstruktor. */

    this ("", null, null);

    }

    Tipp (String s) {

    this (s, null, null);

    }

    Tipp (String s, Tipp p) {

    this (s, p, null);

    }

  • /** nime panemine. */

    public void paneNimi(String s) {

    nimi = s;

    }

    /** tagastab nime. */

    public String votaNimi() {

    return nimi;

    }

    /** väärtustab viida parempoolsele naabrile. */

    public void paneParemNaaber (Tipp p) {

    paremNaaber = p;

    }

  • /** tagastab parempoolse naabri. */

    public Tipp votaParemNaaber() {

    return paremNaaber;

    }

    /** väärtustab viida esimesele alluvale. */

    public void paneEsimAlluv (Tipp a) {

    esimAlluv = a;

    }

    /** tagastab esimese alluva. */

    public Tipp votaEsimAlluv() {

    return esimAlluv;

    }

  • /** teisendus sõneks (ainult tipp) */

    public String toString() {

    return votaNimi();

    }

    /** tipu töötlemine (katta üle alamklassides). */

    public void tootleTipp() {

    System.out.print (votaNimi() + " ");

    }

    /** naabrite Enumeration. */

    public boolean hasMoreElements() {

    return (votaParemNaaber() != null);

    }

  • /** naabrite Enumeration. */

    public Object nextElement() {

    return votaParemNaaber();

    }

    /** alluvate loetelu. */

    public Enumeration alluvad() {

    return votaEsimAlluv();

    }

    /** kas tipp on leht. */

    public boolean onLeht() {

    return (votaEsimAlluv() == null);

    }

  • /** alluva lisamine viimaseks alluvate loetelus. */

    public void lisaAlluv (Tipp a) {

    if (a == null) return;

    Enumeration alluvad = alluvad();

    if (alluvad == null)

    paneEsimAlluv (a);

    else {

    while (alluvad.hasMoreElements())

    alluvad = (Tipp)alluvad.nextElement();

    ((Tipp)alluvad).paneParemNaaber (a);

    }

    }

  • public int size() { /** (alam)puu tippude arv (koos juurega). */

    int n = 1; // juur ise

    Enumeration alluvad = alluvad();

    while (alluvad != null) {

    n = n + ((Tipp)alluvad).size();

    alluvad = (Tipp)alluvad.nextElement();

    }

    return n;

    }

    public void preorder() { /** puu läbimine eesjärjekorras. */

    tootleTipp();

    Enumeration alluvad = alluvad();

    while (alluvad != null) {

    ((Tipp)alluvad).preorder();

    alluvad = (Tipp)alluvad.nextElement();

    }

    }

  • /** puu läbimine lõppjärjekorras. */

    public void postorder() {

    Enumeration alluvad = alluvad();

    while (alluvad != null) {

    ((Tipp)alluvad).postorder();

    alluvad = (Tipp)alluvad.nextElement();

    }

    tootleTipp();

    }

  • /** konkreetse puu tegemine. */

    public static Tipp tehaPuu() {

    Tipp juur = new Tipp ("+", null,

    new Tipp ("*",

    new Tipp ("/", null,

    new Tipp ("6",

    new Tipp ("3", null, null),

    null)),

    new Tipp ("-",

    new Tipp ("4", null, null),

    new Tipp ("2",

    new Tipp ("1", null, null),

    null))));

    return juur;

    }

  • /** peameetod silumiseks. */

    public static void main (String[] param) {

    Tipp t = tehaPuu();

    System.out.println (t.size());

    System.out.print ("Preorder: ");

    t.preorder();

    System.out.println();

    System.out.print ("Postorder: ");

    t.postorder();

    System.out.println();

    } // main lõpp

  • Graafid

    • G=(V,E), V-lõplik tippude hulk• E on alamhulk hulgast V×V • Orienteerimata graafid• Orienteeritud graafid• E nim. servade hulgaks

  • Graafid

    • G=(V,Ø) – nullgraaf• Täisgraaf G={V,V×V\{v,v}v ∈ V}• Tee tipust u tippu v on tippude jada (u,w0), (w0,w1), …(wn,v), kus kõik need paarid on servad.

    • Sidus graaf• Nõrgalt sidus – suundade ärajätmisel saab

    sidusaks

  • Graafid

    • G1=(V1,E1) on graafi G=(V,E) alamgraaf, kui V1⊆V ja E1=E∩V1×V1

    • Külgnevusmaatriks on |V | × | V| maatriks A=a[i][j], milles a[i][j]=1, kui kaar (i,j)∈E ning 0 vastasel juhul.

    • Multigraafi korral a[i][j] tipust i tippu j viivate teede arv

  • Graafid

    • Graafi G transitiivne sulund G+ saadakse lähtegraafile kõigi niisuguste kaarte (u,v) lisamisel, mille korral leidub tee tipust u tippu v

    • Ahel – tee, milles servad ei kordu• Lihtahel – ahel, milles ka tipud ei kordu• Tsükkel – nullist suurema pikkusega kinnine ahel• Lihttsükkel – kinnine lihtahel• Euleri ja Hamiltoni ahelad, tsüklid

  • Graafid

    • Kauguste maatriks D=d[i][j] on |V | × | V | maatriks, milles d[i][j] on kaare (i,j) “pikkus”

    • Adj(v)={e∈E |∃w ∈V: e=(v,w)}• Külgnevusstruktuur on hulk {(v, Adj(v)) | v ∈V}

  • Graafide kujutamine

    • Joonis (nt .tasandilised graafid)• Kaarte loetelu (kaarega peab siis lisanduma ka

    otspunktide kohta käiv informatsioon)• Külgnevusmaatriks (kaaslusmaatriks)• Külgnevusstruktuur – tippude loetelu, milles iga

    tipuga seotud sellest lähtuvate kaarte loetelu, kaare suubumistipud

  • Graafi kujutamine külgnevusstruktuuri abil

  • Graafi kujutamine külgnevusstruktuuri abil

  • interface AbstrGraaf {

    boolean lisaTipp (AbstrTipp t);

    //kas sai lisada?

    boolean eemaldaTipp (AbstrTipp t);

    //kas sai eemaldada?

    AbstrTipp leiaTipp (String nimi);

    //nime jargi tipu leidmine

    String toString ();

    //va"ljatru"kiks vajalik

    }

  • interface AbstrTipp {

    String votaNimi ();

    //tipu nime leidmine

    boolean lisaValjuvkaar (AbstrKaar k);

    //kas sai lisada?

    boolean eemaldaValjuvkaar (AbstrKaar k);

    //kas sai eemaldada?

    }

  • interface AbstrKaar {

    boolean paneSuubuma (AbstrTipp t);

    String votaNimi ();

    //kaare nime leidmine

    }

  • class Element { //lisainfo tuleb lisada alamklassides

    String nimi;

    Element jargmine;

    Element() { //konstruktor vaikimisi

    }

    Element (String s) { //konstruktor nimega isendite loomiseks

    paneNimi (s);

    }

    public String votaNimi() {

    return nimi;

    }

    public Element votaJargmine() {

    return jargmine;

  • public Element votaJargmine() {

    return jargmine;

    }

    public void paneNimi (String s) {

    nimi = s;

    }

    public void paneJargmine (Element e) {

    jargmine = e;

    }

  • public Element lisa (Element e) { //annab uue alguse tagasi

    if (e == null) return this; // ei olnudki soovi lisada

    if (e == this) return this; // ebanormaalne situatsioon niikuinii

    if (e.votaNimi().compareTo (votaNimi()) < 0) { // e.nimi < this.nimi

    e.paneJargmine (this); // lisamine ahela algusesse

    return e;

    }

    Element abi = this; // hakkame kohta otsima abi jarele

    while (abi.votaJargmine() != null) {

    if (e.votaNimi().compareTo (abi.votaJargmine().votaNimi()) < 0) {

    // lisamine abi jarele

    e.paneJargmine (abi.votaJargmine());

    abi.paneJargmine (e);

    return this;

    }

    abi = abi.votaJargmine();

    }

  • abi.paneJargmine (e); // lisamine ahela loppu

    e.paneJargmine (null); // igaks juhuks

    return this;

    } // lisa() lopp

    public Element eemalda (Element e) { //annab uue alguse voi null

    if (e == null) return this; //ei eemalda midagi

    if (e == this) return votaJargmine(); //esimese eemaldamine

    Element abi = this;

    while (abi != null) {

    if (e == abi.votaJargmine()) {

    abi.paneJargmine (e.votaJargmine());

    }

    abi = abi.votaJargmine();

    }

    return this;

  • public Element otsi (String s) { //kui ei leia, siis null

    Element abi = this;

    while (abi != null) {

    if (s.equals (abi.votaNimi())) return abi;

    abi = abi.votaJargmine();

    }

    return null;

    }

    } //Element lopp

  • class Graaf extends Element implements AbstrGraaf {

    Tipp esimene;

    Graaf () { //konstruktor vaikimisi

    }

    Graaf (String s) { //konstruktor nimega graafi jaoks

    super(s);

    }

    public Tipp votaEsimene () {

    return esimene;

    }

    public void paneEsimene (Tipp t) {

    esimene = t;

    }

  • public boolean lisaTipp (AbstrTipp t) {

    if (votaEsimene() == null) {

    paneEsimene ((Tipp) t);

    return true;

    }

    paneEsimene ((Tipp) votaEsimene().lisa ((Tipp) t));

    return true;

    }

  • public boolean eemaldaTipp (AbstrTipp t) {

    if (votaEsimene() == null) return false;

    paneEsimene ((Tipp) votaEsimene().eemalda ((Tipp) t));

    return true;

    }

    public AbstrTipp leiaTipp (String s) {

    if (votaEsimene() == null) return null;

    return (Tipp) votaEsimene().otsi (s);

    }

  • public String toString () {

    String abi = "Graaf: " + votaNimi() + "\n";

    Tipp t = votaEsimene();

    while (t != null) {

    abi += t.votaNimi() + " --> ";

    Kaar k = t.votaEsimenevaljuv();

    while (k != null) {

    abi += k.votaKuhusuubub().votaNimi() + " (" + k.votaNimi() + ") ";

    k = (Kaar) k.votaJargmine();

    }

    abi += "\n";

    t = (Tipp) t.votaJargmine();

    }

    return abi;

    }

    } //Graaf lopp

  • class Tipp extends Element implements AbstrTipp {

    Kaar esimenevaljuv;

    Tipp () { //konstruktor vaikimisi

    }

    Tipp (String s) { //konstruktor nimega tipule

    super (s);

    }

    public Kaar votaEsimenevaljuv () {

    return esimenevaljuv;

    }

    public void paneEsimenevaljuv (Kaar k) {

    esimenevaljuv = k;

    }

  • public boolean lisaValjuvkaar (AbstrKaar k) {

    if (votaEsimenevaljuv () == null) {

    paneEsimenevaljuv ((Kaar) k);

    return true;

    }

    paneEsimenevaljuv ((Kaar) votaEsimenevaljuv().lisa ((Kaar) k));

    return true;

    }

    public boolean eemaldaValjuvkaar (AbstrKaar k) {

    if (votaEsimenevaljuv () == null) return false;

    paneEsimenevaljuv ((Kaar) votaEsimenevaljuv().eemalda ((Kaar) k));

    return true;

    }

    } //Tipp lopp

  • class Kaar extends Element implements AbstrKaar {

    Tipp kuhusuubub;

    Kaar () { //konstruktor vaikimisi

    }

    Kaar (String s) { //konstruktor nimega kaarele

    super (s);

    }

    public Tipp votaKuhusuubub () {

    return kuhusuubub;

    }

  • public void paneKuhusuubub (Tipp t) {

    kuhusuubub = t;

    }

    public boolean paneSuubuma (AbstrTipp t) {

    paneKuhusuubub ((Tipp) t);

    return t != null;

    }

    } //Kaar lopp

  • static public void main (String[] argumendid) {

    System.out.println ("Tere");

    Graaf g = new Graaf ("minugraaf");

    Tipp t1 = new Tipp ("T1");

    Kaar k1 = new Kaar ("K1");

    g.lisaTipp (t1);

    Tipp t2 = new Tipp();

    t2.paneNimi ("T0");

    g.lisaTipp (t2);

    t1.lisaValjuvkaar (k1);

    k1.paneSuubuma (t2);

    System.out.println (g); //oluline, et toString() meetod oleks!

    System.out.println ("Lopp");

    }

  • Programmi töö:

    Tere

    Graaf: minugraaf

    T0 -->

    T1 --> T0 (K1)

    Lopp

  • Külgnevusstruktuuri läbivaatus

    • Kuidas läbida graafi?• “Töödelda” tipud ja kaared.• Kasutusel abimuutujad tippude ja kaarte

    läbimiseks

  • Külgnevusmaatriksi ehitamine

    • Algul kõik M[i][j]=0• Iga kaare korral M[kaare_algus][kaare_lopp]++

    • Mida selle maatriksiga teha?• Tehted maatriksitega, interpretatsioon• Näiteks: M – linnadevaheliste lennuliinide

    olemasolu

  • Kauguste arvutamine

    • Etteantud külgnevusmaatriksi järgi leida lühimad teepikkused kõigi tipupaaride vahe → kauguste maatriks

    • Floyd-Warshalli algoritmi idee: iga tipu t korral vaadata läbi kõikvõimalikud teed kujul i→tj→ .

    • t=1..n i=1..n j=1..n if (M[i][t]+M[t][j]

  • Tsükliteta orienteeritud graafi tippude topoloogiline sorteerimine

    • Leida graafi tippude selline transitiivne järjestus

  • Graafi läbimise üldjuht

    • t olgu algtipp• Adj(v)={e∈E |∃w ∈V: e=(v,w)}• Iga v ∈V korral olek(v)=“uus”|”järjekorras”|”töödeldud”

    • Q – järjekord (tippude hulk)• Kuidas panna tippe järjekorda? Magasini? Kumb

    valida?

  • Graafi läbimine

    • Laiuti, Q on tavaline järjekord – FIFO• Sügavuti, Q on magasin – LIFO• Sõltuvalt ülesandest, nt. Djikstra algoritmis (vaatleme

    järgmises loengus) lühimate teede leidmiseks on Q muutuvate eelistustega järjekord

    • Kas aritmeetikaavaldist kujutava puu “väärtuse” arvutamisel kasutame magasini või järjekorda?

  • Kaarte pikkused on võrdsed

  • Kaarte pikkused ei ole võrdsed

  • Veel

    • Ülesanne: leida minimaalse kaarte arvuga tee antud tipust kõigisse teistesse tippudesse

    • Lühimate teede erijuht, kui kaarte kaalud võrdsed• Graafi läbimine laiuti, kus järjekorrast võetud tipu

    v järglased seotakse ahelasse: eellane(w)=v

    • Kaarte arvu minimaalsuse tagab läbimise järjekord