Difference between revisions of "Esempi didattici in Python"

From Sistemi Operativi
Jump to navigation Jump to search
m
 
Line 169: Line 169:
 
Ma le code e le pile possono venir viste anche come classi derivate della classe liste.
 
Ma le code e le pile possono venir viste anche come classi derivate della classe liste.
 
La prima versione chiama i metodi della classe lista esplicitamente:
 
La prima versione chiama i metodi della classe lista esplicitamente:
<source lang=pyhton>
+
<source lang=python>
 
class queue(list):
 
class queue(list):
 
     def __init__(self):
 
     def __init__(self):
Line 200: Line 200:
 
La seconda versione usa la ereditarieta': i metodi vengono richiamati semplicemente per nome, assumendo che si faccia riferimento alla prima definizione utile presente in una delle classi "ave" (anchestor).
 
La seconda versione usa la ereditarieta': i metodi vengono richiamati semplicemente per nome, assumendo che si faccia riferimento alla prima definizione utile presente in una delle classi "ave" (anchestor).
  
<source lang=pyhton>
+
<source lang=python>
 
class queue(list):
 
class queue(list):
 
     def __init__(self):
 
     def __init__(self):
Line 235: Line 235:
  
 
Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva.
 
Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva.
<source lang=pyhton>
+
<source lang=python>
 
def sieve(n):
 
def sieve(n):
 
     sv={x for x in range(1,n)}
 
     sv={x for x in range(1,n)}
Line 250: Line 250:
  
 
Sort per selezione:
 
Sort per selezione:
<source lang=pyhton>
+
<source lang=python>
 
def selection_sort(v):
 
def selection_sort(v):
 
     for i in range(len(v)):
 
     for i in range(len(v)):
Line 259: Line 259:
  
 
Sort per inserzione:
 
Sort per inserzione:
<source lang=pyhton>
+
<source lang=python>
 
def insertion_sort(v):
 
def insertion_sort(v):
 
     for i in range(1,len(v)):
 
     for i in range(1,len(v)):
Line 268: Line 268:
  
 
Bubblesort:
 
Bubblesort:
<source lang=pyhton>
+
<source lang=python>
 
def bubblesort(v):
 
def bubblesort(v):
 
     for i in range(1,len(v)):
 
     for i in range(1,len(v)):
Line 277: Line 277:
  
 
Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard ''sorted''):
 
Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard ''sorted''):
<source lang=pyhton>
+
<source lang=python>
 
def rqsorted(v):
 
def rqsorted(v):
 
     if v:
 
     if v:
Line 289: Line 289:
  
 
Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale:
 
Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale:
<source lang=pyhton>
+
<source lang=python>
 
def merge(v1,v2):
 
def merge(v1,v2):
 
     v=[]
 
     v=[]
Line 313: Line 313:
  
 
La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva.
 
La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva.
<source lang=pyhton>
+
<source lang=python>
 
def rmerge(v1,v2):
 
def rmerge(v1,v2):
 
     if not v1:
 
     if not v1:

Latest revision as of 10:48, 28 October 2019

Questa pagina contiene alcuni esempi didattici di codice Python

Divisori

Esempio sui divisori. Il primo programma ha uno stile Pascal o C:

#!/usr/bin/env python3

def divisori(x):
    s=[]
    for i in range(2,x):
        if x%i == 0:
            s.append(i)
    return s;

def primo(x):
    if divisori(x):
        return False
    else:
        return True

def divisoriprimi(x):
    s=[]
    for i in divisori(x):
        if (primo(i)):
            s.append(i)
    return s

if __name__ == '__main__':
    n=int(input("dammi n "))
    if primo(n):
        print(n ,"e' primo")
    else:
        print("i divisori di ", n, "sono", divisori(n))
        print("i divisori primi di ", n, "sono", divisoriprimi(n))

Ma il Python ha anche il tipo insieme (set) che e' meglio indicato per questo esempio:

#!/usr/bin/env python3

def divisori(x):
    s=set()
    for i in range(2,x):
        if x%i == 0:
            s.add(i)
    return s;

def primo(x):
    if divisori(x):
        return False
    else:
        return True

def divisoriprimi(x):
    s=set()
    for i in divisori(x):
        if (primo(i)):
            s.add(i)
    return s

if __name__ == '__main__':
    n=int(input("dammi n "))
    if primo(n):
        print(n ,"e' primo")
    else:
        print("i divisori di ", n, "sono", divisori(n))
        print("i divisori primi di ", n, "sono", divisoriprimi(n))

Lo stesso esempio con la Set Comprehension (come si traduce? si traduce?):

#!/usr/bin/env python3

