Løsningsforslag - oppgaver i Avsnitt 1.4.9


Oppgave 1

  public static <T> void innsettingssortering(T[] a, Comparator<? super T> c)
  {
    for (int i = 1; i < a.length; i++)
    {
      T temp = a[i];  // flytter a[i] til en hjelpevariabel

      int j = i-1;    // starter med neste tabellposisjon

      // en og en verdi flyttes inntil rett sortert plass er funnet
      for (; j >= 0 && c.compare(temp,a[j]) < 0; j--) a[j+1] = a[j];

      a[j+1] = temp;  // temp legges inn på rett plass
    }
  } // innsettingssortering  
  public static <T> int maks(T[] a, Comparator<? super T> c)
  {
    return maks(a, 0, a.length, c);  // kaller metoden under
  }

  public static <T> int maks(T[] a, int fra, int til, Comparator<? super T> c)
  {
    fratilKontroll(a.length,fra,til);

    if (fra == til) throw new NoSuchElementException
     ("fra(" + fra + ") = til(" + til + ") - tomt tabellintervall!");

    int m = fra;                // indeks til største verdi
    T maksverdi = a[fra];       // største verdi

    for (int i = fra + 1; i < til; i++)   // går gjennom intervallet
    {
      if (c.compare(a[i],maksverdi) > 0)  // bruker komparatoren
      {
        maksverdi = a[i];     // største verdi oppdateres
        m = i;                // indeks til største verdi oppdateres
      }
    }
    return m;                 // posisjonen til største verdi

  }  // maks

Oppgave 2 a)

Utvalgssortering er kodet vha. metodene min() og bytt(). Det betyr at vi må lage en komparator-versjon av min() og en generisk versjon av bytt():

  public static <T> void bytt(T[] a, int i, int j)
  {
    T temp = a[i]; a[i] = a[j]; a[j] = temp;
  }

  public static <T> int min(T[] a, int fra, int til, Comparator<? super T> c)
  {
    if (fra < 0 || til > a.length || fra >= til)
      throw new IllegalArgumentException("Illegalt intervall!");

    int m = fra;           // indeks til minste verdi i a[fra:til>
    T minverdi = a[fra];   // minste verdi i a[fra:til>

    for (int i = fra + 1; i < til; i++) if (c.compare(a[i], minverdi) < 0)
    {
      m = i;               // indeks til minste verdi oppdateres
      minverdi = a[m];     // minste verdi oppdateres
    }

    return m;  // posisjonen til minste verdi i a[fra:til>
  }

  public static <T> int min(T[] a, Comparator<? super T> c)  // bruker hele tabellen
  {
    return min(a,0,a.length,c);     // kaller metoden over
  }

  public static <T> void utvalgssortering(T[] a, Comparator<? super T> c)
  {
    for (int i = 0; i < a.length - 1; i++)
      bytt(a, i, min(a, i, a.length, c));  // to hjelpemetoder
  }

Oppgave 2 b)

  public static <T>
  int binærsøk(T[] a, int fra, int til, T verdi, Comparator<? super T> c)
  {
    Tabell.fratilKontroll(a.length,fra,til);  // se Programkode 1.2.3 a)
    int v = fra, h = til - 1;    // v og h er intervallets endepunkter

    while (v <= h)  // fortsetter så lenge som a[v:h] ikke er tom
    {
      int m = (v + h)/2;     // heltallsdivisjon - finner midten
      T midtverdi = a[m];  // hjelpevariabel for  midtverdien

      int cmp = c.compare(verdi, midtverdi);

      if (cmp > 0) v = m + 1;        // verdi i a[m+1:h]
      else if (cmp < 0) h = m - 1;   // verdi i a[v:m-1]
      else return m;                 // funnet
    }

    return -(v + 1);   // ikke funnet, v er relativt innsettingspunkt
  }

  public static <T> int binærsøk(T[] a, T verdi, Comparator<? super T> c)
  {
    return binærsøk(a,0,a.length,verdi,c);  // bruker metoden over
  }

