• No results found

Föreläsning 10 ALGORITMER MED VEKTORER: SÖKNING OCH REGISTRERING

N/A
N/A
Protected

Academic year: 2022

Share "Föreläsning 10 ALGORITMER MED VEKTORER: SÖKNING OCH REGISTRERING"

Copied!
28
0
0

Loading.... (view fulltext now)

Full text

(1)

Föreläsning 10

ALGORITMER MED VEKTORER: SÖKNING OCH REGISTRERING

(2)

Algoritmer med vektorer

(3)

Sökning: problemet

Vi skulle vilja ha en metod som söker upp ett givet tal i en vektor. Låt oss kalla den indexOf.

Om talet finns i vektorn vill vi ha reda på dess index.

Om talet inte finns får vi istället –1 (som aldrig är index) som svar.

Exempel:

int[] nbrs = new int[1000];

// vi låter nbrs få värden på något sätt

// på vilken plats ligger talet 4526?

int pos = indexOf(nbrs, 4526);

System.out.println("talet hittades på plats " + pos);

(4)

Sökning

Uppgift: Sök upp givet element i en följd av element.

Lösning: Gå igenom elementen i tur och ordning, kontrollera för varje element om det är det sökta. Avbryt om det sökta

elementet påträffats.

Algoritm (linjärsökning) i pseudokod:

i = "platsen för det första elementet"

while ("fler element kvar att söka igenom" &&

"elementet på plats i inte är det vi söker") { i = platsen för nästa element

}

(5)

Linjärsökning

/** Sök efter talet nbr i vektorn v. Om nbr finns returneras platsen för nbr, annars -1 */

public static int indexOf(int[] v, int nbr) { int i = 0;

while (i < v.length && v[i] != nbr) { i++;

}

if (i < v.length) { return i;

} else {

return -1;

} }

Att fundera på:

Varför måste delvillkoret i < v.length stå först? (Läs om short-circuit-evaluering, Think

Java Kap. 5, ”Logical Operators”.)

Att fundera på:

Varför kan man inte använda villkoret v[i] ==

nbr för att avgöra om man funnit talet nbr eller ej?

(6)

Linjärsökning, snarlik lösning. Men vad är detta?

/** Sök efter talet nbr i vektorn v. Om nbr finns returneras platsen för nbr, annars -1 */

public static int indexOf(int[] v, int nbr) { int i = 0;

while (i < v.length && v[i] != nbr) { i++;

}

return (i < v.length) ? i : -1;

}

(7)

Villkorsuttryck

Värdet av det logiska uttrycket anger vilket av de båda uttrycken som ska beräknas.

logiskt uttryck ? uttryck 1 : uttryck 2

Detta kan alltid skrivas om med if/else-satser.

Du ska emellertid förstå uttryck av detta slag när du ser dem.

Beräknas om det logiska uttrycket är falskt

Beräknas om det logiska uttrycket är sant

(8)

Linjärsökning, en variant till

Eftersom metoden inte ska göra något annat än att returnera ett index, så kan man göra det direkt om man vill.

/** Sök efter talet nbr i vektorn v. Om nbr finns returneras platsen för nbr, annars -1 */

public static int indexOf(int[] v, int nbr) { for (int i = 0; i < v.length; i++) {

if (v[i] == nbr) { return i;

} }

return -1;

}

(9)

…men varning för fel!

public static int indexOf(int[] v, int nbr) {

for (int i = 0; i < v.length; i++) { if (v[i] == nbr) {

return i;

} else {

return -1;

} } }

Varför fungerar inte det här? (Vanligt fel på tentor.)

(10)

Exempel:

klass för att representera en användare för passerkort

/** Skapar en ny användare med givet kortnummer och namn. */

User(int cardNbr, String name);

/** Hämtar användarens kortnummer. */

int getCardNbr();

/** Hämtar användarens namn. */

String getName();

User

(11)

Linjärsökning bland objekt

User[] users = new User[100];

... // Satser för att skapa 100 User-objekt

Uppgift: Sök efter användaren med kortnummer 64319 och skriv ut användarens namn.

int i = 0;

while (i < 100 && users[i].getCardNbr() != 64319) { i++;

}

if (i < 100) {

System.out.println(users[i].getName());

}

