Tietorakenteet, laskuharjoitus 4,

Samankaltaiset tiedostot
Tietorakenteet, laskuharjoitus 4,

TIETORAKENTEET JA ALGORITMIT

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

Listarakenne (ArrayList-luokka)

A TIETORAKENTEET JA ALGORITMIT

Tietorakenteet, laskuharjoitus 6,

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

18. Abstraktit tietotyypit 18.1

Kaksiloppuinen jono D on abstrakti tietotyyppi, jolla on ainakin seuraavat 4 perusmetodia... PushFront(x): lisää tietoalkion x jonon eteen

Sisällys. 18. Abstraktit tietotyypit. Johdanto. Johdanto

Rajapinta (interface)

Algoritmit 2. Luento 7 Ti Timo Männikkö

Pino S on abstrakti tietotyyppi, jolla on ainakin perusmetodit:

Ohjelmointi 2 / 2010 Välikoe / 26.3

Kääreluokat (oppikirjan luku 9.4) (Wrapper-classes)

Ohjelmoinnin jatkokurssi, kurssikoe

Algoritmit 1. Demot Timo Männikkö

58131 Tietorakenteet ja algoritmit (syksy 2015)

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

private TreeMap<String, Opiskelija> nimella; private TreeMap<String, Opiskelija> numerolla;

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo

Sisältö. 22. Taulukot. Yleistä. Yleistä

2. Perustietorakenteet

Algoritmit 1. Luento 5 Ti Timo Männikkö

Sisältö. 2. Taulukot. Yleistä. Yleistä

1.1 Pino (stack) Koodiluonnos. Graafinen esitys ...

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

(a) L on listan tunnussolmu, joten se ei voi olla null. Algoritmi lisäämiselle loppuun:

Rinnakkaisohjelmointi kurssi. Opintopiiri työskentelyn raportti

14. Poikkeukset 14.1

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 4 Ke Timo Männikkö

Algoritmit 2. Luento 2 Ke Timo Männikkö

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

Tietorakenteet, laskuharjoitus 2,

Algoritmit 1. Demot Timo Männikkö

Algoritmit 2. Demot Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2013) Kurssikoe 1, , vastauksia

14. Poikkeukset 14.1

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

4. Perustietorakenteet: pino, jono ja lista

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

Luokan sisällä on lista

Algoritmit 2. Luento 2 To Timo Männikkö

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

1. Mitä tehdään ensiksi?

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

lähtokohta: kahden O(h) korkuisen keon yhdistäminen uudella juurella vie O(h) operaatiota vrt. RemoveMinElem() keossa

1 Tehtävän kuvaus ja analysointi

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

Java ja grafiikka. Ville Sundberg

58131 Tietorakenteet Erilliskoe , ratkaisuja (Jyrki Kivinen)

Algoritmit 2. Luento 3 Ti Timo Männikkö

Tietorakenteet ja algoritmit - syksy

16. Javan omat luokat 16.1

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Lista luokan sisällä

Olio-ohjelmointi Javalla

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

Algoritmit 2. Luento 4 To Timo Männikkö

Tarkennamme geneeristä painamiskorotusalgoritmia

Algoritmit 1. Luento 6 Ke Timo Männikkö

20. Javan omat luokat 20.1

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Sisällys. 20. Javan omat luokat. Java API. Pakkaukset. java\lang

Mikä yhteyssuhde on?

Algoritmit 2. Luento 3 Ti Timo Männikkö

List-luokan soveltamista. Listaan lisääminen Listan läpikäynti Listasta etsiminen Listan sisällön muuttaminen Listasta poistaminen Listan kopioiminen

useampi ns. avain (tai vertailuavain) esim. opiskelijaa kuvaavassa alkiossa vaikkapa opintopistemäärä tai opiskelijanumero

Ohjelmoinnin peruskurssi Y1

Tehtävän V.1 ratkaisuehdotus Tietorakenteet, syksy 2003

Tietorakenteet, laskuharjoitus 1,

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Java-kielen perusteet