Oppgave 2 c)

  public static <T>
  int parter(T[] a, int v, int h, T skilleverdi, Comparator<? super T> c)
  {
    while (v <= h && c.compare(a[v],skilleverdi) < 0) v++;
    while (v <= h && c.compare(skilleverdi,a[h]) <= 0) h--;

    while (true)
    {
      if (v < h) Tabell.bytt(a,v++,h--); else return v;
      while (c.compare(a[v],skilleverdi) < 0) v++;
      while (c.compare(skilleverdi,a[h]) <= 0) h--;
    }
  }

  public static <T> int parter(T[] a, T skilleverdi, Comparator<? super T> c)
  {
    return parter(a,0,a.length-1,skilleverdi,c);  // kaller metoden over
  }

  public static <T>
  int sParter(T[] a, int v, int h, int k, Comparator<? super T> c)
  {
    if (v < 0 || h >= a.length || k < v || k > h) throw new
        IllegalArgumentException("Ulovlig parameterverdi");

    bytt(a,k,h);   // bytter - skilleverdien a[k] legges bakerst
    int p = parter(a,v,h-1,a[h],c);  // partisjonerer a[v:h-1]
    bytt(a,p,h);   // bytter for å få skilleverdien på rett plass

    return p;    // returnerer posisjonen til skilleverdien
  }

  public static <T>
  int sParter(T[] a, int k, Comparator<? super T> c)   // bruker hele tabellen
  {
    return sParter(a,0,a.length-1,k,c); // v = 0 og h = a.lenght-1
  }

  private static <T>
  void kvikksortering(T[] a, int v, int h, Comparator<? super T> c)
  {
    if (v >= h) return;  // hvis v = h er a[v:h] allerede sortert

    int p = sParter(a,v,h,(v + h)/2,c);
    kvikksortering(a,v,p-1,c);
    kvikksortering(a,p+1,h,c);
  }

  public static <T>
  void kvikksortering(T[] a, Comparator<? super T> c) // sorterer hele tabellen
  {
    kvikksortering(a,0,a.length-1,c);
  }

Oppgave 2 d)

  private static <T>
  void flett(T[] a, T[] b, int fra, int m, int til, Comparator<? super T> c)
  {
    int n = m - fra;   // antall elementer i a[fra:m>
    System.arraycopy(a,fra,b,0,n); // kopierer a[fra:m> over i b[0:n>

    int i = 0, j = m, k = fra;     // løkkevariabler og indekser

    while (i < n && j < til)  // fletter b[0:n> og a[m:til>, legger
      a[k++] = c.compare(b[i],a[j]) <= 0 ? b[i++] : a[j++];  // resultatet i a[fra:til>

    while (i < n) a[k++] = b[i++];  // tar med resten av b[0:n>
  }

  public static <T>
  void flettesortering(T[] a, T[] b, int fra, int til, Comparator<? super T> c)
  {
    if (til - fra <= 1) return;     // a[fra:til> har maks ett element

    int m = (fra + til)/2;          // midt mellom fra og til

    flettesortering(a,b,fra,m,c);   // sorterer a[fra:m>
    flettesortering(a,b,m,til,c);   // sorterer a[m:til>

    flett(a,b,fra,m,til,c);         // fletter a[fra:m> og a[m:til>
  }

  public static <T> void flettesortering(T[] a, Comparator<? super T> c)
  {
    T[] b = Arrays.copyOf(a, a.length/2);
    flettesortering(a,b,0,a.length,c);  // kaller metoden over
  } 

Oppgave 3 b)

  Tabell.innsettingssortering(punkt, (p1, p2) ->
    {
      int d = p1.x - p2.x;    // forskjellen mellom x-koordinatene
      if (d != 0) return d;
      return p1.y - p2.y;     // forskjellen mellom x-koordinatene
    }
  );

