Løsningsforslag - oppgaver i Avsnitt 1.3.4


Oppgave 1

3 4 56 7 19 21 23 1014 15 11 16 178
01234567 891011121314
Tabellen etter 5 iterasjoner

3 4 56 7 8 10 23 2114 15 11 16 1719
01234567 891011121314
Tabellen etter 7 iterasjoner

Oppgave 2

15 8 1716 5 6 7 4 1014 3 11 19 2123
01234567 891011121314
Figur 1.3.4 a) : Gitt en (usortert) tabell.

Oppgave 4

  int[] a = Tabell.randPerm(100000);
  long tid = System.currentTimeMillis();
  Tabell.utvalgssortering(a);
  tid = System.currentTimeMillis() - tid;
  System.out.println(tid);

Oppgave 5

  public static void utvalgssortering(int[] a)
  {
    for (int i = 0; i < a.length - 1; i++)
    {
      int m = i;             // indeks til den foreløpig minste
      int  minverdi = a[i];  // verdien til den foreløpig minste

      for (int j = i + 1; j < a.length; j++)
      {
        if (a[j] < minverdi)
        {
          minverdi = a[j];  // ny minste verdi
          m = j;            // indeksen til ny minste verdi
        }
      }
      // bytter om a[i] og a[m]
      int temp = a[i];
      a[i] = a[m];
      a[m] = temp;
    }
  }

Oppgave 6

  public static void utvalgssortering(int[] a)
  {
    for (int i = 0; i < a.length - 1; i++)
    {
      int m = i;             // indeks til den foreløpig minste
      int  minverdi = a[i];  // verdien til den foreløpig minste

      for (int j = i + 1; j < a.length; j++)
      {
        if (a[j] < minverdi)
        {
          minverdi = a[j];  // ny minste verdi
          m = j;            // indeksen til ny minste verdi
        }
      }
      // bytter om a[i] og a[m]
      a[m] = a[i];
      a[i] = minverdi;
    }
  }

I a[m] = a[i]; a[i] = minverdi; inngår det to tilordninger og tre tabellaksesser, mens det i int temp = a[i]; a[i] = a[m]; a[m] = temp; inngår tre tilordninger og fire tabellaksesser. Vi sparer en tilordning og to tabellaksesser. Men dette vil ikke ha noen målbar effekt på algoritmens effektivitet. Innsparingen skjer i den ytre løkken og den går bare n − 1 ganger. Det er innsparinger i den indre løkken som vil kunne få effekt.

Oppgave 7

Med hjelpemetoder:

  public static void utvalgssortering(int[] a)
  {
    for (int i = a.length; i > 1; i--)
    {
      bytt(a, maks(a, 0, i), i-1);
    }
  }

Uten hjelpemetoder:

  public static void utvalgssortering(int[] a)
  {
    for (int i = a.length - 1; i > 0; i--)
    {
      int m = 0;              // indeks til den foreløpig største
      int  maksverdi = a[0];  // verdien til den foreløpig minste

      for (int j = 1; j < i; j++)
      {
        if (a[j] > maksverdi)
        {
          maksverdi = a[j];  // ny minste verdi
          m = j;            // indeksen til ny minste verdi
        }
      }
      // bytter om a[i] og a[m]
      a[m] = a[i];
      a[i] = maksverdi;
    }
  }

Oppgave 8

Hvis vi tar utgangspunkt i Programkode 1.3.4 a), blir det sortert avtagende hvis vi bytter ut min() med maks():

  public static void utvalgssortering(int[] a)
  {
    for (int i = 0; i < a.length - 1; i++)
    {
      bytt(a, i, maks(a, i, a.length));  // to hjelpemetoder
    }
  } 