Taulukot. Taulukon käsittely. Tämän osan sisältö. Esimerkki. Taulukon esittely ja luonti. Taulukon alustaminen. Taulukon koko

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Java-kielen perusteita

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

4 Tehokkuus ja algoritmien suunnittelu

Aikavaativuuden perussäännöt

Sekvenssi: kokoelma peräkkäisiä alkioita (lineaarinen

3. Binääripuu, Java-toteutus

Ohjelmoinnin perusteet Y Python

Ohjelmointityö 3. Mikko Laamanen

Tietorakenteet (syksy 2013)

811312A Tietorakenteet ja algoritmit , Harjoitus 2 ratkaisu

Algoritmit 2. Demot Timo Männikkö

Ohjelmointi 2 / 2011 Välikoe / 25.3

Mitä poikkeuskäsittely tarkoittaa?

Java-kielen perusteita

Ohjelmoinnin perusteet Y Python

8. Näppäimistöltä lukeminen 8.1

Algoritmit 1. Demot Timo Männikkö

17. Javan omat luokat 17.1

Algoritmit 1. Demot Timo Männikkö

Transkriptio:

Tietorakenteet, laskuharjoitus 4, 7. 11.2 1. Tehtävässä piti toteuttaa jono käyttäen Javan valmiita LinkedList- sekä ArrayListtietorakenteita sekä tutkia niiden tehokkuutta. Kuvassa 1 näkyvät suoritettujen mittausten tulokset. 3000 LinkedList ArrayList 2500 2000 ms 1500 1000 500 0 10000 20000 30000 40000 50000 60000 70000 80000 90000 100000 alkioita Kuva 1: Jonon nopeus eri toteutuksilla lisättäessä ensin n alkiota ja tämän jälkeen poistettaessa n alkiota. Mittauksista näkee, että LinkedList on nopeudessaan aivan ylivoimainen. Tutkimalla Javan API-kuvausta selviää, että ArrayList on toteutettu taulukkoon ja Linked- List on toteutettu linkitettynä rakenteena. Poistettaessa ArrayListin alkupäästä tai keskeltä alkio joudutaan siirtämään kaikki sitä seuraavat alkiot askeleella eteenpäin. Linkitetyssä toteutuksessa taas korjataan vain viiteiden paikkaa ja jätetään poistettu listasolmu roskien kerääjän huoleksi. Siis ArrayListista poistettaessa joudutaan tekemään n i askelta, jossa n on alkioiden lukumäärä ja i poistettavan alkion indeksi. Kun alkio poistetaan aina listan edestä, niin n:ssä poisto-operaatiossa joudutaan tekemään (n 1) + (n 2) +... + 1 + 0 = n 1 i=0 i = O(n2 ) askelta. Tällöin yhtä operaatiota kohti kuluu keskimäärin lineaarinen aika. LinkedListia käytettäessä jokainen poisto listan kärjestä sujuu vakioajassa, joten n:n poisto-operatioon kuluvaksi ajaksi saadaan n O(1) = O(n). 1

Tämän perusteella LinkedListin käyttö tuntuu ArrayListin käyttö viisaammalta. Kuitenkin yleisessä tapauksessa riippuu sovelluksesta kumpaa kannattaa käyttää. Esimerkiksi ArrayList toteuttaa Javan RandomAccess rajapinnan, joka tarkoittaa, että jokaiseen listan alkioon päästään käsiksi vakioajassa. LinkedListin tapauksessa listaa joudutaan aina kelaamaan i askelta, kun halutaan päästä sen i:nnenteen alkioon käsiksi. Ohessa on Java-koodit, joita mittauksissa käytettiin. ArrayListJono.java import java.util.arraylist; class ArrayListJono { private ArrayList<Integer> lista; public ArrayListJono() { this.lista = new ArrayList<Integer>(); public boolean enqueue(integer alkio) { /* Tavallinen ArrayList-metodi palauttaa true, jos operaatio * onnistui ja false jos ei onnistunut. Voimme siis palauttaa * arvon suoraan kutsujalle. */ return this.lista.add(alkio); public Integer dequeue() { if (this.isempty()) return null; return this.lista.remove(0); public boolean isempty() { return this.lista.isempty(); LinkedListJono.java import java.util.linkedlist; class LinkedListJono { private LinkedList<Integer> lista; 2

public LinkedListJono() { this.lista = new LinkedList<Integer>(); public boolean enqueue(integer alkio) { return this.lista.add(alkio); public Integer dequeue() { if (this.isempty()) return null; return this.lista.remove(0); public boolean isempty() { return this.lista.isempty(); PerformanceTest.java import java.io.filewriter; import java.io.printwriter; import java.io.ioexception; class PerformanceTest { public static void main(string[] args) { if ( args.length < 3) { System.out.println("Anna testattava väli muodossa \"alku " + "loppu askel\""); System.out.println("Olkoon N = alku + i*askel. Jokaista N " + "<= loppu, molempiin jonoihin" + "tehdään N lisäystä ja poistoa"); System.exit(0); int alku = Integer.parseInt(args[0]); int loppu = Integer.parseInt(args[1]); int askel = Integer.parseInt(args[2]); PrintWriter ulos = null; try { ulos = new PrintWriter(new FileWriter("ArrayListJono.dat")); 3

for (int i = alku; i <= loppu; i += askel) { ArrayListJono jono1 = new ArrayListJono(); long start = System.currentTimeMillis(); for (int j = 0; j < i; j++) jono1.enqueue(j); for (int j = 0; j < i; j++) jono1.dequeue(); long end = System.currentTimeMillis(); ulos.println(i+"\t"+(end - start)); /* Toivotaan, että Javan roskienkeruu tapahtuu * ajanottojen ulkopuolella. */ System.gc(); catch (IOException e) { e.printstacktrace(); finally { if (ulos!= null) ulos.close(); ulos = null; try { ulos = new PrintWriter(new FileWriter("LinkedListJono.dat")); for (int i = alku; i <= loppu; i += askel) { LinkedListJono jono2 = new LinkedListJono(); long start = System.currentTimeMillis(); for (int j = 0; j < i; j++) jono2.enqueue(j); for (int j = 0; j < i; j++) jono2.dequeue(); long end = System.currentTimeMillis(); ulos.println(i+"\t"+(end - start)); System.gc(); catch (IOException e) { e.printstacktrace(); finally { if (ulos!= null) ulos.close(); 2. Ohessa olevan listan metodeilla on seuraavat aikavaativuudet. delete(k) vie lineaarisen ajan, koska samalla täytyy suorittaa avaimen haku. Pahimmassa tapauksessa (esimerkiksi jos poistettavaa avainta ei löydy) jou- 4

dutaan selaamaan listan kaikki alkiot läpi. Linkkien ylläpito-operaatiot, joita tehdään jos alkio poistetaan, sujuvat vakioajassa. search(k) vie samoista syistä lineaarisen ajan kuin delete-operaatiokin. insert(k) sujuu vakioajassa laittamalla jokainen lisättävä alkio jonon etupäähän. Tarvittavat linkkien ylläpito-operaatiot sujuvat vakio-ajassa. list() vie lineaarisen ajan, koska lista on pyyhkäistävä läpi kertaalleen. reverse() vie myös lineaarisen ajan, koska listan jok ikisen viitteen suunta on käännettävä. Tämä kyetään tekemään kulkemalla kerran listan läpi. Ohessa on vielä toteutuksen Java-koodi. class MyLinkedList { private class ListNode { /* Sisäluokan attribuutteihin halutaan päästä helposti käsiksi, * joten jätetään ne julkisiksi. */ public int key; public ListNode next; public ListNode(int arvo) { this.key = arvo; this.next = null; private ListNode head; public MyLinkedList() { this.head = null; public boolean search(int avain) { /* Iteroidaan listaa kunnes löydetään avain tai loppu tulee vastaan.*/ while ( current!= null && avain!= current.key ) { return (current!= null)? true : false; public void delete(int avain) { ListNode prev = null; 5

while ( current!= null && avain!= current.key ) { prev = current; if (current!= null) { // jos löytyi hoidetaan linkit kuntoon if ( prev!= null ) // poistettu alkio ei ollut ensimmäinen prev.next = current.next; else { // poistettu alkio oli ensimmäinen this.head = current.next; public void insert(int avain) { ListNode node = new ListNode(avain); node.next = this.head; this.head = node; public void list() { while( current!= null ) { System.out.print(current.key + " -> "); System.out.println("null"); public void reverse() { if ( this.head == null this.head.next == null ) return; ListNode prev = this.head; ListNode current = prev.next; prev.next = null; while ( current!= null ) { ListNode temp = current.next; current.next = prev; prev = current; current = temp; this.head = prev; public static void main(string[] args) { MyLinkedList lista = new MyLinkedList(); 6

for (int i = 0; i < 5; i++ ) lista.insert( (int) (100*Math.random()) ); lista.insert(101); lista.insert(101); for (int i = 0; i < 5; i++ ) lista.insert( (int) (100*Math.random()) ); lista.list(); lista.delete(101); lista.list(); lista.reverse(); lista.list(); if ( lista.search(101) ) System.out.println("101 löytyi listasta"); else System.out.println("101 ei löytynyt listasta"); 3. Kun lista pidetään järjestyksessä jokainen operaatio paitsi insert(k) vievät saman ajan kuin edelläkin. Koska järjestettyyn listaan ei voi lisätä alkioita mielivaltaiseen paikkaan, täytyy uusille alkioille aina etsiä oikea paikka listasta. Pahimmassa tapauksessa kuljetaan lista kerran läpi, jonka vuoksi tämä vie ajan O(n). Ohessa on toteutus Javalla. Huomaa, että Javamaisempi tapa tässä olisi ollut tehdä tästä edellisen kohdan aliluokka. class MyOrderedList { private class ListNode { /* Sisäluokan attribuutteihin halutaan päästä helposti käsiksi, * joten jätetään ne julkisiksi. */ public int key; public ListNode next; public ListNode(int arvo) { this.key = arvo; this.next = null; private ListNode head; public MyOrderedList() { this.head = null; 7

public boolean search(int avain) { /* Iteroidaan listaa kunnes löydetään avain tai loppu tulee vastaan.*/ while ( current!= null && avain > current.key ) { return (current!= null && current.key == avain)? true : false; public void delete(int avain) { ListNode prev = null; while ( current!= null && avain > current.key ) { prev = current; if (current!= null) { // jos löytyi hoidetaan linkit kuntoon if ( prev!= null ) // poistettu alkio ei ollut ensimmäinen prev.next = current.next; else { // poistettu alkio oli ensimmäinen this.head = current.next; public void insert(int avain) { ListNode node = new ListNode(avain); ListNode prev = null; while ( current!= null && avain > current.key ) { prev = current; node.next = current; if (prev == null) this.head = node; else prev.next = node; public void list() { while( current!= null ) { System.out.print(current.key + " -> "); 8

System.out.println("null"); public static void main(string[] args) { MyOrderedList lista = new MyOrderedList(); for (int i = 0; i < 5; i++ ) lista.add( (int) (100*Math.random()) ); lista.insert(101); lista.insert(101); for (int i = 0; i < 5; i++ ) lista.insert( (int) (100*Math.random()) ); lista.list(); lista.delete(101); lista.list(); lista.delete(101); lista.list(); if ( lista.search(101) ) System.out.println("101 löytyi listasta"); else System.out.println("101 ei löytynyt listasta"); 4. Esitetään kaksisuuntaisesti linkitetty lista toteutettuna taulukkoon, jonka koko on n. Taulukon kukin alkio sisältää kentät key, prev sekä next. next- ja prev-kentät sisältävät taulukon indeksit asiaan kuuluville solmuille. Tämän lisäksi talletetaan taulukon yhteyteen kokonaisluku head, joka on ensimmäisen solmun indeksi taulukossa. Käytännössä tämä voitaisiin toteuttaa käyttäen kaksiulotteista n 3-taulukkoa tai tallettamalla yksiulotteisen taulukon kenttiin viite tietueeseen, johon on talletettu edellämainitut kentät. Pseudokoodiesityksessä emme ota kantaa varsinaiseen toteutukseen vaan viittaamme esimerkiksi taulukon 3:nnessa paikassa olevan alkion avaimeen merkinnällä A[3 ]. key. Tallettamamme tiedon lisäksi meidän tarvitsee myös ylläpitää informaatiota taulukon vapaista paikoista. Käytetään tähän pinoa P, jossa on talletettuna vapaiden indeksien paikat. Lisättäessä taulukkoon alkioita talletetaan uusi alkio pinon päältä löytyvälle taulukon riville. Poistettaessa alkioita pinoon lisätään poistetun alkion indeksi. Pinon koko on suurimmillaan n, joten listan esitys taulukossa vaatii tilaa jokaisella ajanhetkellä Θ(n). Merkitään numerolla 0 Nil-viitettä. Alussa kun lista on tyhjä pinossa on kokonaisluvut 1, 2,..., n ja headin arvo on 0. Tarvitsemme siis listan L esittämiseen taulukon A, pinon P sekä kokonaisluvun head. Nyt olemme valmiita esittämään pseudokoodit Insert- sekä Delete-operaatioille. Insert ottaa parametrinaan avaimen ja lisää sen listaan sekä palauttaa lisätyn avaimen indeksin. Delete ottaa parametrikseen poistettavan alkion indeksin taulukossa 9

ja poistaa tämän indeksin paikalta löytyneen alkion. Tässä on hyvä huomata, että jos Delete- operaatiolle annetaan indeksi joka ei kuulu listaan, niin koko tietorakenne korruptoituu. Delete(L, x) 1 if head == x // Poistetaan listan ensimmäinen alkio 2 head = A[x].next 3 if A[x].next 0 // Poistettava alkio ei ollut listan viimeinen 4 A[A[x].next].prev = 0 5 else // Poistettavalla alkiolla on ainakin yksi edeltäjä 6 A[A[x].prev].next = A[x].next 7 if A[x].next 0 // Poistettava alkio ei ollut listan viimeinen 8 A[A[x].next].prev = A[x].prev // Lopuksi lisätään poistetun alkion paikka vapaiden alkioiden joukkoon 9 Push(P, x) Insert(L, k) 1 if Empty(P) 2 error lista on täynnä 3 i = Pop(P) 4 A[head].prev = i 5 A[i].key = k 6 A[i].next = head 7 A[i].prev = 0 8 head = i Nähdään molempien operaatioiden sujuvan vakioajassa, sillä osaamme toteuttaa pinon operaatiot tehokkaasti eikä kummassakaan operaatiossa suoriteta korkeintaan kuin vakiomäärän verran askelia. 5. Esitetään ensin vakiotilassa ja neliöllisessä ajassa toimiva algoritmi silmukan havaitsemiseen. Ajatuksena on, että edetään listassa aina yksi solmu kerrallaan ja pidetään yllä invarianttia: Ennen tätä solmua listassa ei ole esiintynyt viitteitä taaksepäin. Jos tämän hetkinen solmu on järjestyksessään n:s, niin käydään läpi solmut 1,..., n 1 ja tarkistetaan onko joku niistä myös n:s solmu. Siis n:n solmun tarkistamisessa tarvitsee suorittaa n 1 askelta. Summaamalla kaikkien solmujen tarkistukseen kuluvan ajan tarvitaan silmukallisessa listassa n 1 i=0 i+o(n) = O(n2 )+O(n) = O(n 2 ) askelta. Kaavan O(n) tulee silmukan havaitsemiseen kuuluvasta ajasta viimeisellä kierroksella. On helppo nähdä että myös silmukattoman listan tarkistamiseen kuluu saman verran aikaa. Esitetään nyt algoritmi pseudokoodina. 10

OnkoSilmukkaa1(L) 1 current = L.head.next 2 n = 1 3 while current Nil 4 check = L. head 5 i = 0 6 repeat 7 if check == current // sykli löytyi 8 return True 9 check = check. next 10 i = i + 1 11 until i n 12 current = current. next 13 n = n + 1 14 return True Tarkastelemalla pseudokoodia havaitaan, että sitä ei tarvitsisi muuttaa kovinkaan paljon, mikäli haluttaisiin myö palauttaa solmu, jonka linkki oli virheellinen. Tämä vaatisi prev- mukana pitämistä, jonka arvo olisi riviltä 6 alkavassa silmukassa aina sellainen, että prev.next == check. Toinen tapa havaita onko listassa silmukka olisi koittaa kääntää listan linkit muokkaamalla tehtävässä 4 suunniteltua Reverse-operaatiota. Tällöin, jos listassa L olisi silmukka, niin L. head pysyisi samana Reverse-operaationkin jälkeen. Jos taas listassa ei olisi silmukkaa niin listan ensimmäinen alkio olisi joku toinen alkio, kuin ennen Reverse-operaatiota. Lista voitaisiin palauttaa alkuperäiseksi kääntämällä se uudelleen. Tämä veisi tilaa ainoastaan vakiomäärän, eikä aikavaativuuskaan olisi kuin Θ(n). Kuitenkin tässä lähestymistavassa on 2 ongelmaa: listaa muokattaisiin laskennan aikana emmekä löytäisi kohtaa, jossa silmukka esiintyy. Ongelma voidaan muotoilla hiukan yleisemmällä tavalla, jolloin puhutaan syklin tunnistamisalgoritmeista (cycle detection). Ongelmaan on esitetty useita ajassa O(n) ja tilassa O(1) toimivia algoritmeja, joista tässä esitellään Floydin kilpikonna ja jänis - algoritmi sovellettuna yksisuuntaisesti linkitettyyn listaan. Yleistettäessä algoritmi sykleihin yleisellä tasolla ei se muutu juuri lainkaan 1. Ajatuksena on lähettää kilpikonna ja jänis kulkemaan listaa eteenpäin. Kilpikonna on jänistä hitaampi ja se ehtii edetä vain yhden solmun verran siinä ajassa kun jänis etenee kahden solmun verran. Jokaisen askeleen jälkeen tarkistetaan ovatko jänis ja kilpikonna samassa kohdassa. Mikäli ne jossain vaiheessa ovat on listassa silmukka. Algoritmi voidaan muokata palauttamaan sen solmun järjestysnumeron, johon listan taaksepäin suuntautuva linkki osoittaa. Tässä esitetään kuitenkin ainoastaan algoritmin alkuosa, joka tutkii onko listassa silmukka. Merkitään kilpikonnaa ja jänistä viitemuuttujilla k ja j. 1 Tällöin tarkastellaan mielivaltaista funktiota f ja lukujonoa x 0, x 1 = f(x 0), x 2 = f(x 1),... Tapauksessamme funktion f korvaa linkitetyn listan next-viite 11

OnkoSilmukkaa2(L) 1 k = j = L.head 2 if j == Nil tai j.next == Nil 3 return False 4 repeat 5 k = k.next 6 j = j.next.next 7 until j == k tai j == Nil tai j.next == Nil 8 if j == k 9 return True 10 else return False Tarkastellaan tapausta, jossa listassa on silmukka. Kun kilpikonna pääsee listan silmukan alkukohtaan on jänis jo kiertämässä silmukkaa. Jänis etenee kilpikonnaan nähden kaksinkertaisella vauhdilla, joten kun kilpikonna on kiertänyt silmukan on jänis kiertänyt sen vähintään kerran. Tämän vuoksi aika, jonka kilpikonna viettää silmukassa on luokkaa O(n). Lisäksi kilpikonnan matka silmukaan kestää O(n), joten koko algoritmille riittää lineaarinen aika. Algoritmissa käytetään vain kahta muuttujaa, joten se toimii vakiotilassa. 12