Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
Tobias Wrigstad
1
Datatyper
Det finns flera olika typer av (slags) data Olika datatyper har olika egenskaper. T.ex.
är ett personnummer inte ett tal. (Den sista siffran skall stämma enligt den s.k. Luhnalgoritmen och bindestrecket har en mening och ersätts faktiskt med ett plustecken
när en person blir över hundra år; om det är ett temporärt personnummer kan det ha
en bokstav i sig).
Vanliga datatyper Heltal (int, integer), flyttal (float) , strängar (string), booleska värden
(bool), listor, dictionaries samt ”objekt” (mer om dessa på senare kurser).
En literal är en textuell representation av ett värde i Python-koden, t.ex. strängen
"Hej", talet 1.001232, listan [1,2,3] och det booleska värdet True. Nedanstående
tabell visar datatypen för olika literaler:
int (heltal) 1
float (flyttal) 1.0
str (sträng) Foo"
bool (boolean) False
list (lista) [3,5,7,11]
dict (dictionary) { "Foo" : "Bar" }
Datatyper i Python Python har många olika slags datatyper (http://docs.python.
org/3.1/reference/datamodel.html#objects-values-and-types). De viktiga på
denna kurs är de ovan.
2
Minne
Datorns primärminne är begränsat. Detta är inte så viktigt för oss på den här kursen utan
blir det först på senare kurser. Varje värde, t.ex. siffran 4711, i ett program ligger på en
plats i minnet och varje variabel i ett program ”pekar på” en plats i minnet där ett värde är
sparat. Man kan likna datorns minne vid ett rutnät där varje ruta har en viss adress (t.ex.
med ett löpnummer, 0, 1, 2, 3, . . . ). Varje värde i ett program ligger på en plats i rutnätet.
När man tilldelar ett värde till en variabel sparas den adress där värdet ligger på i variabeln1 ,
inte själva värdet. Man säger att variabeln pekar på ett värde, d.v.s., att den pekar ut den
plats (den adress) i minnet där värdet ligger. I Python är dessa adresser helt dolda för
programmeraren och kan inte manipuleras.
3
Identitet och Ekvivalens
Att två värden är identiska innebär att de är samma värden. Alla 2:or i ett Python-program
är t.ex. identiska – det finns bara en enda 2:a i språket, även om den kan förekomma på
många olika ställen i ett program. Identitet kan enkelt prövas genom att man ser på vilken
1 Detta
varierar med språk och även inom samma språk och blir viktigt först senare.
1 av 6
Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
plats i minnet två värden är sparade. Om de är sparade på samma plats i minnet är de
samma värde och är följaktligen identiska. Två värden som är identiska är automatiskt
också ekvivalenta, se nedan.
Att två värden är ekvivalenta innebär att de är likadana. T.ex. är två olika listor som
innehåller samma värden, t.ex. [1,2,3] och [1,2,3] ekvivalenta. Om listorna ovan inte är
identiska, kan man ta bort ett element ur den första listan utan att den andra påverkas.
Gör man detta upphör listorna att vara ekvivalenta.
Man skiljer ofta mellan värden som kan förändras (eng. mutable values) och värden som inte
kan förändras (eng. immutable values). Ett exempel på ett värde som inte kan förändras är
talet 2. Talet 2 kan inte ändras, då blir det ju ett annat tal! En konsekvens av detta är att
alla 2:or i Python avser samma 2:a, vilket t.ex. sparar minne. Se här:
tal = 2
x = tal
print tal
# skriver ut
tal = tal + 1
print tal
# skriver ut
print x
# skriver ut
print 2
# skriver ut
2
3
2
2
Vid den första tilldelningen till tal stoppas ett heltal av värde 2 in i tal-variabeln. Samma
gäller för tilldelningen till x. Notera att tal och x innehåller samma 2:a. Ofta används
termerna ”pekar på” och ”refererar till” istället för ”innehåller.”
Vid den andra tilldelningen till tal skrivs 5:an över med ett nytt heltal av värde 3. Skriver vi
ut innehållet i tal-variabeln skrivs en 3:a ut, medan innehållet i x-variabeln är oförändrat.
Värdet 2 är också oförändrat.
Samma sak gäller även för bl.a. flyttal, booleska värden, enskilda tecken och strängar.
För mer komplicerade datatyper, som listor, är det dock annorlunda. En lista kan modiferas
(t.ex., element tas bort eller läggas till, eller sorteras om).
list1 = [1,2,3,4]
list2 = list1
print list1
print list2
list1.remove(3) # ta bort sista elementet
print list1
print list2
Vid tilldelningen till list2 sätts denna att ”peka på” samma lista som list1. Listan
[1,2,3,4] finns alltså i två variabler samtidigt. Vi säger att variablerna list1 och list2
är ”alias” och att listan som de innehåller är ”aliaserad.”
Att detta är ett viktigt koncept är uppenbart vid utprintningen av list22 . Eftersom variablerna pekar på samma lista kommer förändringen av listan via list1 också att påverka
list2.
2 Tobias avhandling, ”Owner-Based Alias Management” (Wrigstad, 2006), handlar också om detta koncept.
2 of 6
Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
Python har två operatorer för att jämföra data, == och is. Den första testar om objekten är
ekvivalenta (likadana) och det andra om de är identiska (samma). Vad detta betyder torde
vara uppenbart om man läser nästa program:
list1
list2
print
print
print
print
print
4
= [1,2,3]
= [1,2,3]
list1 == list2
list1 is list2
5 == (4+1)
5 is (4+1)
[] is []
#
#
#
#
#
#
#
Skapar en lista med elementen 1, 2 och 3
Skapar en ny (annan) lista med samma element
True
False
True
True
False
None: avsaknaden av ett värde
Det speciella värdet None avser avsaknaden av ett värde3 . Det används ofta som ett initialt
värde i en variabel som ännu inte har tilldelats sitt riktiga värde. T.ex.:
biggest = None
if a < b:
biggest = b
else:
biggest = a
print biggest
Här används None i variabeln biggest i betydelsen ”vi vet inte ännu.” Efter villkorssatsen
kommer dock biggest att ha fått sitt slutgiltiga värde.
5
Datastrukturer
En datastruktur är en struktur som innehåller ett eller flera värden organiserat på ett visst
sätt. En datastruktur kan innehålla flera andra datastrukturer, t.ex., ”en lista av listor.”
5.1
Mängder och element
En mängd är en oordnad samling diskreta (d.v.s. olika) element, t.ex. alla studenter på
DVK. En mängd skrivs normalt med kommaseparerade element mellan ”krullparenteser,”
d.v.s.:
{ 2, 3, 5, 7, 11 }
är mängden av alla primtal4 mindre än eller lika med 11. Den tomma mängden skrivs
normalt ∅, men kan även skrivas { }.
Att ett element är med i en mängd betecknas normalt ∈, t.ex.
3 ∈ { 1, 2, 3, 4, 5 }
samt, för icke-tillhörighet, 6∈, d.v.s.,
6 6∈ { 1, 2, 3, 4, 5 }.
3 Att
jämföras med null i Java.
primtal är ett heltal som inte går att jämnt dela med ett annat heltal. 4 är inte ett primtal eftersom
4 = 2 × 2, d.v.s. 4 är jämnt delbart med 2. Primtal är inte intressanta för oss under denna kurs.
4 Ett
3 of 6
Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
I Python finns mängder tillgängliga via datatypen set. Nedanstående kodsnutt skapar en
tom mängd och lägger till elementen 1, 3 och 5 i den.
my_set = set()
my_set.add(1)
my_set.add(3)
my_set.add(5)
Man kan också skapa motsvarande mängd ”direkt,” så här: set([1,3,5]).
5.2
Lista
Listan är en av de mest grundläggande datatyperna. En listas element är ordnade. Detta
betyder att varje element i listan har ett index, d.v.s., en speciell plats i listan, och att det
för varje element finns, utantaget första och sista elementen, ett föregående element och ett
efterföljande element i listan. Det betyder också att man vid insertering måste bestämma var
i listan (längst fram, längst bak, mellan två element) man vill stoppa in det nya elementet.
I en homogen lista har alla element samma datatyp, t.ex., i listan [1,2,3,4,5,6] är alla
elementen heltal. I en heterogen lista kan man blanda element av olika datatyp, t.ex. [grodan
boll", 23, False].
En lista kan skapas på många sätt:
• Som en literal: [0,1,2,3,4]
• Med funktionen range(from, upto): range(0,5) (skapar [0,1,2,3,4])
• Incrementellt:
1
2
3
4
5
6
list = []
# initialt värde på listan
list.append(0)
list.append(1)
list.append(2)
list.append(3)
list.append(4)
Notera att append lägger till nya element sist i listan. Alltså, list.append(0) lägger till en
0:a på sista positionen i listan, vilket i detta skede är samma som först elementet eftersom
listan är tom.
I sitt ”vaniljutförande” kan man stoppa in element i en lista på godtycklig plats, t.ex.:
1
2
3
4
5
6
7
8
list = [1,2,3]
print list
list.insert(0,4)
print list
# [4,1,2,3]
list[3] = 8
print list
# [4,1,2,8]
list[3:4] = [7,9,10]
print list
# [4,1,2,7,9,10]
4 of 6
Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
Senare kurser kommer att skilja på olika slags listor och hur listan är uppbyggd i datorns
minne. Vissa slags listor är bra för datamängder som växer och krymper hela tiden, medan
andra listor är bra för att snabbt komma åt ett element som man vet platsen på. Etc.
Element på godtyckling plats i en lista kan tas bort direkt, t.ex.:
list = [1,2,3]
list.pop(0)
print list
list.remove(3)
print list
#
#
#
#
tar bort elementet med index 0
skriver ut [2,3]
tar bort första förekomsten av 3 i listan
skriver ut [2]
Notera att ett element kan förekomma flera gånger i en och samma lista, t.ex., [1,1,1,2,1,2].
5.3
Stack
En stack är en lista som har en s.k. LIFO-struktur (Last in, first out). En stack kan bara
manipuleras med operationerna push som lägger något överst på stacken, och pop som tar
bort det översta elementet (och returnerar det).
Ett exempel på en stack är en hög med tallrikar i ett kök. Enda sättet att lägga till en ny
tallrik är att pusha den, d.v.s., lägga den överst i högen. Vill man lägga till något näst överst
får man först poppa av den första tallriken, lägga den nya överst med push och sedan lägga
tillbaka det föregående första elementet igen.
5.4
Kö
En kö är en lista som har en s.k. FIFO-struktur (First in, first out) och modellerar på så sätt
t.ex. en kassakö i en matvarubutik. En kö manipuleras med operationerna enqueue (lägg till
något sist i kön) och dequeue (ta bort det första elementet i kön).
En kö kan vara bra att använda istället för en lista om man t.ex. har order i ett ordersystem
som tillämpar ”först-till-kvarn-systemet.” Om man alltid betjänar den order som är först i
kön och lägger nya ordrar sist i kön är det en FIFO-kö.
5.5
Dictionary (Map)
Kallas också för en ”associativ array.” En mängd ordnade par där första elementet i varje
par är diskret. Man säger att det första elementet i paret är associerat med det andra, eller,
vanligare, att det första elementet ”mappar till” det andra. Det första elementet kallas för
en nyckel och det andra för ett värde.
Inom matematiken skrivs en map ofta på detta sätt:
{ A 7→ 1, B 7→ 2, C 7→ 3 }
där A 7→ 1 är ett par där A är nyckeln och 1 är värdet. Nyklarna och värdena kan vara av
godtycklig datatyp, d.v.s., kan vara heltal, strängar, listor, etc.
Exempel på en map är en telefonkatalog där varje unikt namn (nyckel) är associerat med
ett telefonnummer (värde). Dock ej tvärtom, eftersom ett telefonnummer kan delas av flera
personer som bor på samma adress.
Ett dictionary skapas så här i Python:
5 of 6
Föreläsningsanteckningar, Introduktion till datavetenskap
HT 2009
S4 – Datastrukturer
phone_book = { "Henrik" : 161611, "Beatrice" : 164988 }
För att slå upp något i dictionariet använder vi samma uppslagningsoperator som för listor,
med skillnaden att vi inte letar med hjälp av index utan med nycklar:
henriks_number = phone_book["Henrik"]
print henriks_number # skriver ut 161611
För att uppdatera ett dictionary använder man följande syntax:
phone_book["Stefan"] = 161621 # lägger till Stefan i listan
phone_book["Henrik"] = 162000 # ändrar henriks nummer till 162000
I det första fallet utökas dictionariet med en ny map från Stefan till 161621. Den resulterande
mappen ser då ut så här:
phone_book = { "Henrik" : 161611, "Beatrice" : 164988, "Stefan" : 161621 }
Efter uppdateringen av Henrik så ser mappen ut så här:
phone_book = { "Henrik" : 162000, "Beatrice" : 164988, "Stefan" : 161621 }
Man kan få tag i alla nycklar i ett dictionary med hjälp av metoden keys() enligt följande:
phone_book.keys() = ["Beatrice", "Stefan", "Henrik"]
I Python är nyklarna inte ordnade utan kan komma ut i vilken ordning som helst. På så
sätt kan vi alltså skriva ut alla namn och telefonnummer i vårt dictionary enligt följande:
names = phone_book.keys()
for name in names:
print name, "has number", phone_book[name]
6 of 6