def divisori(x):
    return {y for y in range(2,x) if x%y == 0}

def primo(x):
    return not divisori(x)

def divisoriprimi(x):
    return {y for y in divisori(x) if primo(y)}

if __name__ == '__main__':
    n=int(input("dammi n "))
    if primo(n):
        print(n ,"e' primo")
    else:
        print("i divisori di ", n, "sono", divisori(n))
        print("i divisori primi di ", n, "sono", divisoriprimi(n))

Il primo e' piu' algoritmico, passo a passo, ma anche piu' contorto. Il secondo e' piu' elegante ma puo' apparire magico-misterioso.

Fattorizzazione, mcm e MCD

Il metodo migliore per calcolare il massimo comun divisore e' l'algoritmo di Euclide:

def gcd(x, y):
  while True:
    if x < y:
      x, y = y, x
    x -= y
    if x == 0:
      return y

def lcm(x, y):
  return x * y // gcd(x, y)

Coda/Pila e programmazione a oggetti

Le code e le pile (queue e stack) possono essere implementate a partire dalle liste. Le funzioni enqueue/dequeue per le code e push/pop per le pile possono essere implementate cosi':

def enqueue(s,x):
    s.append(x)

def dequeue(s):
    return s.pop(0)

def push(s,x): 
    s.append(x)

def pop(s):
    return s.pop()

Passando alla programmazione a oggetti, la versione migliore e' quella con un attributo nascosto "lista", perche' una coda ha una lista, non è una lista

class queue:
    def __init__(self):
        self._list=[]

    def enqueue(self, x):
        self._list.append(x)

    def dequeue(self):
        return self._list.pop(0)

    def empty(self):
        return not self._list

    def head(self):
        return self._list[0]

    def __str__(self):
        return str(self._list)

class stack:
    def __init__(self):
        self._list=[]

    def push(self, x):
        self._list.append(x)

    def pop(self):
        return self._list.pop()

    def empty(self):
        return not self._list

    def __str__(self):
        return str(self._list)


Il setaccio di Eratostene

Ai miei tempi si chiamava crivello!

Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva.

def sieve(n):
    sv={x for x in range(1,n)}
    for i in range(2,n//2):
        if i in sv:
            sv -= {x for x in range(2*i,n,i)}
    return [x for x in range(n) if x in sv]

Ordinamento

Ecco una carrellata di funzioni per l'ordinamento... Le prime sono funzioni per l'ordinamento di vettori/liste sul posto, modificando la sequenza degli elementi.

Sort per selezione:

def selection_sort(v):
    for i in range(len(v)):
        for j in range(i+1,len(v)):
            if v[j] < v[i]:
                v[i],v[j]=v[j],v[i]

Sort per inserzione:

def insertion_sort(v):
    for i in range(1,len(v)):
        for j in range(i):
            if v[j] > v[i]:
                v.insert(j, v.pop(i))

Bubblesort:

def bubblesort(v):
    for i in range(1,len(v)):
        for j in range(len(v)-i):
            if v[j+1] < v[j]:
                v[j+1],v[j]=v[j],v[j+1]

Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard sorted):

def rqsorted(v):
    if v:
        pivot=v[0]
        lesser=[x for x in v[1:] if x <= pivot]
        greater=[x for x in v[1:] if x > pivot]
        return rqsorted(lesser) + [pivot] + rqsorted(greater)
    else:
        return []

Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale:

def merge(v1,v2):
    v=[]
    while True:
        if not v1:
            return v+v2
        elif not v2:
            return v+v1
        else:
            if v1[0] < v2[0]:
                v.append(v1.pop(0))
            else:
                v.append(v2.pop(0))

def mergesort(v):
    lv=len(v)
    ls=1;
    while v[ls:]:
        for i in range(0,lv,2*ls):
            v[i:i+2*ls]=merge(v[i:i+ls],v[i+ls:i+2*ls])
        ls *= 2

La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva.

def rmerge(v1,v2):
    if not v1:
        return v2
    elif not v2:
        return v1
    elif v1[0] < v2[0]:
        return v1[0:1]+rmerge(v1[1:],v2)
    else:
        return v2[0:1]+rmerge(v1,v2[1:])

def rmergesorted(v):
    half=len(v)//2
    if half == 0:
        return v
    else:
        return rmerge(rmergesorted(v[:half]),rmergesorted(v[half:]))

Le definizioni delle funzioni merge e rmerge non sono state inserite nella definizione delle funzioni mergesort e rmergesorted (rispettivamente) perche' hanno una funzionalita' specifica di fusione di vettori ordinati e possono essere usate anche indipendentemente dal mergesort.