Løsningsforslag - oppgaver i Avsnitt 3.2.5


Oppgave 1 og 2

////////////////// class TabellListe  //////////////////////////////

package hjelpeklasser;

import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class TabellListe<T> implements Liste<T>
{
  private T[] a;
  private int antall;
  private int endringer;

  @SuppressWarnings("unchecked")          // pga. konverteringen: Object[] -> T[]
  public TabellListe(int størrelse)       // konstruktør
  {
    a = (T[])new Object[størrelse];       // oppretter tabellen
    antall = 0;                           // foreløpig ingen verdier
  }

  public TabellListe()                    // standardkonstruktør
  {
    this(10);                             // startstørrelse på 10
  }

  public TabellListe(T[] a)               // en T-tabell som parameter
  {
    this.a = a.clone();                   // kloner parametertabellen
    antall = a.length;                    // alle i tabellen
  }

  @Override
  public boolean leggInn(T verdi)  // inn bakerst
  {
    Objects.requireNonNull(verdi, "null er ulovlig!");

    // En full tabell utvides med 50%
    if (antall == a.length)
    {
      a = Arrays.copyOf(a,(3*antall)/2 + 1);
    }

    a[antall++] = verdi;   // setter inn ny verdi

    endringer++;

    return true;
  }

  @Override
  public void leggInn(int indeks, T verdi)
  {
    Objects.requireNonNull(verdi, "null er ulovlig!");

    indeksKontroll(indeks, true);  // true: indeks = antall er lovlig

    // En full tabell utvides med 50%
    if (antall == a.length) a = Arrays.copyOf(a,(3*antall)/2 + 1);

    // rydder plass til den nye verdien
    System.arraycopy(a, indeks, a, indeks + 1, antall - indeks);

    a[indeks] = verdi;     // setter inn ny verdi

    antall++;
    endringer++;
  }

  @Override
  public int antall()
  {
    return antall;          // returnerer antallet
  }

  @Override
  public boolean tom()
  {
    return antall == 0;     // listen er tom hvis antall er 0
  }

  @Override
  public T hent(int indeks)
  {
    indeksKontroll(indeks, false);   // false: indeks = antall er ulovlig
    return a[indeks];                // returnerer er tabellelement
  }

  @Override
  public int indeksTil(T verdi)
  {
    for (int i = 0; i < antall; i++)
    {
      if (a[i].equals(verdi)) return i;   // funnet!
    }
    return -1;   // ikke funnet!
  }

  @Override
  public boolean inneholder(T verdi)
  {
    return indeksTil(verdi) != -1;
  }

  @Override
  public T oppdater(int indeks, T verdi)
  {
    Objects.requireNonNull(verdi, "null er ulovlig!");

    indeksKontroll(indeks, false);  // false: indeks = antall er ulovlig

    T gammelverdi = a[indeks];      // tar vare på den gamle verdien
    a[indeks] = verdi;              // oppdaterer

    endringer++;

    return gammelverdi;             // returnerer den gamle verdien
  }

  @Override
  public T fjern(int indeks)
  {
    indeksKontroll(indeks, false);  // false: indeks = antall er ulovlig
    T verdi = a[indeks];

    antall--; // sletter ved å flytte verdier mot venstre
    System.arraycopy(a, indeks + 1, a, indeks, antall - indeks);
    a[antall] = null;   // tilrettelegger for "søppeltømming"

    endringer++;

    return verdi;
  }

  @Override
  public boolean fjern(T verdi)
  {
    Objects.requireNonNull(verdi, "null er ulovlig!");

    for (int i = 0; i < antall; i++)
    {
      if (a[i].equals(verdi))
      {
        antall--;
        System.arraycopy(a, i + 1, a, i, antall - i);

        a[antall] = null;
        endringer++;

        return true;
      }
    }
    return false;
  }

  @Override
  public boolean fjernHvis(Predicate<? super T> p)  // betingelsesfjerning
  {
    Objects.requireNonNull(p);                       // kaster unntak

    int nyttAntall = antall;

    for (int i = 0, j = 0; j < antall; j++)
    {
      if (p.test(a[j])) nyttAntall--;   // a[j] skal fjernes
      else a[i++] = a[j];               // forskyver 
    }

    for (int i = nyttAntall; i < antall; i++)
    {
      a[i] = null;   // tilrettelegger for "søppeltømming"
    }

    boolean fjernet = nyttAntall < antall;

    if (fjernet) endringer++;

    antall = nyttAntall;

    return fjernet;
  }

  @Override
  public void nullstill()
  {
    if (a.length > 10)
      a = (T[])new Object[10];
    else
      for (int i = 0; i < antall; i++)
      {
        a[i] = null;
      }

    antall = 0;
    endringer++;
  }

  @Override
  public String toString()
  {
    if (antall == 0) return "[]";

    StringBuilder s = new StringBuilder();
    s.append('[').append(a[0]);

    for (int i = 1; i < antall; i++)
    {
      s.append(',').append(' ').append(a[i]);
    }
    s.append(']');

    return s.toString();
  }

  @Override
  public void forEach(Consumer<? super T> action)
  {
    for (int i = 0; i < antall; i++)
    {
      action.accept(a[i]);
    }
  }

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

  private class TabellListeIterator implements Iterator<T>
  {
    private int denne = 0;             // instansvariabel
    private boolean removeOK = false;  // instansvariabel
    private int iteratorendringer = endringer;

    @Override
    public boolean hasNext()     // sjekker om det er flere igjen
    {
      return denne < antall;     // sjekker verdien til denne
    }

    @Override
    public T next()
    {
      if (iteratorendringer != endringer)
      {
        throw new ConcurrentModificationException("Listen er endret!");
      }

      if (!hasNext())
        throw new NoSuchElementException("Tomt eller ingen verdier igjen!");

      T denneVerdi = a[denne];   // henter aktuell verdi
      denne++;                   // flytter indeksen
      removeOK = true;           // nå kan remove() kalles

      return denneVerdi;         // returnerer verdien
    }

    @Override
    public void forEachRemaining(Consumer<? super T> action)
    {
      while (denne < antall)
      {
        action.accept(a[denne++]);
      }
    }

    @Override
    public void remove()
    {
      if (iteratorendringer != endringer) throw new
        ConcurrentModificationException("Listen er endret!");

      if (!removeOK) throw new IllegalStateException("Ulovlig tilstand!");

      removeOK = false;          // remove() kan ikke kalles på nytt

      // verdien i denne - 1 skal fjernes da den ble returnert i siste kall
      // på next(), verdiene fra og med denne flyttes derfor en mot venstre

      antall--;           // en verdi vil bli fjernet
      denne--;            // denne må flyttes til venstre

      System.arraycopy(a, denne + 1, a, denne, antall - denne);  // tetter igjen

      a[antall] = null;   // verdien som lå lengst til høyre nulles

      endringer++;
      iteratorendringer++;
    }

  } // TabellListeIterator

} // TabellListe