Peruskäsitteitä ja lineaariset perustietorakenteet

Tietorakenteet ja algoritmit
Lineaariset perustietorakenteet
Ari Korhonen
15.9.2015
Tietorakenteet ja algoritmit Y
1
2.
TIETORAKENTEIDEN TOTEUTUSPERIAATTEITA
•  Peruskäsitteitä
•  pieni kertaus ohjelmoinnin peruskäsitteistä
•  taulukko
•  linkitetty lista
•  esimerkkejä (polynomin toteutus)
•  abstraktit tietotyypit
15.9.2015
Tietorakenteet ja algoritmit Y
2
2.1 Peruskäsitteitä / Muuttujat
§ 
Muuttujiin talletetaan dataa
§ 
Muuttujiin liittyy tunnus, osoite ja tyyppi
§ 
Muuttuja voi olla yksinkertainen tai rakenteinen
§ 
Muuttujalla on jokin rooli ohjelman suorituksessa
int count;
double sum;
Sortable table[1000];
§ 
/* count: askeltaja */
/* sum: kokooja */
/* table: järjestelijä */
Vakiot ovat arvoja, joita ei voi muuttaa
final int SIZE = 100; (Java)
#define SIZE 100
(C)
SIZE = 100
(Python)
15.9.2015
Tietorakenteet ja algoritmit Y
3
2.1 Peruskäsitteitä / Muuttujat
§ 
Alkeistyyppejä vai tietorakenteita?
§  esim. Double-precision floating-point format (Wikipedia)
§ 
1
2
3
4
5
15.9.2015
esim. integer Pythonissa
struct _intblock {
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;
Tietorakenteet ja algoritmit Y
4
2.1 Peruskäsitteitä / Muuttujat
§ 
Datan lisäksi muuttuja voi sisältää myös osoitteen toiseen
muuttujaan:
double sum = 0;
double *p;
p = &table[0];
for (int i = 0; i < 1000; i++) {
sum += *p;
p=p+1;
}
§ 
15.9.2015
/* p: askeltaja */
/* table: järjestelijä */
/* i: askeltaja */
Sama kuin
double sum = 0;
for (int i = 0; i < 1000; i++)
sum += table[i];
§ 
/* sum: kokooja */
/* sum: kokooja */
/* i: askeltaja */
/* table: järjestelijä */
Tässä esimerkissä osoitinten käyttö tarpeetonta, mutta C-kielessä
esim. merkkijonoja käsitellään usein osoittimien avulla.
Tietorakenteet ja algoritmit Y
5
2.1 Peruskäsitteitä / Muuttujat
§ 
15.9.2015
Osoitinmuuttujien suurin merkitys on mahdollisuus luoda ja
käsitellä dynaamisia tietorakenteita, esim. linkitettyjä listoja tai
puita.
§ 
Rakenteen solmut ovat muuttujia, joihin viitataan
osoitinmuuttujien avulla.
§ 
Solmuja voidaan luoda tarpeen mukaan ja niiden keskinäistä
järjestystä voidaan vaihtaa.
§ 
C-kielessä osoitinten käsittely on eksplisiittistä.
§ 
Javassa ja Pythonissa rakenteet toteutetaan luokkien ja olioiden
avulla. Luokka-tyyppinen muuttuja on itse asiassa osoitin
muistissa olevaan olioon
§  vrt. SortableKey x; vs. new SortableKey();!
§ 
Tärkeä erikoistapaus on tyhjä osoitin NULL.
Tietorakenteet ja algoritmit Y
6
2.1 Peruskäsitteitä / Tyypit
§ 
Tyypit jaetaan alkeistyyppeihin ja rakenteisiin tyyppeihin
§ 
Alkeistyyppejä ovat kokonaisluvut (int), reaaliluvut (double),
merkkitieto (char) ja looginen tieto (boolean)
§ 
Rakenteista tyyppiä olevat alkiot koostuvat alkeistyypeistä,
esimerkiksi taulukot, tietueet, oliot
§ 
Rakenteisten tyyppien alkiot voivat olla myös muita rakenteisia
tyyppejä. Rakenteet voivat olla mielivaltaisen monimutkaisia ja
monitasoisia.
§ 
Taulukot ja tietueet ovat luonteeltaan staattisia tietorakenteita.
§ 
§ 
§ 
15.9.2015
Niiden koko on sidottu määrittelyyn
On olemassa myös dynaamisia taulukoita
Dynaamiset tietorakenteet luodaan osoitinmuuttujien avulla (C)
tai oliorakenteina (Java, Python).
Tietorakenteet ja algoritmit Y
7
2.1 Peruskäsitteitä / Ohjelman suoritus
§ 
Ohjelman suorittamat toiminnot määritellään:
§ 
Muuttujalle voidaan sijoittaa uusi arvo.
§ 
Lausekkeissa lasketaan jokin arvo
§ 
§ 
§ 
15.9.2015
Lausekkeella voi olla myös sivuvaikutuksia muuttujien
arvoihin
Kontrollilauseet ohjaavat suoritusjärjestystä
§ 
Ehtorakenteet (if - else, switch)
§ 
Toistorakenteet (for, while-do, do-while)
Isommat kokonaisuudet lasketaan usein funktioiden,
proseduurien tai metodien avulla. Laskentaa ohjataan
parametreilla.
Tietorakenteet ja algoritmit Y
8
2.2 Yleistä tietorakenteista
§ 
Tietorakenne voidaan luokitella kahdella tasolla
§ 
Talletusrakenne on rakenne, joka sisältää joukon dataalkioita jollain tavalla talletettuna (esim. peräkkäin)
ottamatta kantaa alkioiden sisältöön
§  Esim. taulukko, linkitetty lista, binääripuu
§ 
Abstrakti tietotyyppi (ADT) määrittelee tietotyypin, joilla on
jokin semanttinen merkitys (tarvittavat operaatiot)
§  Esim. hakemisto, prioriteettijono
§ 
Abstraktit tietotyypit (määritellyt operaatiot) toteutetaan
talletusrakenteiden avulla
§  Esim. haetaan jokin alkio, jolla on tunniste (avain) tai
lisätään tiettyä avainta vastaava alkio rakenteeseen
15.9.2015
Tietorakenteet ja algoritmit Y
9
2.2 Yleistä…
§ 
Tietorakenne on lineaarinen, jos kaikki sen alkiot on
ryhmitetty peräkkäin.
§ 
§ 
15.9.2015
taulukko, linkitetty lista, pino, jono
Tällaista rakennetta voidaan käyttää esim.
• 
yksinkertaisena hakurakenteena,
• 
tilapäisenä tallennusrakenteena.
Tietorakenteet ja algoritmit Y
10
2.2 Yleistä…
Tietorakenne on staattinen, jos sille varattu muistitila on
vakiokokoinen.
Tietorakenne on dynaaminen, jos tietorakenteen koko tai
muoto voi vaihdella.
§ 
§ 
Mikä seuraavista on staattinen,
mikä dynaaminen tietorakenne?
• 
• 
• 
• 
• 
• 
Taulukko
Tietue
Dynaaminen taulukko
Linkitetty lista
Verkko
Binääripuu
Muistinvaraus kiinteä tai dynaaminen
15.9.2015
Tietorakenteet ja algoritmit Y
11
2.2 Yleistä…
§ 
Monet ohjelmointikielet tarjoavat valmiina joukon erilaisia
tietorakenteita ja abstrakteja tietotyyppejä joko itse kielen
rakenteina tai kirjastojen avulla toteutettuna
§ 
C:
Taulukko, dynaaminen taulukko
§ 
Java:
ArrayList, Map, HashMap, …
§ 
Python: Dictionary, List, Tuple, …
§ 
Monia asioita ei tarvitse toteuttaa itse, vaan voi käyttää
valmiita kirjastoissa olevia toimintoja.
§ 
On tärkeää ymmärtää, mitä tekee, koska erilaisia
tietorakenteilla on erilaisia ominaisuuksia, jotka vaikuttavat
suurestikin tehokkuuteen.
15.9.2015
Tietorakenteet ja algoritmit Y
12
2.2 Yleistä…
Alkion saavutettavuus talletusrakenteissa:
Mitä eroa?
• 
Taulukko
• 
Tietue
• 
Linkitetty lista
• 
Binääripuu
• 
Verkko
Alkion paikka voidaan laskea vakioajassa tai sitten ei.
15.9.2015
Tietorakenteet ja algoritmit Y
13
2.2 Yleistä…
Abstraktiotaso
Mitä eroa?
*
+
• 
Binääripuu
• 
Jäsennyspuu
• 
Binäärinen hakupuu
• 
Taulukko
• 
Hajautustaulukko
1
D
3
2
A
B
G
C
Talletusrakenne vai semanttinen rakenne:
§ 
15.9.2015
Rakenne voi olla puhdas talletusrakenne tai
abstrakti tietotyyppi, jolla on jokin semantiikka
Tietorakenteet ja algoritmit Y
14
2.3 Taulukko
§ 
Kuuluu yleisimpien ohjelmointikielten perusrakenteisiin
§ 
Alkiot indeksoidaan ensimmäisestä viimeiseen.
§ 
Mihin tahansa alkioon voidaan heti viitata.
§ 
Taulukon alkioiden väliin ei voi lisätä uutta alkiota eikä sieltä
voi poistaa alkiota.
⇒  Rakenne on erittäin jäykkä, jos tällaisia toimintoja
(päivityksiä) tarvitaan.
Joissakin ohjelmointikielissä on taulukon tapaisia rakenteita,
joissa näennäisesti voidaan tehdä asioita joustavasti, mutta
tehokkuuden hinnalla (esim. Javan ArrayList)
!
15.9.2015
Tietorakenteet ja algoritmit Y
15
Taulukko…
§ 
Taulukon määrittely C-kielessä:
§ 
§ 
< type > < name >[<number of elements>]
esim.
§ 
int numbers[10];
numbers[5] = 1;
!
indeksointi alkaa nollasta (0 - N-1)
§ 
Moniulotteiset taulukot
§ 
Dynaaminen taulukko
15.9.2015
Tietorakenteet ja algoritmit Y
16
2.4 Linkitetyn listan (linked list) toteutus
§ 
Lista toteutetaan tyypillisesti osoitinmuuttujien ja
dynaamisen muistinvarauksen avulla.
§ 
Voidaan toteuttaa myös pelkän taulukon avulla
§ 
Tyypillinen määrittely C-kielessä:
struct node {
int data;
struct node * next;
};
typedef struct node * ListNode;
ListNode p, q, r;
Esimerkkilista:
p
20
10
13
11
K2.1
15.9.2015
q ja algoritmit Yr
Tietorakenteet
17
§ 
Eräs määrittelytapa Java-kielessä:
class ListNode
{
int data;
ListNode next;
ListNode(int data)
{
this.data = data;
this.next = null;
}
}
ListNode p, q, r;
p
20
10
13
K2.1
Esim.
15.9.2015
11
q
r
Tietorakenteet ja algoritmit Y
18
§ 
Alkion lisääminen on helppoa, kun käsillä on osoitin
siihen alkioon, jonka jälkeen uusi alkio sijoitetaan
p
20
10
13
11
K2.3
(C)
q
r = malloc(sizeof(node));
r->data = 99;
r->next = q->next;
q->next = r;
(Java)
r = new ListNode(99);
r.next = q.next;
q.next = r;
p
20
10
13
11
K2.3
q
r
15.9.2015
99
r
Tietorakenteet ja algoritmit Y
99
19
Alkion poistaminen käy helposti, kun on käsillä osoitin
poistettavaa alkiota edeltävään alkioon:
(C)
(Java)
r = q->next;
q->next = r->next;
free(r);
r = q.next;
q.next = r.next;
p
20
10
13
11
K2.2
q
r
Miten poistaa ensimmäinen alkio?
15.9.2015
Tietorakenteet ja algoritmit Y
20
§ 
Header-alkion ansiosta myös ensimmäinen alkio voidaan
poistaa samalla koodinpätkällä kuin muutkin.
p
head
20
10
13
11
K2.4
§ 
Samasta syystä (erikoistapausten välttäminen) toisinaan
määritellään listan loppuun ylimääräinen alkio z, josta on
viittaus itseensä (Sedgewick: Algorithms)
p
head
20
10
13
z
K2.5
Listan loppumisen tarkastaminen:
if (q == q->next) ...; TAI if (q == z) ...
15.9.2015
Tietorakenteet ja algoritmit Y
21
Esimerkkejä listan käsittelyfunktioiden toteuttamisesta (C):
void print_list(ListNode head) {
ListNode list;
/*
list: kulkija */
list = head->next;
if (list == z)
printf("List is empty\n");
else {
while (list != z) {
printf("%d ”, list->data);
list = list->next;
}
printf("\n");
}
}
15.9.2015
Tietorakenteet ja algoritmit Y
22
Lisää listan alkuun:
void insert(ListNode head, int key)
{
ListNode temp;
/* temp:
temp = get_node(); // malloc
temp->data = key;
temp->next = head->next;
head->next = temp;
tilapäissäilö */
/* temp->data: kiintoarvo */
/* temp->next: kiintoarvo */
/* head->next: tuoreimman säilyttäjä */
}
15.9.2015
Tietorakenteet ja algoritmit Y
23
Esimerkkejä listan käsittelyfunktioiden toteuttamisesta (Java):
public void print_list(ListNode head){
ListNode list;
/* list:
kulkija */
list = head.next;
if (list == z)
System.out.println("List is empty");
else {
while (list != z) {
System.out.print(list.data+" ");
list = list.next;
}
System.out.println();
}
}
15.9.2015
Tietorakenteet ja algoritmit Y
24
class LinkedList {
ListNode header;
ListNode z = new ListNode(null);
/* kiintoarvo */
/* kiintoarvo */
LinkedList ()
{
header = new ListNode(null);
header.next = z;
/*
}
tuoreimman säilyttäjä */
addFirst(int element)
{
ListNode temp;
/* tilapäissäilö
temp = new ListNode(element);
temp.next = header.next;
/* kiintoarvo */
header.next = temp;
}
*/
}
15.9.2015
Tietorakenteet ja algoritmit Y
25
Etsi alkio:
ListNode search(ListNode head, int key)
{
ListNode list;
/* node: kulkija */
list = head->next;
z->data = key;
/* z->data: kiintoarvo, ”vartiosotilas” */
while (list->data != key)
list = list->next;
return (list);
}
15.9.2015
Tietorakenteet ja algoritmit Y
26
boolean delete(ListNode head, int key){
ListNode current, previous;
z->data = key;
/* z->data: kiintoarvo, ”vartiosotilas” */
current = head->next; /* current: kulkija */
previous = head;
/* previous: seuraaja, ”current->previous”
*/
while (current->data != key) {
previous = current;
current = current->next;
}
if (current != z) {
previous->next = current->next;
free (current);
return (TRUE);
} else
return (FALSE);
}
15.9.2015
Tietorakenteet ja algoritmit Y
27
§ 
Lista voidaan toteuttaa myös 2 taulukon avulla
(useampi lista voi käyttää samoja taulukoita)
data[0..N]
next[0..N]
i
0
1
2
3
4
5
6
p
15.9.2015
arvot
osoittimet
data
head
z
T
I
L
S
A
h
e
a
d
L
next
4
1
6
5
3
2
1
I
S
T
A
z
K2.7
Tietorakenteet ja algoritmit Y
28
§ 
Kaksisuuntainen linkitetty lista on nopeampi käsitellä,
mutta vaatii (vähän) enemmän muistitilaa.
p
E
E
S
T
A
A
S
K2.8
struct node {
char data;
struct node *next, *previous;
};
typedef struct node * DlistNode;
15.9.2015
Tietorakenteet ja algoritmit Y
29
§ 
Eräs määrittelytapa Python-kielessä:
class ListNode:
def __init__(self, value, previous=None, next=None):
self.val = value
self.next = next
self.previous = previous
15.9.2015
Tietorakenteet ja algoritmit Y
30
§ 
§ 
Linkitetty lista (ilman header-alkiota)
Kotitehtävä: toteuta vastaava luomalla erilliset head- ja z-oliot
class LinkedList:
def __init__(self):
self.first = None
self.last = None
self.size = 0
def addFirst(self, item):
self.size += 1
old = self.first
self.first = ListNode(item, None, self.first)
if old:
old.previous = self.first
if not self.last:
self.last = self.first
15.9.2015
def addLast(self, item):
…
Tietorakenteet ja algoritmit Y
31
Linkitetyn listan ominaisuudet
§ 
Taulukkoa paljon joustavampi rakenne monessa tilanteessa.
§ 
Lista koostuu yksittäisistä alkioista, joihin kuhunkin on
talletettu dataa ja osoitin (referenssi) seuraavaan alkioon.
§ 
Listan kokoa ei ole ennalta rajoitettu, vaan listaan voidaan
lisätä ja siitä voidaan poistaa alkioita ajonaikaisesti.
=> Listan kokoa rajoittaa vain käytettävissä oleva muisti.
§ 
Alkioita voi lisätä minne tahansa.
§ 
Alkioita voi poistaa mistä tahansa.
§ 
Alkioiden järjestystä voi vaihtaa.
§ 
Listan alkiot voivat olla samaa tyyppiä tai lista voi olla
geneerinen.
15.9.2015
Tietorakenteet ja algoritmit Y
32
LINKITETYN LISTAN TÄRKEIN RAJOITUS:
§ 
Alkioita voi käydä läpi vain yksitellen,
ts. alkioihin ei voi viitata suoraan (vrt.
taulukko)
Linkitetyn listan tärkeimmät operaatiot ovat:
15.9.2015
• 
TULOSTUS
• 
HAKU
• 
LISÄYS
• 
POISTO
• 
PÄIVITYS
• 
TYHJÄN LISTAN LUOMINEN
• 
N:NNEN ALKION PALAUTTAMINEN
• 
ONKO LISTA TYHJÄ?
…
Tietorakenteet ja algoritmit Y
33
§ 
Eri operaatioitten vaatima aika:
• 
• 
• 
• 
§ 
• 
Tiedetään, ettei enää kannata etsiä, kun oikea
kohta on jo ohitettu
Lisäys on vastaavasti hitaampi (ei voidakaan
lisätä aina listan alkuun)
Listasta voidaan muodostaa rengas
p
15.9.2015
N
N/2 (epäonnistunut: N)
1
N/2
Lista voidaan pitää järjestyksessä, jolloin
(epäonnistunut) haku on nopeampi
• 
§ 
TULOSTUS
HAKU
LISÄYS
POISTO
17
20
10
13
Tietorakenteet ja algoritmit Y
99
K2.6
34
2.5 Tapausesimerkki POLYNOMI
∑ ai xi
§ 
i=0...n
Jos polynomi on ‘tiheä’ l. suurin osa kertoimista
poikkeaa nollasta
=> Esitetään kertoimet taulukossa
#define MAX 1000 // ”magic number”
struct polynomi {
int kerroin[MAX+1];
int asteluku;
};
typedef struct polynomi Polynomi;
15.9.2015
Tietorakenteet ja algoritmit Y
35
§ 
Jos polynomi on ‘harva’ (vähän termejä)
=> Esitetään kertoimet järjestettynä listana
struct polynomi {
int kerroin, eksponentti;
struct polynomi * next;
};
typedef struct polynomi * Polynomi;
§ 
15.9.2015
Ei rajaa polynomin asteluvulle!
Tietorakenteet ja algoritmit Y
36
§ 
Toteutetaan polynomeille tulo-operaatio:
Polynomi A_kertaa_B(Polynomi a,b)
/* Toteutus riippuu valitusta tietorakenteesta */
}
Tai Javalla rajapinta...
public interface Polynomi {
public Polynomi multiply(Polynomi A);
}
=> käsitellään polynomia abstraktiona!
!! Kutsuvan ohjelman ei tarvitse tietää miten kertoimet on
talletettu, toteutustapaa voidaan vaihtaa tarpeen mukaan !!
15.9.2015
Tietorakenteet ja algoritmit Y
37
2.6 Abstrakti tietotyyppi (abstract data type, ADT)
§ 
Kun talletetulle tiedolle annetaan semanttinen merkitys (mitä
tieto tarkoittaa) ja määritellään, mitä tiedolle saa tehdä
(operaatiot), saadaan abstrakti tietotyyppi.
§ 
Määritellään tietorakenteeseen kohdistuvat operaatiot
§ 
Ei oteta kantaa, miten operaatiot toteutetaan
§ 
Otetaan kantaa, mitä operaatiot tekevät (riittävä
tarkkuustaso!)
§ 
Mahdollistaa toteutuksen muuttamisen joustavasti
§ 
Sama abstrakti tietotyyppi voidaan toteuttaa usean eri
talletusrakenteen avulla.
15.9.2015
Tietorakenteet ja algoritmit Y
38
Abstraktit tietotyypit / Esimerkkejä
A) Joukko abstraktina tietotyyppinä
§ 
Määritellään vaikkapa operaatiot:
• 
• 
• 
• 
∩
∪
^
||
- Leikkaus
- Unioni
- Komplementti
- Koko (= alkioiden määrä)
• 
∈ - Kuuluu joukkoon?
Set intersection(Set A, Set B)
Set union(Set A, Set B)
Set compl(Set A, Set superSet)
int size(Set A)
boolean in(Element E, Set A)
§ 
Operaatiot toteutetaan aliohjelmina, metodeina, tms.
§ 
Muualla ohjelmassa voidaan kutsua em. operaatioita
tarvitsematta tietää, miten alkiot on talletettu (taulukko, lista,
puu, ...)
15.9.2015
Tietorakenteet ja algoritmit Y
39
B) Hakurakenne abstraktina tietotyyppinä
§ 
Määritellään, että hakurakenne on kokoelma tietueita,
jotka voidaan yksiselitteisesti tunnistaa niihin talletetun
hakuavaimen arvon perusteella
§ 
Määritellään esimerkiksi operaatiot
• 
• 
• 
• 
• 
15.9.2015
Element Search(Key K)
Element Insert(Key K, Data D)
Element Delete(Key K)
Element Next(Key K) [Previous]
•  Etsi annettua tietuetta lähinnä seuraava [edellinen]
tietue
Element[] Range(Key From, Key To)
•  Etsi tietueet, joiden avainarvot ovat avainarvojen
[From,To] välissä
Tietorakenteet ja algoritmit Y
40
C) Prioriteettijono abstraktina tietotyyppinä
§ 
Määritellään, että rakenne on kokoelma alkioita, joihin
jokaiseen liittyy alkion suhdetta muihin alkioihin kuvaava
prioriteetti
§ 
Määritellään esimerkiksi operaatiot
15.9.2015
• 
Insert(Element E, int P)
•  Lisää alkio ja aseta sen prioriteetiksi P
• 
Element DeleteMax()
•  Poista ja palauta alkio, jonka prioriteettiarvo on
suurin (tai deleteMin - pienin)
• 
DecreaseKey(Element E, int delta)
•  pienennä (tai IncreaseKey -suurenna) alkion
prioriteettiä deltalla
Tietorakenteet ja algoritmit Y
41
3. Lisää lineaarisista perustietorakenteista
3.1 Pino (stack)
3.2 Jono (queue)
3.3 Pakka (deque)
15.9.2015
Tietorakenteet ja algoritmit Y
42
3. Lineaariset perustietorakenteet
§ 
Tietorakenne on lineaarinen, jos kaikki sen alkiot on
ryhmitetty peräkkäin.
§ 
Tällaista rakennetta voidaan käyttää esim.
§ 
15.9.2015
• 
yksinkertaisena hakurakenteena,
• 
tilapäisenä tallennusrakenteena.
• 
Taulukko, lista
Seuraavaksi tarkastellaan eräitä tärkeitä lineaarisia
abstrakteja tietotyyppejä.
Tietorakenteet ja algoritmit Y
43
3.1
Pino (stack)
§ 
Toimii samaan tapaan kuin pöydällä oleva korttipakka
§ 
Pino on abstrakti tietotyyppi, jolle on määritelty
seuraavat operaatiot:
15.9.2015
• 
Push(x) - lisää pinon päälle alkion x
• 
Pop() - palauttaa ja poistaa pinon päällimmäisen
alkion
• 
Top() - palauttaa pinon päällimmäisen alkion
(poistamatta sitä)
• 
IsEmpty() - palauttaa tiedon siitä, onko pino tyhjä
Tietorakenteet ja algoritmit Y
44
Jonokuri LIFO (Last In - First Out)
§ 
Kaikki pino-operaatiot voidaan toteuttaa vakioajassa (ei
riipu pinon koosta)
§ 
Pino voidaan implementoida taulukon avulla tai
linkitettynä listana
Toteutus taulukkona:
§  apuna pino-osoitin (stack pointer), joka osoittaa
...
päällimmäiseen alkioon
§ 
isEmpty() ⇔ (sp == -1)
§ 
Taulukkototeutuksessa
pinolle varattu tila voi
loppua
15.9.2015
sp
Tietorakenteet ja algoritmit Y
7
6
5
4
3
2
1
0
K2.13
45
§ 
Toteutus listana:
top
K2.14
§ 
push(): liitä uusi alkio listan alkuun
§ 
pop(): poista ja palauta alkio listan alusta
§ 
isEmpty(): tosi, jos lista on tyhjä
15.9.2015
§ 
top == null tai
§ 
Header == Z (jos käytetään erillisiä head ja z--alkioita)
Tietorakenteet ja algoritmit Y
46
Pinon sovelluksia
§  Ohjelmointikielessä lausesulkujen tarkastus: kullekin
alkusululle löytyy oikeantyyppinen loppusulku
• 
• 
Kielessä voi esiintyä useita eri sulkutyyppejä, esim. Ckielessä (,); [,]; {,}
Sulkuvirheet (esim. ”{(})”) voivat usein sotkea
kääntäjän toiminnan pahoin
§ 
Syötevirran kääntäminen päinvastaiseen järjestykseen
§ 
Ajonaikainen pino (aliohjelmakutsut):
• 
• 
15.9.2015
Kutsuvan ohjelman tila (=rekisterit) ja kutsun paikka
(=program counter) pinoon
Aliohjelmasta palattaessa voidaan palauttaa
alkuperäinen tila
Tietorakenteet ja algoritmit Y
47
Yksinkertainen lausesulkujen tarkastusperiaate
• 
Luetaan syötettä merkki kerrallaan
• 
Tutkitaan vain sulkumerkkejä
• 
Alkusulku asetetaan pinoon (push)
• 
Kohdattaessa loppusulku otetaan pinosta (pop)
päällimmäinen sulku
ü 
• 
15.9.2015
Jos pino on tyhjä (isEmpty) tai sulku on väärän
tyyppinen ⇒ virhe
Algoritmin päättyessä pinon tulee olla tyhjä
Tietorakenteet ja algoritmit Y
48
Lausekkeen arvon laskeminen
• 
Miten evaluoida lausekkeen arvo?
• 
Infix-notaatio:
5 * ( ( 9 + 8 ) * 4 * 6 + 7 )
15.9.2015
§ 
Miten tallentaa välitulokset?
§ 
Mikä on toimintajärjestys, kun lauseke luetaan
ohjelmalle merkki merkiltä?
Tietorakenteet ja algoritmit Y
49
Periaate:
1)
Muunnetaan lauseke pinon avulla postfix-muotoon:
5 9 8 + 4 * 6 * 7 + *
2) Evaluoidaan postfix-lauseke pinon avulla
15.9.2015
Tietorakenteet ja algoritmit Y
50
INFIX-POSTFIX-muunnos pinon avulla
§ 
Luetaan Infix-lauseketta merkki kerrallaan
§ 
operandit [0-9]*
⇒ tulostetaan suoraan
§ 
(
⇒ asetetaan pinoon (PUSH)
§ 
operaattorit *,+
⇒ otetaan pinosta (POP) ja tulostetaan operaattoreita, joilla
on sama tai suurempi prioriteetti, sen jälkeen asetetaan
viimeksi luettu operaattori pinoon. Sulkumerkkiä ’(’ ei
kuitenkaan lueta
§ 
)
⇒ otetaan pinosta ja tulostetaan operaattoreita, kunnes
löytyy alkusulku, joka myös luetaan, mutta ei tulosteta
§ 
Kun syöte loppuu, otetaan pinosta ja tulostetaan loput
operaattorit
15.9.2015
Tietorakenteet ja algoritmit Y
51
§ 
Esim. Muunnetaan lauseke 5*((9+8)*4*6+7)
muotoon 598+4*6*7+*
Syöte
15.9.2015
5
*
(
(
9
+
8
)
*
4
*
6
+
7
)
tyhjä
Pino
Tuloste
5
*
*(
*((
9
*((+
*(
*(*
*(*
*(+
*
Tietorakenteet ja algoritmit Y
8
+
4
*
6
*
7
+
*
52
§ 
POSTFIX-lausekkeen arvo voidaan laskea pinon avulla
§ 
Esim. lauseke 598+4*6*7+*
15.9.2015
Input
Pino
5
9
8
+
4
*
6
*
7
+
*
empty
5
5 9
5 9 8
5 17
5 17 4
5 68
5 68 6
5 408
5 408 7
5 415
2075
Tietorakenteet ja algoritmit Y
53
3.2
§ 
15.9.2015
JONO (queue)
Jono on abstrakti tietotyyppi, jolle on määritelty seuraavat
operaatiot:
• 
Put(x) tai Enqueue(x) - lisää jonon loppuun alkion x
• 
Get() tai Dequeue() - palauttaa (ja poistaa) jonon
ensimmäisen alkion
• 
First() - palauttaa jonon ensimmäisen alkion
• 
IsEmpty() - kertoo, onko jono tyhjä
• 
Jonokuri FIFO (First In First Out)
• 
Jono voidaan toteuttaa eri tavoin (taulukon avulla tai
linkitettynä listana). Toteutetaan usein sirkulaarisena
taulukkona (indeksit lasketaan modulo N).
Tietorakenteet ja algoritmit Y
54
§ 
Jonon toteutus sirkulaarisena taulukkona
Jono[0 .. MAX-1]
l ast
fi r s t
0
1
2
3
4
5
6
7
MAX
put
get
§ 
first osoittaa jonon alkuun
§ 
last osoittaa 1. vapaaseen paikkaan
§ 
Jonossa yksi tyhjä paikka, jota ei käytetä
15.9.2015
Tietorakenteet ja algoritmit Y
55
§ 
Put(x):
Jono[last] = x;
/* Jono: säiliö */
last = (last+1) % MAX;
/* last: askeltaja */
if (last == first) error;
//Jono ei saa mennä täyteen!
§ 
Get():
tmp = Jono[first];
first = (first+1) % MAX;
return tmp;
§ 
/* tmp: tilapäissäilö */
/* first:askeltaja */
First():
return Jono[first];
§ 
15.9.2015
IsEmpty():
(last == first);
Tietorakenteet ja algoritmit Y
56
§ 
Jonon toteutus listana
struct node {
datatype data;
/* data: kiintoarvo; hyötykuorma */
struct node *next; /* next: kiintoarvo; seuraava alkio */
};
typedef struct node * Queue;
fi r s t
l ast
K2.16
15.9.2015
Tietorakenteet ja algoritmit Y
57
§ 
struct node *first, *last;
struct node *temp;
§ 
Put(x):
temp = (Queue)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
last->next = temp;
last = temp;
§ 
Get():
temp = first;
x = first->data;
first = first->next;
free(temp)
return (x);
§ 
First():
return(first);
§ 
IsEmpty():
return (first == NULL);
15.9.2015
/* first, last: kulkijat
/* tmp: tilapäissäilö */
Tietorakenteet ja algoritmit Y
*/
58
Jonon sovelluksia
§ 
Esim. Printterijono
§ 
Puskuri
• 
• 
• 
• 
• 
§ 
Diskreetti simulointi
• 
§ 
15.9.2015
tiedon välivarasto
tietoa tulee
tietoa lähtee
tiedon järjestys säilyy
Esim. tulostettava tiedosto menee puskurin kautta
Esim. liikenne, tietoliikenne, palvelut
Verkkoalgoritmit (esim. leveyssuuntainen haku eli BFS)
Tietorakenteet ja algoritmit Y
59
3.3 PAKKA (deque)
§ 
Alkioita voidaan asettaa rakenteen molempiin päihin, ja myös
ottaa pois
§ 
Vrt. korttipakka kädessä
§ 
Määrittely jätetään kotitehtäväksi:
§ 
15.9.2015
Määrittele abstrakti tietotyyppi pakka
Tietorakenteet ja algoritmit Y
60
Ensi kerraksi…
•  Tee viikkojen 37-39 viikkoharjoitukset
•  Tutustu rekursion käsitteeseen
•  Tutki esim. kalvosetin lopusta löytyviä Fibonacci- ja Hanoiesimerkkejä
•  Piirrä itsenäisesti algoritmien rekursiohistoriapuut pienillä
N:n arvoilla (esim. 4)
15.9.2015
Tietorakenteet ja algoritmit Y
61
Tietorakenteet ja algoritmit
Algoritmit
Ari Korhonen
15.9.2015
Tietorakenteet ja algoritmit Y
62
4.1 Algoritmit suhteessa tietorakenteisiin
§ 
Useimmat algoritmit käsittelevät jotain tietorakennetta, eikä
atomista dataa
§ 
Käsiteltävä data on siten joukko data-alkioita, jotka
muodostavat jonkin kokonaisuuden. Algoritmi käsittelee tätä
kokonaisuutta eli tietorakennetta. Esimerkiksi:
• 
• 
• 
• 
15.9.2015
Lajitellaan tieto suuruusjärjestykseen
Etsitään jotain yksittäistä tietoa suuresta tietojoukosta
Käsitellään rakennetta, jossa tietojoukon yksittäisten
alkioiden välillä voi olla yhteyksiä, jotka yksilöivät alkion
suhteen muihin alkioihin (verkot)
Käsitellään koordinaattiavaruudessa olevaa
kokonaisuutta
Tietorakenteet ja algoritmit Y
63
4.2 Algoritmien vertailu
§ 
Jos sama asia voidaan toteuttaa eri tavoin, täytyy jotenkin
pystyä arvioimaan, mikä toteutus on kulloinkin hyvä
§ 
Vertailukriteereitä on monia:
1. 
Algoritmin askelmäärä suhteessa käsiteltävän tiedon
määrään
ü 
ü 
ü 
Pahin mahdollinen askelmäärä
Keskimääräinen askelmäärä
Tasattu askelmäärä
=> ALGORITMIANALYYSI
15.9.2015
Tietorakenteet ja algoritmit Y
64
Algoritmien vertailu / kriteereitä
2.
Algoritmin kuluttama todellinen cpu-aika (usein
ongelmallinen arvioitava)
3.
Algoritmin/tietorakenteen vaatima muistitila suhteessa
käsiteltävän tiedon määrään
4.  Laskennalliseen ongelmaan liittyvät kriteerit (esim.
vakaus (stabiilius) järjestämismenetelmissä)
15.9.2015
Tietorakenteet ja algoritmit Y
65
4.3 Algoritmien toteutus ja esittäminen
§ 
Ohjelman ylläpidettävyyden kannalta on ehdottomasti järkevää
toteuttaa tärkeä algoritmi siten, että sen mahdollinen
vaihtaminen tehokkaampaan vaikuttaa mahdollisimman vähän
muuhun ohjelmaan
⇒  Käytetään abstrakteja tietotyyppejä
§ 
Usein algoritmit esitetään pseudokielellä (á la Pascal) ja jätetään
toteutuksen pienimmät yksityiskohdat avoimiksi
⇒  Algoritmin perusajatusta on helpompi ymmärtää, kun ei
tarvitse kiinnittää huomiota ohjelmointikielen syntaksiin
⇒  Kuvaus on kieliriippumaton
15.9.2015
Tietorakenteet ja algoritmit Y
66
4.4 Iteratiiviset ohjelmat
syöte (vrt. algoritmin määritelmä)
peräkkäisyys Esim. print_list
public void print_list(ListNode head){
ListNode list;
/* list: kulkija */
list = head.next;
if (list == z)
System.out.print("List is empty");
else {
while (list != z) {
System.out.print(list.data+" ");
list = list.next;
}
}
System.out.println();
}
haarau-­‐
tuminen peräkkäisyys toisto peräkkäisyys peräkkäisyys tulos(te) Luentotehtävä: Vastaako vuokaavion rakenne em. ohjelmaa?
15.9.2015
Tietorakenteet ja algoritmit Y
67
4.5 REKURSIO
§ 
Rekursiivinen ohjelma
• 
• 
Rekursiivinen rakenne
• 
§ 
Kutsuu itseään
Rakenne sisältyy itseensä
Rekursiivinen funktio
• 
On määritelty itsensä avulla
• 
Esim. Fibonacci-luvut:
X(i) = X(i-1) + X(i-2),
X(0) = X(1) = 1
15.9.2015
Tietorakenteet ja algoritmit Y
68
§ 
Rekursio ei voi jatkua loputtomiin
• 
Täytyy löytyä päätösehto jonka toteutuminen lopettaa
rekursion
• 
Esim. Kertoma:
Rekursio:
Päätösehto:
15.9.2015
N! = N(N-1)!
0! = 1
Tietorakenteet ja algoritmit Y
69
Rekursion neljä kultaista sääntöä:
1. 
Perustapaukset (ratkaistavissa ilman rekursiota)
2.  Edistyminen (liikutaan perustapausta kohti)
3.  Oletus (kaikki rekursiiviset kutsut toimivat)
4.  Vältä turhaa työtä (jokainen tapaus ratkaistaan vain
kerran)
15.9.2015
Tietorakenteet ja algoritmit Y
70
§ 
Esim. Kertoma rekursiivisena:
int factorial(int n) /* n: askeltaja */
{
if (n==0)
return 1;
else
return factorial(n-1)*n;
}
§ 
Esim. Kertoma ei-rekursiivisena:
int factorial(int n)
/* n: kiintoarvo */
{
int i,fact;
fact = 1;
/* fact: kokooja */
for (i=2; i<=n; i++) /* i: askeltaja */
fact = fact*i;
return fact;
}
15.9.2015
Tietorakenteet ja algoritmit Y
71
Esim. Fibonacci-luvut:
int fibonacci(int n)
{
if (n<=1)
return 1;
else
return
fibonacci(n-1)+fibonacci(n-2);
}
{Rikkoo neljättä sääntöä}
§ 
F4
Parempi toteuttaa eirekursiivisena
F3
F2
F1
15.9.2015
F1
F5
F4
F3
F2
F1
F6
F2
F0
F1
F3
F1
F0
F2
F1
F2
F1
F1
F0
F0
F0
Tietorakenteet ja algoritmit Y
72
Rekursiohistoriapuu
§ 
§ 
§ 
§ 
§ 
Puurakenne, jossa solmu jokaista rekursiokutsua kohti
Solmut aktivoituvat ns. esijärjestyksessä (ks. puiden läpikäynti)
Ensimmäistä kutsua vastaa puun juuri
Pinokehys aktiivinen, kunnes kaikki alipuut on käyty läpi
Pinokehys poistuu, kun rekursio palaa solmusta
Esim. Fibonaccin luvut:
int fibonacci(int n)
{
if (n<=1)
return 1;
else
return
fibonacci(n-1)+fibonacci(n-2);
}
15.9.2015
Tietorakenteet ja algoritmit Y
73
§ 
Esim. Hanoin tornit (Edouard Lucas, 1883):
Siirrä renkaat toiseen tappiin yksi kerrallaan niin, että
isompi rengas ei koskaan ole pienemmän päällä:
Mi s t ä
Mi nne
Vi a
N
K2.17
15.9.2015
? Tietorakenteet ja algoritmit Y
74
§ 
Esim. Hanoin tornit (Edouard Lucas, 1883):
Ratkaisu rekursion avulla:
Mi s t ä
Mi nne
Vi a
N-1
N-1
1
K2.17
15.9.2015
Tietorakenteet ja algoritmit Y
75
void hanoi(int N, int mista, int minne, int via)
{
if (N==1)
printf(”Siirrä rengas tapista %d
tappiin %d kiitos\n”, mista, minne);
else {
hanoi(N-1, mista, via, minne);
hanoi(1, mista, minne, via); // printf
hanoi(N-1, via, minne, mista);
}
}
Mi s t ä
Kotitehtävä: Ohjelmoi hanoi
haluamallasi ohjelmointikielellä
ja testaa, että se toimii!
15.9.2015
Tietorakenteet ja algoritmit Y
Mi nne
Vi a
K2.17
76
Hanoin tornien rekursiohistoriapuu
§ 
Esim. hanoin(3, 1, 2, 3)
void hanoi(int N, int mista, int minne, int via)
{
if (N==1)
printf(”Siirrä rengas tapista %d
tappiin %d kiitos\n”, mista, minne);
else {
hanoi(N-1, mista, via, minne);
hanoi(1, mista, minne, via); // printf
hanoi(N-1, via, minne, mista);
}
}
Mi s t ä
Mi nne
Vi a
K2.17
h(3,1,2,3) h(2,1,3,2) h(1,1,2,3) 15.9.2015
Tietorakenteet ja algoritmit Y
77
Rekursiohistoriapuu…
§ 
Esim. hanoi(3, 1, 2, 3)
void hanoi(int N, int mista, int minne, int via)
{
if (N==1)
printf(”Siirrä rengas tapista %d
tappiin %d kiitos\n”, mista, minne);
else {
hanoi(N-1, mista, via, minne);
hanoi(1, mista, minne, via); // printf
hanoi(N-1, via, minne, mista);
}
}
h(3,1,2,3) h(2,1,3,2) h(1,1,2,3) 15.9.2015
h(1,1,3,2) h(2,3,2,1) h(1,1,2,3) h(1,2,3,1) Tietorakenteet ja algoritmit Y
h(1,3,1,2) h(1,3,2,1) h(1,1,2,3) 78