TDDC30
Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 7
Jonas Lindgren, Institutionen för Datavetenskap, LiU
På denna föreläsning:
•
Bubblesort, Shakersort, Mergesort
•
Strömmar, Datum, Formatering
1
Hittills, och vidare!
• Objektorientering och Java
• Objekt, klasser, instanser
• Arv, polymorfism
• Dölj implementationen
• Private/Public (inkapsling)
• Abstrakta datatyper (ADT)
• Datastruktur med algoritmer
• Listor, köer och stackar
• Gränssnitt vs implementation
• Analys av algoritmer
• Komplexitet: tids-, rums• Fallstudie: Sorteringsalgoritmer
100
50
2
0
0
10
20
Bubblesort
• Jämför med närliggande element
• Start från höga index
void bubbleSort(int[] a) {
for (int i = 0; i < a.length; ++i) {
for (int j = a.length-1; j > i; --j){
n
if (a[j] < a[j-1]) {
byt plats på a[j] och a[j-1];
}
}
}
}
O(n2)
• Asymptotisk (tids)komplexitet?
Ja
• Stabil?
Låg
”overhead”
n2
3
Shakersort
• Tvåvägs bubblesort
•
•
•
•
Små element bubblar upp
Stora element sjunker ner
Fram och tillbaka
Jämför med närliggande element
• Bubbla ner eller bubbla upp
• Gör om för varje element
• Tshakersort?
• Stabil?
O(n2)
Ja
O(n)
O(n)
4
Kort om rekursion
Ibland när man delar upp ett problem, uppstår samma problem
igen!
T.ex.
N! = 1 * 2 * 3 * … kan även skrivas:
N! = 1 då N = 0,
N * (N-1)! annars
I java kan en metod anropa sig själv!
int fak(int N) { N : 2
if (N == 0) {
return 1;
}
return N * fak(N-1)
2=2*1
}
svar = fak(2);
int fak(int N) {N : 1
if (N == 0) {
return 1;
}
return N * fak(N-1)
1=1*1
}
int fak(int N) { N : 0
if (N == 0) {
5
return 1;
}
return N * fak(N-1)
}
”Divide and Conquer”
(sv. söndra och härska)
En rekursiv strategi:
1. Om datamängden är liten, lös direkt (härska).
2. Annars: dela upp datamängden (söndra) och applicera
söndra och härska (rekursivt) på varje del.
3. Sammanfoga lösningarna för varje del till lösningen för
hela.
6
Mergesort
Strategi:
”Divide and conquer”: Tag två sorterade delmängder och sortera
ihop dessa.
Algoritm:
Då mängden innehåller 0 eller 1 element:
• Redan sorterad => Klart!
Annars:
• Dela upp mängden i två lika stora delar och sortera dessa
• Med mergesort! (rekursion)
• Sortera ihop dessa två delar (en. Merge)
7
Mergesort(2)
• Utnyttjar att det krävs få jämförelser att sortera små mängder
• Vanlig optimering: Byt ut sorteringsalgoritmen när
delmängden är tillräckligt liten!
Komplexitet:
• Antal uppdelningar av arrayen
• Mergar på varje nivå
O(log(n))
O(n)
Tmergesort = O(log(n)) * O(n) = O(nlog(n))
Rmergesort = O(n)
Stabil?
(O(1) möjlig men impl. ger dålig prestanda)
Ja (om sammanslagningsalgoritmen är väl vald)
8
Sammanfattning
• Kvadratiska algoritmer
•
•
•
•
Insertionsort
Selectionsort
Bubblesort
Shakersort
• Mer avancerade algoritmer
• Shellsort
• Mergesort
• Quicksort
Enkla,
långsamma
Komplexa,
snabba
9
In- och utmatning
Definition: En ström (en. Stream) är en
sekvens av data från någon källa och/eller
till något mål.
• In och utmating i Java utförs av strömmar
Vanliga exempel
• System.out (av klassen PrintStream)
• Vanligen kopplad till terminalen
• System.err (av klassen PrintStream)
• Vanligen kopplad till terminalen
• System.in (av klassen InputStream)
• Vanligen ihopkopplad med annan ström som formaterar indatat, ex.
BufferedReader, BufferedLineReader, Scanner
10
In- och utmatning(2)
Exempel
// connect reader to inputstream
BufferedReader input = new BufferedReader(
new InputStreamReader(System.in));
// read a line and convert to int
int num = Integer.parseInt(input.readLine());
…
// open file for reading
FileInputStream stream = new FileInputStream(
new File("test.txt"));
Scanner scanner = new Scanner(stream);
// read from file
System.out.println(scanner.nextInt());
11
Formatering
• Ofta vill man skriva ut på en viss form
double d = 10.0/3.0;
System.out.println(d); // 3.3333333333333335
• Metoden format i PrintStream kan hjälpa till:
System.out.format("Värdet %1.2f är bra grejor.\n", d); // 3,33
Locale.setDefault(Locale.UK);
// format adjust itself by looking at default locale!
System.out.format("The value %1.2f is indeed good\n.", d); // 3.33
12
Formatering(2)
• Formatspecificerare är på följande form:
%[flagga][bredd]typ
Typ
Förklaring
Flaggor
Förklaring
d
Heltal, decimal
form
-
Vänsterjustering
x
Heltal,
hexadecimal
form
+
Talets tecken
skrivs ut
f
Reellt tal,
decimalform
blankt
Positivt tal
inleder med
blank
e
Reellt tal,
exponentform
,
Siffrorna
grupperas tre och
tre
Fler specificerare finns, se Javas API-dokumentation
13
Datum och tid
• Klassen Date sparar en tid
// num = number of milliseconds since Jan 1, 1970
Date date = new Date(num);
• Klassen Calendar är mer användbar, och kan ta fram
nuvarande tid som ett Date.
Calendar cal = Calendar.getInstance();
System.out.format("The time is: %tc \n", cal.getTime());
int minute = cal.get(Calendar.MINUTE);
14
Datum och tid(2)
• DateFormat: en (abstrakt) klass som formaterar datum åt oss
DateFormat time = DateFormat.getTimeInstance();
DateFormat date = DateFormat.getDateInstance();
Date now = Calendar.getInstance().getTime();
// note that this is locale dependent
System.out.println(time.format(now)); // 13:37:00
System.out.println(date.format(now)); // 2012-nov-14
(Mer kontroll? SimpleDateFormat!)
15
Scanner
• Scanner: En klass som hjälper oss att hantera inmatning
• Kopplas mot en InputStream
// example usage of scanner
Scanner keyboard = new Scanner(System.in);
while (keyboard.hasNextInt()) {
myList.add(keyboard.nextInt());
}
16
Hantering av strömmar
• Filer läses som strömmar
• För textfiler, använd FileReader resp. FileWriter
String filename = "myfile.txt";
FileReader reader = new FileReader(new File(filename));
Scanner scanner = new Scanner(reader);
//...
scanner.close(); // always close your streams!
scanner.nextInt(); // error, since scanner + stream is now closed
17
Hantering av (binära) datafiler
• För binära filer, använd DataInputStream resp. DataOutputStream
String filename = "myfile.dat";
DataInputStream input;
try {
input = new DataInputStream(new FileInputStream(filename));
while (true) {
System.out.println(input.readInt());
}
} catch (EOFException e) {
System.out.println("Something went wrong while reading:");
e.printStackTrace(); // print the details!
} finally {
input.close(); // always close!
}
18
Serialisering
• Det går att spara objekt på fil mellan körningar
• Java kan ”platta till” ett objekt till en sekvens av bytes
• Perfekt för att spara
• Använd strömmarna ObjectInputStream och ObjectOutputStream
• Kräver att klassen implementerar interfacet Serializable
Object readObject(); // casting is needed to be usable
void writeObject(Object o);
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream(new File("test.dat")));
out.writeObject(new Cat("Isaac", 11)); // if Serializable!
out.writeObject("Hejsan"); // String is Serializable
19