(12)

Varför fungerar inte detta?

User[] users = new User[100];

... // Satser för att skapa 100 User-objekt

Uppgift: Sök efter användaren med kortnummer 64319 och skriv ut användarens namn.

int i = 0;

while (i < 100 && ) { i++;

}

if (i < 100) {

System.out.println(users[i].getName());

}

users[i] != 64319

(13)

Andra sökalgoritmer

Linjärsökning är enkelt,

men inte alltid mest effektivt.

I en sorterad mängd är binärsökning effektivare.

Hur gör du själv när du söker upp ett tal eller ett ord i en sorterad mängd?

(14)

Binärsökning: idén

v 2 9 22 56 61 72 76 97

v 2 9 22 31 42 56 61 72 76 97

Idé: välj det mittersta av de återstående elementen. Antingen hittar vi rätt element, eller så kan vi utesluta hälften.

Exempel: Sök upp talet 61 i vektorn v.

v 2 9 22 31 42 56 61 72 76 97

v 2 9 22 31 42 56 61 72 76 97

31 42

?

?

?

!

(15)

Binärsökning: formulera algoritmen

v 2 9 22 56 61 72 76 97

mid=4

mid=5

low=5 high=6

v 2 9 22 31 42 56 61 72 76 97

Sök upp talet 61 i vektorn v.

low=0 high=9

v 2 9 22 31 42 56 61 72 76 97

low=5 mid=7 high=9

mid=6

low=6 high=6

v 2 9 22 31 42 56 61 72 76 97

Sätt mid = (low + high) / 2 Är v[mid] == 61? Nej, 42 42 < 61, så sätt low = mid + 1

Sätt mid = (low + high) / 2 Är v[mid] == 61? Nej, 72 72 > 61, så sätt high = mid – 1

Sätt mid = (low + high) / 2 Är v[mid] == 61? Nej, 56 56 < 61, så sätt low = mid + 1

Sätt mid = (low + high) / 2 Är v[mid] == 61? Ja!

31 42

(16)

Binärsökning: Java-kod

Metoden söker i int-vektorn v efter talet nbr.

Returnerar indexet om nbr hittas, annars -1.

public static int binarySearch(int[] v, int nbr) { int low = 0; // undre gräns

int high = v.length - 1; // övre gräns while (low <= high) {

int mid = (low + high) / 2; // mittpunkt if (v[mid] == nbr) {

return mid;

} else if (v[mid] < nbr) { low = mid + 1;

} else {

high = mid - 1;

} }

return -1;

}

(17)

Hur lång tid tar sökningen?

Anta att vi söker bland N element.

• Linjärsökning: t ~ N

• Binärsökning: t ~ log N

På den dubbla tiden kan vi

• linjärsöka 2N element

• binärsöka N2 element

(Tecknet ~ betyder här ”proportionellt mot”)

N

t k1 · N

k2 · log N

(18)

Registrering

(19)

Registrering

Uppgift: Räkna antal element av olika slag.

Lösning: Använd en vektor av typ int[] för att lagra de olika antalen.

Exempel: Räkna mynt.

Vi behöver en låda för enkronor, en för 5-kronor och en för 10-kronor:

int[] nbrCoins = new int[3];

enkronor 5-kronor 10-kronor

(20)

Exempel: räkna olika tärningsslag

Programmet på nästa sida räknar antalet 6:or som en tärning slår.

Hur kan man ändra detta till att samla statistik för alla

tärningens utfall, det vill säga räkna hur många 1:or, 2:or, 3:or, 4:or, 5:or och 6:or som slås?

(21)

Räkna sexor

(jämför gärna med exemplet på föreläsning 7)

public class DieTest {

public static void main(String[] args) { Die d = new Die();

Scanner scan = new Scanner(System.in);

System.out.println("Antal tärningskast: ");

int nbr = scan.nextInt();

int nbr6 = 0;

for (int i = 0; i < nbr; i++) { d.roll();

if (d.getResult() == 6) { nbr6++;

} }

System.out.println("Det blev en 6:a i " +

((double)nbr6/nbr * 100) + "% av fallen");

} }

(22)

Hur spara samtliga tärningsresultat?

int[] res = new int[6];