Oppgave 3 c)

  Tabell.innsettingssortering(punkt,
    Comparator.comparing((Point p) -> p.x).thenComparing(p -> p.y));

og

  Tabell.innsettingssortering(punkt,
    Comparator.comparingInt((Point p) -> p.x).thenComparingInt(p -> p.y));

Oppgave 3 d)

Hvis vi bruker koden under, får vi en feilmelding. Kompilatoren klarer ikke avgjøre hva som er typen til variabelen p. Det løses ved å ha (Point p) -> p.x.
  Tabell.innsettingssortering(punkt,
    Comparator.comparing(p -> p.x).thenComparing(p -> p.y));

Oppgave 3 e)

  Tabell.innsettingssortering(punkt,
    Comparator.comparingDouble(Point::getX).thenComparingDouble(Point::getY));

Oppgave 3 f)

  Tabell.innsettingssortering(punkt, (p1,p2) ->
    {
      int d = (p1.x*p1.x + p1.y*p1.y) - (p2.x*p2.x + p2.y*p2.y);
      if (d != 0) return d; else return p1.y - p2.y;
    }
  );

Oppgave 3 g)

  Tabell.innsettingssortering(punkt, (p1,p2) ->
    {
      int d = p2.x*p1.y - p1.x*p2.y;
      if (d != 0) return d;
      if (p1.x != 0) return p1.x - p2.x;
      if (p1.y != 0) return p1.y - p2.y;

      // nå må p1 == (0,0)
      if (p2.x == 0 && p2.y == 0) return 0; // p1 == p2 == (0,0)
      return -1; // p1 == (0,0) og p2 != (0,0) gir p1 mindre enn p2
    }
  );

Oppgave 4 b)

  Tabell.innsettingssortering(d, Comparator.naturalOrder());

Oppgave 4 d, e, f

public class Dato implements Comparable<Dato>
{
  private final int dag, mnd, år;               // instansvariabler

  // Verdiene bør testes. F.eks. kan ikke dag være mindre
  // enn 1 eller større en 31, 31. april finnes ikke, osv.

  public Dato(int dag, int mnd, int år)         // konstruktør
  {
    this.dag = dag;
    this.mnd = mnd;
    this.år = år;
  }

  public Dato(int dag, Måned måned, int år)  // konstruktør
  {
    this.dag = dag;
    mnd = måned.mndnr();
    this.år = år;
  }

  @Override
  public int compareTo(Dato d)                  // compareTo
  {
    if (år < d.år) return -1;
    else if (år > d.år) return 1;
    else if (mnd < d.mnd) return -1;
    else if (mnd > d.mnd) return 1;
    else return dag - d.dag;
  }

  @Override
  public boolean equals(Object o)               // equals
  {
    if (o == this) return true;
    if (!(o instanceof Dato)) return false;
    Dato d = (Dato)o;
    return år == d.år && mnd == d.mnd && dag == d.dag;
  }

  public boolean equals(Dato d)                 // equals
  {
    return år == d.år && mnd == d.mnd && dag == d.dag;
  }

  @Override
  public int hashCode()                         // laget av Netbeans
  {
    int hash = 3;
    hash = 89 * hash + dag;
    hash = 89 * hash + mnd;
    hash = 89 * hash + år;
    return hash;
  }

  @Override
  public String toString()                      // toString
  {
    StringBuilder s = new StringBuilder();
    s.append(dag).append('.').append(' ').
      append(Måned.toString(mnd)).append(' ').append(år);
    return s.toString();
  }

} // class Dato

Oppgave 5

public class Klokkeslett implements Comparable<Klokkeslett>
{
  private int timer,minutter;