Vi kan også ta utgangspunkt i versjonen fra Oppgave 6. Bruker vi variabelnavnet maksverdi istedenfor minverdi og snur ulikhet til a[j] > maksverdi, så blir det også sortert avtagende:

  public static void utvalgssortering(int[] a)
  {
    for (int i = 0; i < a.length - 1; i++)
    {
      int m = i;             // indeks til den foreløpig minste
      int  maksverdi = a[i];  // verdien til den foreløpig minste

      for (int j = i + 1; j < a.length; j++)
      {
        if (a[j] > maksverdi)
        {
          maksverdi = a[j];  // ny minste verdi
          m = j;            // indeksen til ny minste verdi
        }
      }
      // bytter om a[i] og a[m]
      a[m] = a[i];
      a[i] = maksverdi;
    }
  } 

Oppgave 9

  public static void utvalgssortering(int[] a, int fra, int til)
  {
    fratilKontroll(a.length, fra, til);

    for (int i = fra; i < til - 1; i++)
    {
      bytt(a, i, min(a, i, til));  // to hjelpemetoder
    }
  }

Oppgave 10

2 8 26 5 1 7 3 94
01234567 89
Tall fra 1 til 9 inklusive to 2-ere

I tabellen er det to 2-ere. Den første av dem har rød farge. Den minste verdien 1 ligger i posisjon 5. Den byttes med verdien i posisjon 0:

1 8 26 5 2 7 3 94
01234567 89
Den minste verdien er på rett plass

Neste skritt er å finne den minste blant de usorterte (den hvite delen). Algoritmen er laget slik at hvis det er flere, er det den første av dem vi velger. Med andre ord stopper vi på verdien 2 i posisjon 2. Den byttes med verdien i posisjon 1:

1 2 86 5 2 7 3 94
01234567 89
To av de minste er på rett plass

Så velger vi igjen den minste. Det er verdien 2 i posisjon 5. Etter byttingen blir tabellen slik:

1 2 26 5 8 7 3 94
01234567 89
Tre av de minste er på rett plass

Vi ser at de to 2-erne har byttet innbyrdes rekkefølge. Utvalgssortering er ikke stabil.

Oppgave 11

La m være posisjonen til den minste i intervallet. Hvis m = i, er ombyttingen unødvendig:

  public static void utvalgssortering(int[] a)
  {
    for (int i = 0; i < a.length - 1; i++)
    {
      int m = min(a, i, a.length);  // posisjonen til den minste
      if (m != i) bytt(a, i, m);
    }
  }

Hvis vi gjør noen små endringer i koden over, vil vi få vite antallet ganger m = i:

 public static int utvalgssortering(int[] a)
  {
    int antall = 0;
    for (int i = 0; i < a.length - 1; i++)
    {
      int m = min(a, i, a.length);  // posisjonen til den minste
      if (m != i) bytt(a, i, m);
      else antall++;
    }
    return antall;
  }

Flg. programbit (med den versjonen av utvalgssortering som står rett over) gir antallet for noen tilfeldige permutasjoner av tallene fra 1 til 10:

  for (int i = 0; i < 10; i++)
  {
    int[] a = Tabell.randPerm(10);
    System.out.print(Tabell.utvalgssortering(a) + " ");
  }

Ved en kjøring av programbiten ble resultatet slik: 4 4 1 0 3 1 2 0 0 2

Men resultatet blir forskjellig hver gang. Men hva blir gjennomsnittsverdien? Vi har 10! forskjellige permutasjoner. Det er 9! stykker som har tallet 1 først. Det betyr at i første iterasjon er sannsynligheten 1/10 for at m og i er like. I neste iterasjon vil sannsynligheten være 1/9 for at de er like. Osv. til intervallet inneholder kun to verdier. Da vil sannsynligheten være 1/2. Sammenlagt blir det 1/10 + 1/9 + · · · + 1/2. Dette er lik H10 − 1 = 4861/2520 = 1.93. Med andre ord er gjennomsnittsverdien nær 2.

Hvis tabellen inneholder tallene fra 1 til n, vil gjennomsnittet bli Hn − 1. I Avsnitt 1.1.6 fant vi at for store n er Hn − 1 ≈ log(n) – 0,423. Hvis n f.eks. er 100 000, vil det bli 11,1. Dette betyr at det overhodet ikke lønner seg å ha testen if (m != i). Den utføres hver gang (n − 1 ganger), men det er svært sjelden at m og i er like.