TIETORAKENTEET JA ALGORITMIT Timo Harju 1999-2004 1 typedef link List; /* Vaihtoehtoisia nimiä */ typedef link Stack; /* nodepointterille */ typedef link Queue typedef struct node Node; /* itse nodelle */ 2 KOODILIITE /* Funktioiden prototyypit */ Tässä liitteessä esitetään tietorakenteiden ja algoritmien kooditoteutuksia. Pääosin koodit on otettu alan tunnustetuista kirjoista. Toki ne on kirjoittajan toimesta implementoitu ja vähäisiltä osin modifioitu. 1. Linkitetty lista, C-toteutus Toteutus perustuu Weissin kirjaan Data Structures and Algorithm Analysis in C. /*------------------------------------------------------------------*/ /* LIST.H - linkitetyn listan ja pinon käyttöön liittyviä */ /* määrittelyjä. */ /* Käyttö: */ /* - omaan ohjelmaan #include "list.h", jonka on oltava */ /* hakemistossa, mistä kääntäjä sen löytää */ /* - tiedosto list.c linkitettävä mukaan ohjelmaan */ /* Sisältö: */ /* crealist() : luo listan headerin, palauttaa pointterin alkuun */ /* isempty() : palauttaa tiedon, onko lista pelkkä headeri */ /* islast() : palauttaa tiedon, onko annettu node viimeinen */ /* insnode() : lisää noden listaan annettuun paikkaan */ /* push() : lisää noden pinona käytetyn listan alkuun */ /* enqueue() : lisää noden jonona käytetyn listan loppuun */ /* find() : etsii noden paikan listassa */ /* findprev() : etsii nodea edellisen noden paikan */ /* pop() : poistaa pinosta ens. noden ja pauttaa datan */ /* dequeue() : poistaa jonosta ens. noden ja palauttaa datan */ /* delnode() : poistaa noden listasta */ /* dellist() : tuhoaa koko listan paitsi headerin */ /* printlist() : tulostaa listan sisällön */ /* Timo Harju 1999.11, 2000.12 */ /* ---------------------------------------------------------------- */ #ifndef _LIST.H #define _LIST.H typedef int item_type; /* Listan datan tyyppi */ List crealist( void ); int isempty( List L ); int islast( link p ); void insnode( link p, item_type a ); void push( Stack S, item_type a ); void enqueue( Queue S, item_type a ); link find( List L, item_type x); link findprev( List L, item_type x); void delnode( List L, item_type x); item_type pop( Stack S ); item_type dequeue( Queue S ); void dellist( List L ); void printlist( List p ); #endif /*------------------------------------------------------------------*/ /* LIST.C - linkitetyn listan ja pinon käyttöön liittyviä */ /* funktioita. */ /* Käyttö: */ /* - omaan ohjelmaan #include "list.h", jonka on oltava */ /* hakemistossa, mistä kääntäjä sen löytää */ /* - tämä tiedosto list.c linkitettävä mukaan ohjelmaan */ /* Sisältö: */ /* crealist() : luo listan headerin, palauttaa pointterin alkuun */ /* isempty() : palauttaa tiedon, onko lista pelkkä headeri */ /* islast() : palauttaa tiedon, onko annettu node viimeinen */ /* insnode() : lisää noden listaan annettuun paikkaan */ /* push() : lisää noden pinona käytetyn listan alkuun */ /* enqueue() : lisää noden jonona käytetyn listan loppuun */ /* find() : etsii noden paikan listassa */ /* findprev() : etsii nodea edellisen noden paikan */ /* pop() : poistaa pinosta ens. noden ja pauttaa datan */ /* dequeue() : poistaa jonosta ens. noden ja palauttaa datan */ /* delnode() : poistaa noden listasta */ /* dellist() : tuhoaa koko listan paitsi headerin */ /* printlist() : tulostaa listan sisällön */ /* Timo Harju 1999.11, 2000.12 */ /* ---------------------------------------------------------------- */ typedef struct node *link; /* Pointteri nodeen */ struct node /* Node: */ item_type item; /* data */ link next; /* pointteri seuraavaan nodeen */ ; #include <stdlib.h> #include <stdio.h> #include "list.h"
/* Luo linkitetyn listan headerin (noden + NULL-linkin ) */ List crealist( void ) List L; L = ( link ) malloc( sizeof ( Node ) ); if ( L == NULL ) printf( "crealist: muistin varaaminen epäonnistui\n" ); exit( 1 ); L->next = NULL; return L; /* Testaa, onko lista tyhjä */ int isempty( List L ) return ( L->next == NULL ); /* Testaa, onko parametrina oleva paikka listan viimeinen */ int islast( link p ) return ( p->next == NULL ); /* Lisää alkion listaan parametrina olevan paikan perään */ void insnode( link p, item_type a ) link t; t = ( link ) malloc( sizeof ( Node ) ); if ( t == NULL ) printf( "inslist: muistin varaaminen epäonnistui\n" ); exit( 1 ); t->item = a; t->next = p->next; p->next = t; /* Sijoittaa alkion pinona käytetyn listan ensimmäiseksi */ void push( Stack S, item_type a ) insnode( S, a ); 3 /* Etsii annettua alkiota listasta */ link find( List L, item_type x) p = L->next; while ( ( p!= NULL ) && ( p->item!= x ) ) return p; /* Etsii annettua alkiota edellisen alkion paikan listassa */ link findprev( List L, item_type x) p = L; while ( ( p->next!= NULL ) && ( p->next->item!= x ) ) return p; /* Poistaa annetun alkion listasta */ void delnode( List L, item_type x) link p, t; p = findprev( L, x); if ( p->next!= NULL ) t = p->next; p->next = t->next; free( t ); /* Poistaa päällimmäisen alkion pinona käytetystä listasta */ item_type pop ( Stack S ) item_type a; if ( isempty( S ) ) printf( "Pino tyhjä\n" ); return -1; else p = S->next; a = p->item; S->next = p->next; free( p ); return a; 4
/* Tuhoaa listan kaikki alkiot paitsi Headerin */ void dellist( List L ) link p, t; p = L->next; L->next = NULL; while ( p!= NULL ) t = p->next; free( p ); p = t; /* Tulostaa lista sisällön näytölle */ void printlist( List p ) while ( p->next!= NULL ) printf( "%d\n", p->item ); 5 2 Linkitetty lista, Java-toteutus /*-------------------------------------------------------------/ / LINKITETTY LISTA: Luokka List / / Sisältää tunnussolullisen linkitetyn listan osittaisen / / toteutuksen. / / Listan solu: sisäluokka Node / / Ilmentymämuuttujat: / / Node head : viite tunnussoluun / / Node iterator : iteraatttori eli "kulkuriviite" / / Konstuktori List(): luo tyhjän listan eli pelkän tunnussolun / / Julkiset metodit: / / Node gethead() : palauttaa tunnussolun viitteen / / boolean isempty() : onko lista tyhjä / / void makeempty : tyhjää listan / / void resetit() : iteraattori osoittamann tunnussoluun/ / Node getit() : palauttaa iteraattorin paikan / / void advanceit() : edistää iteraattoria yhdellä / / void makecircular() : tekee listasta rengaslistan / / void insert() : lisää solun haluttuun paikkaan / / void insertatend() : lisää solun listan loppuun / / void delete() : poistaa solun halutusta paikasta / / void deletenexttoit(): poistaa iteraattorin osoittamaa / / seuraavan solun / / void reverse() : kääntää listan / / String tostring() : listan sisällön merkkiesitys / / TH 2001.10 / /-------------------------------------------------------------*/ public class List //Listaluokka class Node //Listan solu sisäluokkana: Object item; // solun data Node next; // viite seuraavaan soluun public Node() // solun konstruointi item = null; next = null; public Object getitem() // palauttaa solun datan return item; public Node getnext() // palauttaa solun next-viitteen return next; private Node head; //Viite listan headeriin private Node iterator; //Iteraattori eli "kulkuri" 6
public List() //Konstruktori luo headerin head = new Node(); head.next = null; iterator = head; // ja alustaa kulkurin public Node gethead() //Palauttaa viitteen tunnussoluun return head; public boolean isempty() //Onko lista tyhjä return head.next == null; public void makeempty() //Tyhjentää listan head.next = null; // käy näin helposti Javassa public void resetit() //Alustaa kulkurin uudestaan iterator = head; iterator.next = head.next; public Node getit() //Palauttaa kulkurin paikan return iterator; public void advanceit() //Edistää kulkuria yhden askeleen if ( iterator.next!= null ) iterator = iterator.next; public void makecircular() //Tekee listasta rengaslistan if( head.next!= null ) Node current = head.next; while ( current.next!= null ) current.next = head.next; //Lisää solun paikan index perään public void insert( Object x, int index ) int i = 0; while ( current.next!= null && i < index ) ++i; if ( i == index ) Node newnode = new Node(); newnode.item = x; newnode.next = current.next; current.next = newnode; 7 public void insertatend( Object x ) //Lisää solun loppuun while ( current.next!= null ) Node newnode = new Node(); newnode.item = x; current.next = newnode; public void delete( int index ) //Poistaa solun paikasta index if ( index == 0 ) return; int count = 0; while ( current.next!= null && count < index -1 ) ++count; if ( current.next!= null ) current.next = current.next.next; public void deletenexttoit() //Poistaa kulkurin osoittamaa if ( iterator.next!= null ) //seuraavan solun if ( iterator.next == head.next ) head = head.next; iterator.next = iterator.next.next; public void reverse() //Kääntää listan: "nuolten" Node p, q, r; //suunta päinvastaiseksi if ( head.next == null head.next.next == null ) return; // Jos lista on tyhjä tai // 1-soluinen, ei tehdä mitään p = null; q = head.next; r = head.next.next; while ( r.next!= null ) // Nuoli käännetään tässä. q.next = p; // Edetään pitkin listaa p = q; // koko ajan 3 peräkkäistä q = r; // solua muistissa r = r.next; r.next = q; // Tultiin loppuun. q.next = p; // 2 nuolta oli vielä head.next = r; // kääntämättä. public String tostring() //Merkkiesitys String str = "[]->"; while ( current.next!= null ) str = str + "[" + current.next.item + "]->"; 8
str = str + " "; return str; 9 public static void main( String[] args ) //Kokeillaan List test = new List(); for ( int i = 1; i <= 9; ++i ) test.insert( new Integer( i ), 0 ); test.insertatend( new Integer( 10 ) ); test.reverse(); test.delete(1); test.delete(9); test.advanceit(); test.deletenexttoit(); test.makecircular(); System.out.print( "Jatko: paina Enter... " ); Lue.rivi(); test.resetit(); for ( int i = 1; i <= 20; ++i ) test.advanceit(); System.out.println( (Integer)(test.getIt().getItem()) ); test.makeempty();