infor teo
infor teo
infor teo
Sistema informatico
Ampia gamma di strumenti utilizzati per svolgere algoritmi in modo
automatico.
Hardware
Un computer è costituito da vari dispositivi fisici ( chiamati hardware) :
Tastiera, schermo, mouse, dischi a stato solido, dischi rigidi, memoria, lettori
DVD.
Software
Programmi eseguibili: istruzioni e dati che consentono all'hardware di compiere
determinate funzioni.
L’architettura dell’esecutore
Elementi principali
Memoria Centrale: -- Memorizza dati e programmi in esecuzione.
-- Può essere organizzata in vari livelli (es: cache)
-- Capacità limitata
--Volatile le informazioni vengono tipicamente perse quando
l'alimentazione del computer viene spenta.
-- Accesso all’informazione molto rapido
Memoria secondaria o memoria di massa:-- Memorizza grandi quantità di
dati e programmi
--Persistente
-- Accesso molto meno rapido della memoria centrale
--Con la memoria centrale e la cache forma una gerarchia di memoria
Unità di elaborazione (CPU):-- Elabora dati, coordina trasferimento dei
dati
-- Esegue i programmi, cioè interpreta ed esegue le loro istruzioni.
Essa è composta da :
• Control Unit: dirige le operazioni delle altre unità mandando segnali di
comando e di timing. Gestisce anche il passaggio di dati con gli altri
componenti
• ALU( Aritmetic logic Unit ) : esegue le operazioni aritmetiche e logiche
(addizione, sottrazione, moltiplicazione, divisione, AND, OR,…)
• Register unit: un insieme di spazi di memoria molto piccoli e veloci.
Possono contenere istruzioni, dati o indirizzi. La ALU accede a questi
registri direttamente.
CODIFICA
CODIFICA BINARIA (BASE 2)
Codifica posizionale usata dal calcolatore per tutte le informazioni
3. Ripartire dal punto (1) fino a ottenere 0 come risultato della divisione
ESEMPIO:
Aumento e riduzione dei bit in bin
• Aumento dei bit: premettendo in modo progressivo un bit 0 a sinistra, il
valore del numero non muta. Esempio:
Somma di due numeri con stesso segno: Si sommano i valori assoluti dei due
numeri (sono due numeri naturali)
• Si effettua la sottrazione tra il valore assoluto più grande e quello più piccolo
(sono due
numeri naturali)
--Il bit più a sinistra è ancora chiamato bit di segno .Determina se il peso del
primo bit è positivo o negativo.—
N.B. : in base al bit di segno lo zero è considerato positivo
Invertire un numero in C2
L’inverso additivo (o opposto) –N di un numero N rappresentato in C2 si
ottiene:
--Il bit più significativo rivela il segno: 0 per numero positivo, 1 per numero
negativo (il numero zero è considerato positivo), ma…
--Se il numero è negativo, NON si può distaccare il bit più significativo e dire
che i bit rimanenti rappresentano il valore assoluto del numero
RIPORTO E OVERFLOW IN C2
Nelle operazioni su numeri C2, l’overflow non ha alcuna relazione con il riporto
precedente
Esadecimale o in base sedici (hex): Si usano le cifre 0-9 e le lettere A-F per i
valori 10-15
NUMERI RAZIONALI
Utilizzando opportune convenzioni possiamo pensare di rappresentare non solo
interi ma anche numeri razionali
STANDARD IEEE
Precisione quadrupla su 128 bit:
o 1 bit di segno
o 15 di esponente
o 111 di mantissa
Il codice ASCII a 7 bit è pensato per la lingua inglese. Si può estendere a 8 bit
per rappresentare il doppio dei caratteri. Si aggiungono così, ad esempio, le
lettere con i vari gradi di accento necessarie in molte lingue europee, e altri
simboli speciali ancora
Spesso, quando il codice ASCII a 7 bit è usato in un calcolatore avente parole di
memoria da un Byte (o suoi multipli), l’ottavo bit del Byte memorizzante il
carattere funziona come bit di parità • Il bit di parità serve per rilevare
eventuali errori che potrebbero avere alterato la sequenza di bit, purché siano
errori di tipo abbastanza semplice
pari:
• Se per errore un (solo) bit si inverte, il conteggio dei bit uguali a 1 dà valore
dispari! • Così si può rilevare l’esistenza di un errore da un bit (ma non
localizzarne la posizione)
• Il bit di parità non rileva gli errori da due bit; ma sono meno frequenti di quelli
da un bit
OPERATORI LOGICI
Gli operatori logici servono a combinare valori logici (VERO, FALSO) per
ottenere preposizioni più complesse
Tautologie e Contraddizioni
• Tautologia: Una espressione logica che è sempre vera, per qualunque
combinazione di valori delle variabili
Valutazione cortocircuitata
La valutazione cortocircuitata delle espressioni è una tecnica utilizzata in
programmazione elettronica e informatica per migliorare l'efficienza
nell'elaborazione di espressioni booleane.
• Valutazione cortocircuitata dell’AND: se il primo termine risulta falso,
l’espressione risulta falsa senza che gli altri termini vengano controllati
Caratteri
Le persone preferiscono lavorare con cifre decimali (0–9), lettere (A–Z e a–z) e
simboli speciali come:
Campi
• Un campo è un gruppo di caratteri o byte che trasmette un significato.
Record
Diversi campi correlati possono essere utilizzati per comporre un record.
Files
Un file è un gruppo di record correlati e contiene dati arbitrari in formati
arbitrari.
Databases
Un database è una raccolta di dati organizzata per un facile accesso e
manipolazione. Il modello più popolare è il database relazionale, in cui i dati
sono memorizzati in tabelle ( include record e campi )semplici.
Linguaggi di programmazione
I programmatori scrivono istruzioni in vari linguaggi di programmazione, alcuni
direttamente comprensibili dai computer e altri che richiedono passaggi
intermedi di traduzione. Oggi sono in uso centinaia di tali linguaggi, che
possono essere suddivisi in tre tipi generali:
Interpreter
Gli interpreter eseguono i programmi in linguaggio di alto livello direttamente.
Evitano i ritardi della compilazione, ma il codice viene eseguito più lentamente
rispetto ai programmi compilati.
Sistemi operativi
I sistemi operativi sono software che rendono l'uso dei computer più comodo
per utenti, sviluppatori di software e amministratori di sistema. Forniscono
servizi che permettono alle applicazioni di eseguire in modo sicuro, efficiente e
simultaneo.
Il linguaggio C
Pensato per sistemi operativi e compilatori, inventato nel 1972 nei Bell
Laboratories da Dennis Ritchie. E’ Hardware-independent, ovvero i programmi
scritti in C possono essere lanciate sulla maggior parte dei computer con poche
modifiche.
• Sistemi embedded
• Sistemi di comunicazione
Sviluppo di un programma C
I sistemi C generalmente consistono di diverse parti:
• Il linguaggio
4. Collegamento (Link): Unione del codice oggetto con le librerie per creare
l'eseguibile
LINGUAGGIO C
Identificatori
Gli identificatori assegnano i nomi alle entita' (variabili e funzioni). All'interno di
un programma un'entita' deve avere un identificatore univoco.
♦ sintassi: deve iniziare o con una lettera o con l'underscore ('_') e puo'
proseguire con lettere, underscore o cifre.
Variabili
Una variabile può essere descritta come un contenitore, il cui contenuto è
sempre a disposizione e rappresenta il valore della variabile stessa.
• un nome (identificatore);
• un valore (in istanti diversi la variabile può assumere valori differenti, purché
coerenti con il tipo).
Rappresentazione numerica
I tipi di dato predefiniti del C, adatti a rappresentare numeri, si differenziano tra
tipi per numeri interi oppure con virgola e per il numero di bit che sono
utilizzati nella loro rappresentazione nell’elaboratore.
• short (dichiarabile nei seguenti modi short int, signed short, signed short int);
• long (dichiarabile nei seguenti modi long int, signed long, signed long int).
-- I valori limite sono contenuti nel file limits.h, che definisce le costanti:
SHRT_MIN, SHRT_MAX, INT_MIN, INT_MAX, LONG_MIN, LONG_MAX .
Queste costanti possono ad esempio servire in un programma per controllare
se il dato immesso da un utente cade nell’intervallo di rappresentazione. Se
non lo fosse, possiamo segnalarlo all’utente al posto che far continuare
l’esecuzione e generare quindi un probabile errore di overflow/underflow.
OPERATORI
Gli operatori utilizzabili sono:
Operatori aritmetici
-
Operatore unario di cambio segno.
-espressione
Cambia il segno all'intera espressione.
+
Operatore unario +
+espressione
Equivale a espressione.
Operatore di incremento.
++ Puo' essere impiegato sia in forma postfissa (es: variabile++) che
in forma prefissa (es: ++variabile).
In entrambi i casi le due forme sono equivalenti a:
variabile = variabile + 1;
--
Operatore di decremento.
Valgono le stesse considerazioni effettuate per l'operatore di
incremento ++, tranne il fatto che le forme variabile-- e --
variabile equivalgono a:
variabile = variabile - 1;
Operatori relazionali
Operatore relazionale di uguaglianza.
== Ritorna 1 (vero) se le 2 espressioni ritornano valori uguali.
Ritorna 0 (falso) in caso contrario.
Operatore relazionale di disuguaglianza.
!= Ritorna 1 (vero) se le 2 espressioni ritornano valori
differenti.
Ritorna 0 (falso) in caso contrario.
Operatore relazionale di minoranza.
c = a&b; /* 00001010 a
* 00001100 b
* --------
* 00001000 c
= a&b */
• %d per int
• unsigned int;
• unsigned long (dichiarabile nei seguenti modi long int, unsigned long,
unsigned long int).
• char;
• unsigned char.
Tipicamente vale sizeof(char) = sizeof(int) ove sizeof(char) vale 8 bit. Tutti gli
operatori definiti su int (+, -, *, /, %, ==, !=, <, >, <=, >=) valgono sui
caratteri.
Costanti
Costanti intere:
- suffisso:
Costanti reali:
Costanti carattere:
Strutture di controllo
Le istruzioni di controllo del flusso specificano l’ordine secondo il quale i calcoli
devono essere effettuati. La maggior parte delle istruzioni sono istruzioni-
espressione, sono cioe' delle espressioni seguite dal ; (punto e virgola). La
sintassi è la seguente:
espressione;
Esempio: ;
Blocchi
In C i blocchi sono realizzati mediante l'uso delle parentesi graffe dentro le
quali vi è una sequenza di istruzioni. E' possibile dichiarare delle variabili locali
all'interno di un blocco di istruzioni C. I blocchi possono essere innestati uno
dentro l’altro a piacere: le dichiarazioni delle variabili locali seguono
immediatamente la parentesi sinistra e
Istruzioni di selezione
Il C mette a disposizione due istruzioni di selezione:
• il costrutto IF
• il costrutto SWITCH
Costrutto IF
E’ composto da una espressione e uno/due/tre/enne blocchi di codice (chiamati
i "rami" dell'if). Le due forme tipiche in cui si può presentare la sintassi relativa
al costrutto IF sono le seguenti:
1° caso:
if (espressione)
istruzione_1
2° caso:
if (espressione)
istruzione_1
else
istruzione_2
istruzione_1 viene eseguita se espressione, una volta valutata assieme a tutti i
suoi effetti collaterali, torna un valore vero (cioè non zero); altrimenti se
espressione torna un valore falso (cioe' uguale a zero) viene eseguita
istruzione_2, se esistente.
Nel caso di IF innestate, la parte else viene abbinata sempre all'ultima if posta
nello stesso blocco della else, ma non gia' abbinata ad una precedente else.
Per evitare possibili ambiguita' nelle IF innestate, e' possibile l'utilizzo di blocchi
per racchiudere i costrutti piu' interni.
Costrutto SWITCH
Il costrutto SWITCH è solitamente impiegato quando si devono controllare molti
casi. In questo modo il codice risulta essere più ordinato. Il costrutto è
composto da etichette (CASE) e da un caso generale (DEFAULT). Le etichette
del case devono essere delle costanti. La forma tipica della sintassi relativa al
costrutto SWITCH è la seguente :
switch (espressione)
{
case espr_costante_1:
[istruzioni]
...
case espr_costante_2:
[istruzioni]
...
default:
[istruzioni]
...
}
N.B. – L’etichetta default e le istruzioni ad essa relativa, sono opzionali, così
pure è opzionale la lista di istruzioni che seguono ogni etichetta (label) del
case. L'espressione viene valutata assieme ai suoi effetti collaterali ed il valore
ritornato da essa, che deve essere di tipo intero (char, int, long) viene
confrontato con le espressioni costanti associate alle case. In caso di
corrispondenza il controllo viene passato alle istruzioni ad essa associate, e
continua fino al termine dell'istruzione SWITCH (quindi fino al raggiungimento
della parentesi } di chiusura dell'istruzione). Se il valore dell'espressione non
corrisponde a nessuna delle espressioni costanti, allora il controllo viene
trasferito alla prima istruzione associata alla label default, e prosegue fino al
raggiungimento del termine dell'istruzione SWITCH. Se nemmeno la label
default è specificata, la SWITCH termina immediatamente.
Tra gli statement che compongono il corpo dello SWITCH e' permesso l'utilizzo
dell'istruzione di salto BREAK. Quando tale istruzione viene incontrata, essa
causa il termine dell'esecuzione dell'istruzione SWITCH ed il controllo passa
all'istruzione successiva.
Esempio:
Istruzioni di Iterazione
Il C mette a disposizione tre istruzioni di iterazione:
• il costrutto WHILE
• il costrutto DO-WHILE
• il costrutto FOR
Costrutto WHILE
E’ il costrutto più generale, da cui si possono ottenere tutti gli altri costrutti per
l’iterazione. La sua struttura è la seguente:
while (espressione)
istruzione
oppure:
while (espressione)
{
istruzione1
istruzione2
....
istruzionen
}
L'espressione viene valutata e, se ha valore diverso da 0 (vero), viene eseguita
l'istruzione successiva (che può anche essere un intero blocco di istruzioni,
opportunamente delimitato dalle parentesi graffe). Una volta che quest'ultima
è terminata, l'espressione viene valutata nuovamente e, se è nuovamente
vera, si ripete l'istruzione. Ciò si replica fino a quando l'espressione ha valore 0
(falso), e in questo caso il controllo si trasferisce all'istruzione successiva, al
while. Un ciclo while può essere eseguito zero o più volte, poiché l'espressione
potrebbe essere falsa già la prima volta. Si tratta di un ciclo a condizione
iniziale: prima di eseguire il ciclo si valuta la condizione. Il problema principale
delle strutture iterative è che possono entrare in ciclo infinito. Questo accade
se per un errore di programmazione o per qualche condizione esterna alla
espressione del while rimane sempre vera.
Costrutto DO-WHILE
Il costrutto DO-WHILE presenta la seguente sintassi:
do
istruzione
while (espressione);
Per ogni ciclo viene eseguita l’istruzione, poi viene valutata l'espressione. Se
risulta vera (diversa da zero) il ciclo viene riavviato, altrimenti l'istruzione DO-
WHILE ha termine. L’istruzione viene eseguita almeno una volta: infatti il
costrutto do-while è un ciclo a condizione finale: prima di valutare la condizione
si esegue il ciclo. Quindi il corpo del ciclo viene eseguito sempre almeno una
volta Al posto dell’istruzione può esserci un blocco.
Costrutto FOR
Il costrutto FOR è equivalente al costrutto WHILE, ma l’uso è consigliato solo
nel caso in cui il numero di iterazioni SIA NOTO A PRIORI.
Per esempio, se si deve scandire una struttura dati che ha sempre N elementi,
allora si userà un ciclo FOR. Nel caso in cui si debba continuare a chiedere
all’utente di digitare un numero finché non viene immesso un numero pari a
zero, allora si userà un costrutto WHILE in quanto il numero di iterazioni non è
noto a priori.
ISTRUZIONI DI INPUT/OUTPUT:
Output: printf
Obiettivo: dichiarare una variabile i intera, assegnarvi un valore e stamparla a
video.
Input: scanf
Obiettivo: dichiarare una variabile i intera, leggere un valore dalla tastiera e
copiarlo in una variabile. Un semplice programma che esegue queste azioni è il
seguente:
#include <stdio.h>
int main()
{
int i;
printf("immetti un numero intero :");
scanf("%d", &i);
printf("il valore memorizzato e’ %d", i); /* lo stampiamo per controllo */
}
Nella parte dichiarativa si dichiara la variabile i come intera (int). Nella prima
riga della parte esecutiva si stampa un messaggio per l’utente affinché capisca
che gli stiamo chiedendo di battere un numero intero sulla tastiera.
L’immissione si conclude automaticamente con la pressione del tasto enter
(invio). La terza riga del main chiama la funzione scanf che permette di copiare
il numero letto da tastiera nella variabile i.
Alla sinistra della virgola è scritto come deve essere letto il dato immesso dalla
tastiera. In questo caso l’indicazione “%d” indica che deve essere letto come
un numero intero. Questa considerazione non è banale. Infatti se l’utente
digitasse 1024 sulla tastiera seguito dalla pressione dell’enter, il sistema
potrebbe interpretare questo dato sia come il numero intero 1024 ma anche
come la stringa composta dai caratteri ‘1’, ‘0’, ‘2’ e ‘4’. Indicando %d, si toglie
ogni possibilità sull’interpretazione di come il dato debba essere letto ossia
come un numero intero.
Alla destra della virgola è presente l’indirizzo dove il valore letto deve essere
memorizzato (&i significa “all’indirizzo di i”).
L’ultima riga del main stampa il valore immesso. In questo modo è possibile
effettuare una verifica secondo le modalità già descritte a proposito della
funzione printf.
LIBRERIE
- #include <stdio.h> // libreria standard
- #include <stdlib.h> // libreria per avere numeri casuali (e anche altre cose ->
vedi memoria dinamica)
ARRAY
vettori di elementi indicizzati, omogenei, memorizzati in celle di memora
consecutive.
int array[N];
La lunghezza dell’array deve essere per forza dichiarata. Questo array avrà
lunghezza N. l’ultimo elemento si trova nella cella N-1. (l’array riempie dalla
cella 0 alla cella N-1)
Un array può essere considerato come un puntatore !!! (come un puntatore che
punta alla prima cella dell’array (la cella 0)). Il nome di un array è una costante
di tipo puntatore.
a. Bubble sort: confronto uno a uno gli elementi uno di fianco all’altro e
posiziono prima quello minore. Ripete l’operazione quanti sono gli
elementi del vettore.
Es: void bubblesort(int v[], int n) {
int i,k;
int temp;
for(i = 0; i<n-1; i++) {
for(k = 0; k<n-1-i; k++) {
if(v[k] > v[k+1]) {
temp = v[k];
v[k] = v[k+1];
v[k+1] = temp;
}
}
}
}
STRINGA
STRINGA ≠ ARRAY
o \n, \t ecc
Dopo aver usato la strtok devo riusarla mettendo come primo parametro un
puntatore a NULL, se no entro in un loop (mi legge sempre la prima parola
della stringa che sto analizzando).
MATRICI
schieramento rettangolare di oggetti (di solito numeri) organizzati in righe e
colonne Matrice[righe][colonne]; (Matrice righeXcolonne )
OPERAZIONI:
- Somma: due matrici si possono sommare se hanno le stesse dimensioni
- Moltiplicazione Per uno scalare: 2xMAT[i,j]-> moltiplico ogni elemento per 2
- Moltiplicazione Tra due matrici: avviene solo se il numero di righe m di B
coincide con il numero di colonne n di A. => il risultato sarà una matrice di m
righe e n colonne.
tipi enumerativi: tipo costituito elencando al suo interno tutti i suoi valori
( scritti tra le {}).
ES: Typedef enum {lun, mar, mer, gio, ven, sab,dom} Giornodellasettimana;
STRUCT
(chiamate anche record) Corrisponde a collezioni di variabili eterogenee.
Aggregati di dati, ogni dato è chiamato campo.
Es:
typedef struct {
char titolo[30];
int anno[4];
char regista[30];
}t_film //nome della struct
PUNTATORI
- & : operatore di referenziazione, ci permette di accedere all’indirizzo di una
variabile
- Puntatori: variabili il cui valore è l’indirizzo di un’altra variabile.
ES:
Int x=3;
int *punt;
Punt = &x; //al valore di punt corrisponde l’indirizzo di x
* -operatore di derefenziazione
int x=3;
int *p;
p=&x;
DOPPIO PUNTATORE
int **c; //la variabile c punta ad una variabile che a sua volta punta ad una
variabile di tipo int.
Attenzione al tipo- un puntatore che punta ad una variabile a di tipo1 non può
puntare anche ad una variabile b di un altro tipo.
NULL- costante simbolica rappresenta un valore speciale che può essere
assegnata ad un puntatore. Significa che il puntatore non punta a niente. Il
valore iniziale di un puntatore dovrebbe essere NULL. ( Si ha la costante NULL -
#include <stdlib.h> )
FUNZIONI
- Invocazione: quando uso la funzione all’interno del main. Nel prototipo non è
necessario specificare un nome per i parametrI (( int somma_interi(int, int);
equivale a scrivere int somma_interi (int addendo1, int addendo2); ))
risultato:
- non può essere un array
- può essere una struct anche se questa contiene degli array al suo interno
parametri:
- non sono modificabili ad eccezione degli array.
1. Nella definizione della funzione il parametro deve essere di tipo puntore (*p)
2. Nella chiamata si deve passare l’indirizzo (usando &) del parametro attuale
da modificare (&varLocale)
3. Nel corpo della funzione si usa l’operatore "* " di dereferenziazione per
riferirsi al valore del parametro (*p)
Esempio:
#include "stdio.h"
void swap(int * , int *);
int main(){
int a=4, b=9;
swap( &a, &b); //quando chiami la funzione non devi specificare il tipo di
funzione
printf("a= %d, b=%d", a, b);
return 0;
}
void swap (int *a, int *b){
int temp=0;
temp= *a;
*a=*b;
*b=temp;
FUNZIONI RICORSIVE
Funzioni ricorsive: una funzione che chiama se stessa. Per ottimizzare una
funzione in poche
righe.
Bisogna definire due casistiche fondamentali:
1. Caso base. (quando faccio terminare la mia funzione ricorsiva).
2. Passi induttivi. Quelli che si ripetono.
STRUTTURE DI DATI
strutture di dati dinamiche che possono crescere e ridursi durante l’esecuzione
• Liste collegate (linked list) :
--Collezioni di elementi di dati «allineati in una riga»
-- Permettono di inserire ed eliminare elementi da qualsiasi punto
• Pile (stack)
-- Utilizzate nei compilatori e nei sistemi operativi
--Permettono di inserire ed eliminare elementi solo dalla cima della pila
• Code (queue)
-- Rappresentano le file di attesa
-- Permettono di inserire elementi solo alla fine della coda ed eliminarli solo
dalla testa
• Alberi binari (binary tree)
-- Facilitano la ricerca e l’ordinamento dei dati ad alta velocità
-- Permettono l’eliminazione efficiente dei dati duplicati
-- Utilizzati per la compilazione di espressioni nel linguaggio macchina
void* malloc (n°di byte da allocare); //alloca size byte nella memoria e ne
ritorna il puntatore void.
Il puntatore punta ad una variabile che non ha nome: può essere utilizzata solo
tramite il suo puntatore. crea in memoria una variabile di TipoDato e restituisce
l’indirizzo del primo byte riservato alla variabile. Se P è una variabile di tipo
puntatore TipoDato, l’istruzione è
P= malloc(sizeof(TipoDato));
si può fare riferimento ad una variabile creata dinamicamente solo tramite
puntatore. Se non c’è più memoria disponibile la malloc restituisce NULL.
• La funzione free : Questa funzione dice che la zona di memoria non ci serve
più, e che può quindi venire usata in altro modo. Il vantaggio di chiamare la
funzione free è che, in questo modo, la memoria non più utilizzata dal
programma può venire ``riciclata'', ossia riutilizzata.
• L’operatore sizeof
- void* calloc (size_t num, size_t size); //alloca num elementi di dimensione size
allocati a 0
Una lista collegata è una collezione con organizzazione lineare di oggetti struct
autoreferenziali chiamati nodi. Sono connessi da collegamenti di puntatori. Si
accede a una lista collegata tramite un puntatore al suo primo nodo. Si accede
ai nodi successivi tramite il puntatore di collegamento memorizzato in ogni
nodo.
Idati sono memorizzati dinamicamente in una lista collegata creando ogni nodo
quando necessario. Un nodo può contenere dati di ogni tipo. Le pile e le code
sono strutture lineari di dati. Sono versioni vincolate di liste collegate.
In termini di accesso, gli array offrono un vantaggio: gli elementi sono registrati
in memoria in modo contiguo, consentendo un accesso immediato calcolando
l’indirizzo in base alla posizione. Al contrario, le liste collegate non offrono
accesso immediato ai loro elementi, rendendo l’operazione più lenta in
confronto.
Pile
Una pila o stack può essere implementata come versione vincolata di una lista
collegata. In una pila, è possibile aggiungere nuovi nodi ed eliminare quelli
esistenti solo in cima. Questa struttura di dati segue il principio Last-In, First-
Out (LIFO), dove il primo elemento a uscire è l’ultimo che è stato inserito. Una
pila si rappresenta tramite un puntatore all’elemento in cima. Il membro link
nell’ultimo nodo della pila è impostato a NULL, indicando il fondo della pila. Non
terminare una pila con NULL può causare errori in fase di esecuzione.
Nelle pile, stackPtr punta all’elemento in cima. Si tratta di una lista collegata in
cui inserimenti e cancellazioni possono avvenire solo sulla cima. Le principali
funzioni per manipolare una pila sono push e pop.
--La funzione push crea un nuovo nodo e lo colloca in cima alla pila.
-- La funzione pop rimuove il nodo in cima alla pila, libera la memoria occupata
e restituisce il valore del nodo rimosso.
CODE
Una coda è simile alla fila davanti alla cassa del supermercato. La prima
persona in fila è servita per prima, mentre i nuovi clienti si aggiungono alla fine
della coda. I nodi della coda possono essere estratti solo dalla testa della coda
e inseriti solo alla fine. Questa struttura segue il principio First-In, First-Out
(FIFO).
ALBERI
Gli alberi sono strutture dati non lineari. A differenza di liste, pile e code, gli
alberi permettono ai nodi di avere due o più collegamenti. Un albero binario è
una struttura in cui ogni nodo ha al massimo due figli. Il nodo radice è il primo
nodo dell’albero. Ogni collegamento di un nodo si riferisce a un figlio, e due figli
dello stesso nodo sono chiamati fratelli. Un nodo senza figli è una foglia, e i
nodi foglia hanno i collegamenti ai nodi figli impostati a NULL.
-- in ordine,
-- in pre-ordine
-- post-ordine.
La ricerca in un albero binario è veloce, specialmente se l’albero è ben
organizzato. Ogni livello contiene il doppio degli elementi del livello
precedente, e una ricerca in un albero con n elementi richiede al massimo log n
livelli. Ad esempio, in un albero con 1.000.000 di nodi, sono necessari circa 20
confronti per trovare un nodo o determinare che non esiste.
Abbiamo già analizzato come sia possibile ordinare un array di dati in ordine
crescente o decrescente utilizzando il metodo Bubble Sort. Ci si può chiedere,
tuttavia, se esistano algoritmi più efficienti. La notazione "O grande" è uno
strumento utile che consente di stimare il tempo di esecuzione di un algoritmo
nel caso peggiore. Nel corso della trattazione esamineremo diversi algoritmi di
ordinamento, confrontandoli sia per il tempo di esecuzione che per l'uso della
memoria.
ciclo interno cerca l’elemento più piccolo tra quelli rimanenti ((Viene eseguito 𝑛
((Inserisce l’elemento più piccolo rimanente nella sua posizione ordinata)). Il
− 1 volte nella prima iterazione del ciclo esterno, 𝑛 − 2 volte nella seconda
iterazione; Il numero totale di iterazioni del ciclo interno sono
Es:
--Efficienza merge sort: L'ordinamento per fusione è più efficiente rispetto a
quello per inserzione e selezione. La prima chiamata alla funzione sortSubArray
genera due chiamate ricorsive alla stessa funzione, ciascuna con un sottoarray
di dimensioni circa pari alla metà dell'array originale, seguite da una chiamata