Løsningsforslag - oppgaver i Avsnitt 5.2.13


Oppgave 1a)

  public boolean leggInn(T verdi)
  {
    Node<T> p = rot, q = null;             // pekere
    int cmp = 0;                           // hjelpevariabel

    while (p != null)
    {
      q = p;                               // q er forelder til p
      cmp = comp.compare(verdi,p.verdi);   // sammenligner
      if (cmp < 0) p = p.venstre;          // går til venstre
      else if (cmp > 0) p = p.høyre;       // går til høyre
      else                                 // verdien finnes fra før
      {
        p.forekomster++;                   // øker antallet
        return true;
      }
    }

    p = new Node<>(verdi);                 // oppretter ny node

    if (q == null) rot = p;                // første node - rotnoden
    else if (cmp < 0) q.venstre = p;       // p blir venstre barn til q
    else q.høyre = p;                      // p blir høyre barn til q

    endringer++;                           // en endring i treet
    antall++;                              // en ny verdi i treet

    return true;                           // vellykket innlegging
  }

Oppgave 1b)

Hvis verdien som skal fjernes ligger i en node p med to barn, så går vi isteden til den neste noden r i inorden. Verdien i r kopieres inn i p og r fjernes. Nå kan det hende at det er flere forkomster av verdien i r. Dermed må en passe på at også forekomstantallet kopieres.

  public boolean fjern(T verdi)  // hører til klassen SBinTre
  {
    if (verdi == null) return false;  // treet har ingen nullverdier

    Node<T> p = rot, q = null;   // q skal være forelder til p

    while (p != null)            // leter etter verdi
    {
      int cmp = comp.compare(verdi,p.verdi);      // sammenligner
      if (cmp < 0) { q = p; p = p.venstre; }      // går til venstre
      else if (cmp > 0) { q = p; p = p.høyre; }   // går til høyre
      else break;    // den søkte verdien ligger i p
    }
    if (p == null) return false;   // finner ikke verdi

    p.forekomster--;               // reduserer antall forekomster

    if (p.forekomster > 0) return true;

    if (p.venstre == null || p.høyre == null)  // Tilfelle 1) og 2)
    {
      Node<T> b = p.venstre != null ? p.venstre : p.høyre;  // b for barn
      if (p == rot) rot = b;
      else if (p == q.venstre) q.venstre = b;
      else q.høyre = b;
    }
    else  // Tilfelle 3)
    {
      Node<T> s = p, r = p.høyre;   // finner neste i inorden
      while (r.venstre != null)
      {
        s = r;    // s er forelder til r
        r = r.venstre;
      }

      p.verdi = r.verdi;   // kopierer verdien i r til p
      p.forekomster = r.forekomster;  // kopierer forekomster

      if (s != p) s.venstre = r.høyre;
      else s.høyre = r.høyre;
    }

    endringer++;
    antall--;   // det er nå én node mindre i treet
    return true;
  }

Oppgave 1c)

  public boolean inneholder(T verdi)
  {
    if (verdi == null) return false;           // har ingen nullverdier

    Node<T> p = rot;
    while (p != null)
    {
      int cmp = comp.compare(verdi,p.verdi);   // sammenligner
      if (cmp < 0) p = p.venstre;              // går til venstre
      else if (cmp > 0) p = p.høyre;           // går til høyre
      else return true;                        // verdien er funnet
    }

    return false;                              // ukjent verdi
  }

Oppgave 1d)

  public String toString()
  {
    StringBuilder s = new StringBuilder();   // StringBuilder
    s.append('[');                           // starter med [
    if (!tom()) toString(rot,s);             // den rekursive metoden
    s.append(']');                           // avslutter med ]
    return s.toString();                     // returnerer
  }

  private static <T> void toString(Node<T> p, StringBuilder s)
  {
    if (p.venstre != null)                   // p har et venstre subtre
    {
      toString(p.venstre, s);                // komma og mellomrom etter
      s.append(',').append(' ');             // den siste i det venstre
    }                                        // subtreet til p

    s.append(p.verdi);                       // verdien i p
    int i = 1;
    while (i < p.forekomster)              // tar med duplikatene
    {
      s.append(',').append(' ').append(p.verdi);
      i++;
    }

    if (p.høyre != null)                     // p har et høyre subtre
    {
      s.append(',').append(' ');             // komma og mellomrom etter p
      toString(p.høyre, s);                  // siden p ikke er den siste
    }                                        // noden i inorden
  }

Oppgave 1e)

  @Override
  public Iterator<T> iterator()
  {
    return new InordenIterator();
  }

  private class InordenIterator implements Iterator<T>
  {
    private Stakk<Node<T>> s = new TabellStakk<>();  // for traversering
    private Node<T> p = null;                        // nodepeker
    private Node<T> q = null;                        // nodepeker
    private int iteratorforekomster;                 // forekomster
    private int iteratorendringer;                   // iteratorendringer

    private Node<T> først(Node<T> q)   // en hjelpemetode
    {
      while (q.venstre != null)        // starter i q
      {
        s.leggInn(q);                  // legger q på stakken
        q = q.venstre;                 // går videre mot venstre
      }
      return q;                        // q er lengst ned til venstre
    }

    public InordenIterator()  // konstruktør
    {
      if (rot == null) return;         // treet er tomt
      p = først(rot);                  // bruker hjelpemetoden
      iteratorforekomster = 1;         // første forekomst i p
      iteratorendringer = endringer;   // setter treets endringer
    }

    public T next()
    {
      if (iteratorendringer != endringer)
         throw new ConcurrentModificationException();

      if (!hasNext()) throw new NoSuchElementException();

      T verdi = p.verdi;               // tar vare på verdien i noden p
      q = p;                           // q oppdateres før p flyttes

      if (iteratorforekomster < p.forekomster)
      {
        iteratorforekomster++;
      }
      else
      {
        iteratorforekomster = 1;

        if (p.høyre != null)
        {
          p = først(p.høyre);    // p har høyre subtre
        }
        else if (!s.tom())
        {
          p = s.taUt();          // p har ikke høyre subtre
        }
        else p = null;           // stakken er tom
      }

      return verdi;              // returnerer verdien
    }

    public boolean hasNext()
    {
      return p != null;
    }

    public void remove()
    {
      throw new UnsupportedOperationException("Ikke laget!");
    }

  } //InordenIterator