for (int i = 0; i < nbr; i++) { d.roll();

int a = d.getResult();

res[a - 1]++;

}

[0] [1] [2] [3] [4] [5]

res 16454 16512 16786 16725 16731 16792

antal 1:or antal 2:or antal 6:or

(23)

Exempel: registrera studenters poäng på prov

antag att vi har en klass Student:

Student

(Klassen Student innehåller säkert även en konstruktor och andra metoder – vi bortser här från dessa.)

/** Tar reda på studentens poäng på provet. */

int getPoints();

(24)

Exempel: registrera studenters poäng på prov

public class Test {

private Student[] students; // studenterna

private int n; // antalet studenter /** Skapar ett prov med plats för max studenter. */

public Test(int max) {

students = new Student[max];

n = 0;

}

/** Lägger till studenten s. */

public void add(Student s) { students[n] = s;

n++;

}

/** Skriver ut antalet studenter som har 0,1,...,50 poäng på provet */

public void printStatistics() { ... } }

(25)

Exempel: registrera studenters poäng på prov

Antag att vi vill registrera hur många som hade 0, hur många som hade 1, hur många som hade 2 poäng etc. etc. Maxpoäng är 50.

public void printStatistics() { int[] nbrs = new int[51];

for (int i = 0; i < n; i++) {

int index = students[i].getPoints();

nbrs[index]++;

}

System.out.println("Poäng\tAntal studenter ");

for (int i = 0; i < nbrs.length; i++) { System.out.println(i + "\t " + nbrs[i]);

} }

(26)

Exempel: registrera studenters poäng på prov

Antag att vi vill registrera hur många som hade 0-9 poäng, 10-19 poäng, 20-29 poäng, 30-39 poäng och 40-50 poäng. Detta är ett (nästan) regelbundet

intervall och kan därför lösas relativt enkelt.

public void printStatistics() { int[] nbrs = new int[5];

for (int i = 0; i < n; i++) {

int index = students[i].getPoints() / 10;

if (index == 5) { // specialfall: om 50 poäng index = 4;

}

nbrs[index]++;

}

// ... skriv ut antalen }

(27)

Exempel: registrera studenters poäng på prov

Tänk istället att 0-24 poäng ger U, 25-34 poäng betyg 3, 35-42 poäng betyg 4 och 43-50 poäng betyg 5. Då har vi ett oregelbundet intervall som vi får hantera

annorlunda.

Antalet U-betyg registreras i nbrs[0], antalet 3-betyg i nbrs[1], osv.

int[] nbrs = new int[4]; // plats för U, 3, 4, 5 //För varje student

int points = students[i].getPoints();

int index;

if (points < 25) { index = 0;

} else if (points < 35) { index = 1;

} else if (points < 43) { index = 2;

} else {

index = 3;

}

nbrs[index]++;

(28)

References

Related documents

Sökanden eller andra nyttjanderättshavare till bostaden kommer inte att krävas på ersättning för återställning av anpassningsåtgärderna. Sökta åtgärder får

Den grupp som spelade den abstrakta versionen utan återkopplingar till det förkonstruerade narrativet gjorde i sitt återberättande fler referenser till det

Att som i exemplet ovan best¨ amma den st¨ orsta gemensamma delaren till tv˚ a tal genom att f¨ orst best¨ amma alla delarna till de b˚ ada talen verkar inte vara n˚ agon

ü Anod: Anoden utgörs av den metall som lättast oxideras (avger elektroner) och bildar joner.. Anoden har ett elektronöverskott jämfört

§ Hos galvaniska element med metallelektroder (det finns andra varianter också) så är det positiva joner i elektrolytlösningen runt katoden som tar emot de elektroner som

mitten av bägaren ligger stålull som består av rent järn (Fe). De negativa jonerna har ingen funktion i detta exempel så de lämnas utanför. Båda metalljonerna vill ha fullt

Material 1 M kopparsulfat, 1 M zinksulfat, 1 M Kaliumklorid Utförande Bygg ett galvaniskt element enligt figuren2. Koppla

Igenom att göra dessa förändringar och tillägg på denna tomt så kommer den att kunna används mer och bättre utav alla boende i området, min tanke är att detta kommer att bli