  // klokkeslett på formen 12:21, 00:00, 09:09 osv.
  public Klokkeslett(String klokkeslett)
  {
    if (klokkeslett.length() != 5 || klokkeslett.charAt(2) != ':')
      throw new IllegalArgumentException("Klokkeslett må ha formen tt:mm");

    timer = Integer.parseInt(klokkeslett.substring(0,2));

    if (timer < 0 || timer > 23)
      throw new IllegalArgumentException
        ("Timetallet " + timer + " er ulovlig!");

    minutter = Integer.parseInt(klokkeslett.substring(3));

    if (minutter < 0 || minutter > 59)
      throw new IllegalArgumentException
        ("Minutt-tallet " + minutter + " er ulovlig!");
  }

  @Override
  public int compareTo(Klokkeslett k)
  {
    if (timer < k.timer) return -1;
    else if (timer > k.timer) return 1;
    else return minutter - k.minutter;
  }

  @Override
  public boolean equals(Object o)
  {
    if (o == this) return true;
    if (!(o instanceof Klokkeslett)) return false;
    Klokkeslett k = (Klokkeslett)o;
    return timer == k.timer && minutter == k.minutter;
  }

  public boolean equals(Klokkeslett k)
  {
    return timer == k.timer && minutter == k.minutter;
  }

  @Override
  public int hashCode()  // generert av NetBeans
  {
    int hash = 7;
    hash = 29 * hash + this.timer;
    hash = 29 * hash + this.minutter;
    return hash;
  }

  @Override
  public String toString()
  {
    StringBuilder s = new StringBuilder();
    if (timer < 10) s.append('0'); s.append(timer);
    s.append(':');
    if (minutter < 10) s.append('0'); s.append(minutter);
    return s.toString();
  }

} // class Klokkeslett

//  Programeksempel:

  Klokkeslett[] k = new Klokkeslett[5];

  k[0] = new Klokkeslett("23:56");
  k[1] = new Klokkeslett("09:09");
  k[2] = new Klokkeslett("07:00");
  k[3] = new Klokkeslett("00:00");
  k[4] = new Klokkeslett("19:01");

  Tabell.innsettingssortering(k);
  for (Klokkeslett x : k) System.out.print(x + " ");

  // Utskrift: 00:00 07:00 09:09 22:56 23:59

Oppgave 6

public class Tid implements Comparable<Tid>
{
  private Dato dato;
  private Klokkeslett klokkeslett;

  public Tid(int dag, int mnd, int år, String klokkeslett)
  {
    dato = new Dato(dag,mnd,år);
    this.klokkeslett = new Klokkeslett(klokkeslett);
  }

  public Tid(Dato dato, Klokkeslett klokkeslett)
  {
    this.dato = dato;
    this.klokkeslett = klokkeslett;
  }

  @Override
  public int compareTo(Tid tid)
  {
    int cmp = dato.compareTo(tid.dato);
    if (cmp != 0) return cmp;

    return klokkeslett.compareTo(tid.klokkeslett);
  }

  @Override
  public boolean equals(Object o)              // equals
  {
    if (o == this) return true;
    if (!(o instanceof Tid)) return false;
    return equals((Tid)o);
  }

  public boolean equals(Tid tid)              // equals
  {
    return
    klokkeslett.equals(tid.klokkeslett) && dato.equals(tid.dato);
  }

  @Override
  public int hashCode()
  {
    int hash = 7;
    hash = 97 * hash + dato.hashCode();
    hash = 97 * hash + klokkeslett.hashCode();
    return hash;
  }

  @Override
  public String toString()
  {
    return dato + " kl. " + klokkeslett;
  }

}  // Tid

// Testprogram

  Tid[] tider = new Tid[4];

  tider[0] = new Tid(24,12,2014,"15:30");
  tider[1] = new Tid(24,12,2014,"12:00");
  tider[2] = new Tid(23,12,2014,"12:00");
  tider[3] = new Tid(23,12,2014,"09:00");

  Tabell.innsettingssortering(tider);

  for (Tid tid : tider) System.out.println(tid);