(* LIB_LISTANUM.PAS *) (* Definizione di classe per gestire liste concatenate *) (* doppie di numeri longint. *) (* *) (* Autore: Corrado Damiano *) (* Data ultima versione: 16-6-2026 *) UNIT lib_listanum; (*--------------------------------*) INTERFACE type (* puntatore a un record di tipo nodo_num *) p_nodo_num = ^nodo_num; (* puntatore doppio *) pp_nodo_num = ^p_nodo_num; (* puntatore a longint *) p_numero = ^longint; (* record nodo per creare una lista concatenata doppia *) nodo_num = record num: longint; p_preced: p_nodo_num; p_prossimo: p_nodo_num; end; (*--------------------------------*) (* classe per istanziare oggetti gestori di liste *) gestore_lista_num = object protected (* nome della lista *) nome: string; (* numero di nodi messi in lista *) n_nodi: longint; (* numero massimo di nodi inseribili in lista *) max_nodi: longint; (* puntatori a primo e ultimo nodo della lista *) p_primo: p_nodo_num; p_ultimo: p_nodo_num; (* puntatore a nodo di cui mostrare il numero contenuto, *) (* usando il metodo leggi_num_corrente *) p_nodo_corrente: p_nodo_num; public (* inizializzazione e svuotamento lista *) constructor iniz(str_nome: string; num_max_nodi: longint); function svuota: longint; (* visualizzazione dati lista *) function calcola_lungh_num(n: longint): longint; function cerca_lungh_max: longint; function mostra(numeri_riga: longint): boolean; (* iterazione per leggere i numeri in lista *) function iniz_p_corrente: boolean; function leggi_num_corrente(pn: p_numero): boolean; (* estrazione informazioni *) function leggi_n_nodi: longint; function conta_num(n: longint): longint; function conta_p_nodo(p: p_nodo_num): longint; public function leggi_num_posiz(pos: longint; pn: p_numero): boolean; function cerca_min_max(pn_min: p_numero; pn_max: p_numero): boolean; function calcola_tipo_ordine: byte; (* inserimento numeri in lista *) function alloca_nodo(n: longint): p_nodo_num; function ok_metti_nodo: boolean; function metti_inizio(n: longint): boolean; function metti_fine(n: longint): boolean; private function cerca_magg_ug(n: longint): p_nodo_num; public function metti_ord_1(n: longint): boolean; function metti_ord_2(n: longint): boolean; function metti_numeri_cas(num_nodi: longint; val_max: longint): longint; (* inserimento in lista di nodi gia' allocati *) function metti_nodo_inizio(p: p_nodo_num): boolean; function metti_nodo_fine(p: p_nodo_num): boolean; private function metti_nodo_prima(p_base: p_nodo_num; p: p_nodo_num): boolean; function metti_nodo_dopo(p_base: p_nodo_num; p: p_nodo_num): boolean; (* estrazione nodi da lista *) procedure azzera_pp_nodo(p: p_nodo_num); function togli_nodo(p: p_nodo_num): boolean; public function estraz_primo: p_nodo_num; function estraz_ultimo: p_nodo_num; (* cancellazione nodi *) function cancella_nodo(pp: pp_nodo_num): boolean; function cancella_num(n: longint): longint; function cancella_ripetiz: longint; (* ordinamento e inversione lista *) function ordina: boolean; function inverti: boolean; (* esportazione/importazione dati lista *) function esporta(pp: pp_nodo_num): longint; function importa(p: p_nodo_num): longint; end; (* fine definizione classe *) (* funzione non appartenente alla classe, per spostare nodi *) (* da una lista all'altra *) function sposta_nodo(var G_lista_1: gestore_lista_num; var G_lista_2: gestore_lista_num; p: p_nodo_num): boolean; (*--------------------------------*) IMPLEMENTATION (* inizializzazione e svuotamento lista *) constructor gestore_lista_num.iniz(str_nome: string; num_max_nodi: longint); begin nome := str_nome; n_nodi := 0; max_nodi := num_max_nodi; p_primo := nil; p_ultimo := nil; p_nodo_corrente := nil; end; (* fine costruttore *) (* dealloca tutti i nodi e passa in uscita *) (* il numero di nodi cancellati; *) (* nome della lista e numero max di nodi *) (* restano invariati *) function gestore_lista_num.svuota: longint; var conta: longint; p_temp: p_nodo_num; begin (* contatore dei nodi cancellati *) conta := 0; if p_primo = nil then begin svuota := conta; exit; end; while p_primo <> nil do begin inc(conta); (* puntatore al secondo nodo *) p_temp := p_primo^.p_prossimo; dispose(p_primo); p_primo := p_temp; end; p_ultimo := nil; n_nodi := 0; svuota := conta; end; (* fine svuota *) (*--------------------------------*) (* visualizzazione dati lista *) (* rende in uscita il numero di cifre del numero di input *) function gestore_lista_num.calcola_lungh_num(n: longint): longint; var lungh_n: longint; begin if n < 10 then lungh_n := 1; if (n >= 10) and (n < 100) then lungh_n := 2; if (n >= 100) and (n < 1000) then lungh_n := 3; if (n >= 1000) and (n < 10000) then lungh_n := 4; if (n >= 10000) and (n < 100000) then lungh_n := 5; if (n >= 100000) and (n < 1000000) then lungh_n := 6; if (n >= 1000000) and (n < 10000000) then lungh_n := 7; if (n >= 10000000) and (n < 100000000) then lungh_n := 8; if (n >= 100000000) and (n < 1000000000) then lungh_n := 9; if n >= 1000000000 then lungh_n := 10; calcola_lungh_num := lungh_n; end; (* fine calcola_lungh_num *) (* rende in uscita la lunghezza massima (num. di cifre) *) (* dei numeri presenti in lista; serve per formattare *) (* i numeri visualizzati con la procedura successiva *) function gestore_lista_num.cerca_lungh_max: longint; var lungh_max: longint; p_corrente: p_nodo_num; num: longint; lungh_n: longint; begin lungh_max := 1; p_corrente := p_primo; while p_corrente <> nil do begin num := p_corrente^.num; lungh_n := calcola_lungh_num(num); if lungh_n > lungh_max then begin lungh_max := lungh_n; end; p_corrente := p_corrente^.p_prossimo; end; cerca_lungh_max := lungh_max; end; (* fine cerca_lungh_max *) (* mostra i numeri contenuti nella lista, dal primo all'ultimo; *) (* numeri_riga indica quanti numeri visualizzare in ogni riga *) function gestore_lista_num.mostra(numeri_riga: longint): boolean; var lungh_max: longint; conta: longint; p_corrente: p_nodo_num; num: longint; begin if (numeri_riga < 1) or (numeri_riga > 100) then begin writeln('argomento numeri_riga ', numeri_riga, ' non ammesso'); mostra := false; exit; end; writeln; writeln(nome, ' (', n_nodi, '-', max_nodi, '): '); lungh_max := cerca_lungh_max; (* contatore dei numeri mostrati in una riga *) conta := 0; p_corrente := p_primo; while p_corrente <> nil do begin inc(conta); num := p_corrente^.num; write(num:lungh_max); write(' '); if conta mod numeri_riga = 0 then begin writeln; end; p_corrente := p_corrente^.p_prossimo; end; (* con liste che hanno piu' di 1000 nodi il numero *) (* di nodi viene mostrato anche alla fine *) if n_nodi > 1000 then begin writeln; writeln('Nodi: ', n_nodi, '-', max_nodi); end; writeln; writeln; mostra := true; end; (* fine mostra *) (*--------------------------------*) (* iterazione per leggere i numeri in lista *) (* i programmi che usano un'istanza del gestore di liste *) (* potrebbero avere bisogno di conoscere tutti i numeri *) (* in lista, senza accedere ai puntatori ai nodi; *) (* questo viene fatto usando il puntatore p_nodo_corrente, *) (* che punta al nodo il cui numero sara' passato in uscita *) (* alla prossima chiamata di leggi_num_corrente *) (* metodo da chiamare prima della lettura dei nodi; *) (* se la lista contiene almeno un nodo, a p_nodo_corrente *) (* viene assegnato l'indirizzo del primo nodo; *) (* il booleano in uscita indica se l'operazione e' stata *) (* fatta oppure no *) function gestore_lista_num.iniz_p_corrente: boolean; begin if p_primo <> nil then begin p_nodo_corrente := p_primo; iniz_p_corrente := true; exit; end; (* lista vuota *) p_nodo_corrente := nil; iniz_p_corrente := false; end; (* fine iniz_p_corrente *) (* se p_nodo_corrente punta a un nodo, inserisce in pn^ *) (* il valore del numero contenuto nel nodo; *) (* dopodiche' aggiorna p_nodo_corrente, in modo che punti *) (* al nodo successivo a quello letto; il booleano in uscita *) (* indica se la lettura e' stata fatta oppure no *) function gestore_lista_num.leggi_num_corrente(pn: p_numero): boolean; begin if p_nodo_corrente <> nil then begin pn^ := p_nodo_corrente^.num; p_nodo_corrente := p_nodo_corrente^.p_prossimo; leggi_num_corrente := true; exit; end; leggi_num_corrente := false; end; (* fine leggi_num_corrente *) (*--------------------------------*) (* estrazione informazioni *) (* rende in uscita il numero di nodi in lista *) function gestore_lista_num.leggi_n_nodi: longint; begin leggi_n_nodi := n_nodi; end; (* rende in uscita il numero di occorrenze di n *) (* presenti in lista *) function gestore_lista_num.conta_num(n: longint): longint; var conta: longint; p_corrente: p_nodo_num; begin (* contatore delle occorrenze di n *) conta := 0; if p_primo = nil then begin conta_num := conta; exit; end; p_corrente := p_primo; while p_corrente <> nil do begin if p_corrente^.num = n then begin inc(conta); end; p_corrente := p_corrente^.p_prossimo; end; conta_num := conta; end; (* fine conta_num *) (* rende in uscita il numero di nodi puntati da p; *) (* puo' servire per rilevare anomalie o per verificare *) (* l'appartenenza di un nodo a una lista *) function gestore_lista_num.conta_p_nodo(p: p_nodo_num): longint; var conta: longint; p_corrente: p_nodo_num; begin (* contatore dei nodi puntati da p *) conta := 0; if p = nil then begin conta_p_nodo := conta; exit; end; p_corrente := p_primo; while p_corrente <> nil do begin if p_corrente = p then begin inc(conta); end; p_corrente := p_corrente^.p_prossimo; end; conta_p_nodo := conta; end; (* fine conta_p_nodo *) (* legge in lista il numero posto nel nodo nella posizione indicata; *) (* le posizioni sono contate a partire da 1; il valore trovato viene *) (* assegnato al numero puntato da pn *) function gestore_lista_num.leggi_num_posiz(pos: longint; pn: p_numero): boolean; var conta: longint; p_corrente: p_nodo_num; begin if p_primo = nil then begin leggi_num_posiz := false; exit; end; if (pos < 1) or (pos > n_nodi) then begin leggi_num_posiz := false; exit; end; (* contatore dei nodi letti *) conta := 0; p_corrente := p_primo; while p_corrente <> nil do begin inc(conta); if conta = pos then begin pn^ := p_corrente^.num; p_corrente := nil; end else begin p_corrente := p_corrente^.p_prossimo; end; end; leggi_num_posiz := true; end; (* fine leggi_num_posiz *) (* cerca i valori minimo/massimo presenti in lista; *) (* vengono assegnati ai numeri puntati da pn_min, pn_max *) function gestore_lista_num.cerca_min_max(pn_min: p_numero; pn_max: p_numero): boolean; var p_corrente: p_nodo_num; n_min: longint; n_max: longint; begin if p_primo = nil then begin cerca_min_max := false; exit; end; p_corrente := p_primo; n_min := p_corrente^.num; n_max := p_corrente^.num; while p_corrente <> nil do begin if p_corrente^.num < n_min then begin n_min := p_corrente^.num; end; if p_corrente^.num > n_max then begin n_max := p_corrente^.num; end; p_corrente := p_corrente^.p_prossimo; end; pn_min^ := n_min; pn_max^ := n_max; cerca_min_max := true; end; (* fine cerca_min_max *) (* verifica se una lista e' ordinata; *) (* valori di uscita: *) (* 0: lista non ordinata; *) (* 1: lista ordinata senza ripetizioni; *) (* 2: lista ordinata con ripetizioni; *) (* liste vuote o con un solo nodo sono considerate ordinate senza ripetizioni (1); *) (* liste con valori tutti uguali sono considerate ordinate con ripetizioni (2); *) (* quindi una lista e' non ordinata (0) solo quando c'e' almeno una coppia *) (* di numeri consecutivi tali che il primo e' maggiore del secondo *) function gestore_lista_num.calcola_tipo_ordine: byte; var tipo: byte; num_preced: longint; p_corrente: p_nodo_num; begin tipo := 1; (* lista vuota *) if p_primo = nil then begin calcola_tipo_ordine := tipo; exit; end; (* lista con un solo nodo *) if p_primo = p_ultimo then begin calcola_tipo_ordine := tipo; exit; end; num_preced := p_primo^.num; (* inizia la lettura dal secondo nodo *) p_corrente := p_primo^.p_prossimo; while p_corrente <> nil do begin if p_corrente^.num >= num_preced then begin if p_corrente^.num = num_preced then begin tipo := 2; end; num_preced := p_corrente^.num; p_corrente := p_corrente^.p_prossimo; end else begin tipo := 0; p_corrente := nil; end; end; calcola_tipo_ordine := tipo; end; (* fine calcola_tipo_ordine *) (*--------------------------------*) (* inserimento numeri in lista *) (* alloca un nuovo nodo contenente il numero di input; *) (* il valore del puntatore al nodo viene passato in uscita *) function gestore_lista_num.alloca_nodo(n: longint): p_nodo_num; var p_nuovo: p_nodo_num; begin p_nuovo := nil; new(p_nuovo); if p_nuovo <> nil then begin p_nuovo^.num := n; p_nuovo^.p_preced := nil; p_nuovo^.p_prossimo := nil; end; alloca_nodo := p_nuovo; end; (* fine alloca_nodo *) (* verifica se e' possibile l'inserimento di un nuovo nodo *) function gestore_lista_num.ok_metti_nodo: boolean; begin if max_nodi > n_nodi then begin ok_metti_nodo := true; exit; end; ok_metti_nodo := false; end; (* fine ok_metti_nodo *) (* mette il numero di input in un nuovo nodo *) (* da inserire a inizio lista; funziona anche *) (* con lista vuota *) function gestore_lista_num.metti_inizio(n: longint): boolean; var p_nuovo: p_nodo_num; begin if ok_metti_nodo = false then begin metti_inizio := false; exit; end; p_nuovo := alloca_nodo(n); if p_nuovo = nil then begin metti_inizio := false; exit; end; (* lista vuota *) if p_primo = nil then begin p_primo := p_nuovo; p_ultimo := p_nuovo; p_nuovo := nil; n_nodi := 1; metti_inizio := true; exit; end; (* il nuovo nodo deve puntare in avanti all'ex primo nodo *) p_nuovo^.p_prossimo := p_primo; (* l'ex primo nodo deve puntare all'indietro al nuovo nodo *) p_primo^.p_preced := p_nuovo; (* il nuovo nodo diventa il primo *) p_primo := p_nuovo; p_nuovo := nil; inc(n_nodi); metti_inizio := true; end; (* fine metti_inizio *) (* mette il numero di input in un nuovo nodo *) (* da inserire a fine lista; funziona anche *) (* con lista vuota *) function gestore_lista_num.metti_fine(n: longint): boolean; var p_nuovo: p_nodo_num; begin if ok_metti_nodo = false then begin metti_fine := false; exit; end; p_nuovo := alloca_nodo(n); if p_nuovo = nil then begin metti_fine := false; exit; end; (* lista vuota *) if p_primo = nil then begin p_primo := p_nuovo; p_ultimo := p_nuovo; p_nuovo := nil; n_nodi := 1; metti_fine := true; exit; end; (* il nuovo nodo deve puntare all'indietro all'ex ultimo nodo *) p_nuovo^.p_preced := p_ultimo; (* l'ex ultimo nodo deve puntare in avanti al nuovo nodo *) p_ultimo^.p_prossimo := p_nuovo; (* il nuovo nodo diventa ultimo *) p_ultimo := p_nuovo; p_nuovo := nil; inc(n_nodi); metti_fine := true; end; (* fine metti_fine *) (* cerca in lista il primo nodo con numero maggiore/uguale *) (* a quello di input n; rende in uscita il puntatore al nodo *) (* trovato; se non trova, esce con nil; *) (* serve per l'inserimento in liste ordinate (ord. crescente) *) function gestore_lista_num.cerca_magg_ug(n: longint): p_nodo_num; var p_trovato: p_nodo_num; p_corrente: p_nodo_num; begin p_trovato := nil; p_corrente := p_primo; while p_corrente <> nil do begin if p_corrente^.num >= n then begin p_trovato := p_corrente; p_corrente := nil; end else begin p_corrente := p_corrente^.p_prossimo; end; end; cerca_magg_ug := p_trovato; end; (* fine cerca_magg_ug *) (* mette il numero di input in un nuovo nodo all'interno *) (* di una lista ordinata (crescente) senza ripetizioni *) function gestore_lista_num.metti_ord_1(n: longint): boolean; var p_nuovo: p_nodo_num; p_trovato: p_nodo_num; begin if ok_metti_nodo = false then begin metti_ord_1 := false; exit; end; p_nuovo := alloca_nodo(n); if p_nuovo = nil then begin metti_ord_1 := false; exit; end; (* cerca un nodo con numero maggiore/uguale n *) p_trovato := cerca_magg_ug(n); if p_trovato <> nil then begin (* prima del nodo trovato viene aggiunto il nuovo nodo, *) (* solo se il numero non e' gia' presente nel nodo trovato *) if p_trovato^.num > n then begin metti_ord_1 := metti_nodo_prima(p_trovato, p_nuovo); p_nuovo := nil; p_trovato := nil; exit; end else begin metti_ord_1 := false; p_nuovo := nil; p_trovato := nil; exit; end; end; (* se arriva fin qui, significa che non ha trovato un nodo *) (* con numero maggiore/uguale n, quindi il nuovo nodo va messo a fine lista *) metti_ord_1 := metti_nodo_fine(p_nuovo); p_nuovo := nil; end; (* fine metti_ord_1 *) (* mette il numero di input in un nuovo nodo all'interno di una lista *) (* ordinata (crescente) con eventuali ripetizioni *) function gestore_lista_num.metti_ord_2(n: longint): boolean; var p_nuovo: p_nodo_num; p_trovato: p_nodo_num; begin if ok_metti_nodo = false then begin metti_ord_2 := false; exit; end; p_nuovo := alloca_nodo(n); if p_nuovo = nil then begin metti_ord_2 := false; exit; end; (* cerca un nodo con numero maggiore/uguale n *) p_trovato := cerca_magg_ug(n); if p_trovato <> nil then begin metti_ord_2 := metti_nodo_prima(p_trovato, p_nuovo); p_nuovo := nil; p_trovato := nil; exit; end; (* se arriva fin qui, significa che non ha trovato un nodo *) (* con numero maggior/uguale n, quindi il nuovo nodo va messo a fine lista *) metti_ord_2 := metti_nodo_fine(p_nuovo); p_nuovo := nil; end; (* fine metti_ord_2 *) (* mette in lista una certa quantita' (num_nodi) di numeri casuali; *) (* val_max indica il valore massimo che puo' assumere un numero casuale; *) (* rende in uscita il numero di nodi inseriti; opera solo con liste vuote *) function gestore_lista_num.metti_numeri_cas(num_nodi: longint; val_max: longint): longint; var conta: longint; continua: boolean; numero_cas: longint; ok: boolean; begin (* contatore dei nodi messi in lista *) conta := 0; if (num_nodi < 1) or (num_nodi > max_nodi) then begin metti_numeri_cas := conta; exit; end; if p_primo <> nil then begin metti_numeri_cas := conta; exit; end; continua := true; while continua = true do begin numero_cas := random(val_max) + 1; ok := metti_fine(numero_cas); if ok = true then begin inc(conta); end; if (ok = false) or (conta = num_nodi) then begin continua := false; end; end; metti_numeri_cas := conta; end; (* fine metti_numeri_cas *) (*--------------------------------*) (* inserimento in lista di nodi gia' allocati *) (* mette un nodo all'inizio della lista; *) (* funziona anche con lista vuota *) function gestore_lista_num.metti_nodo_inizio(p: p_nodo_num): boolean; begin if ok_metti_nodo = false then begin metti_nodo_inizio := false; exit; end; if p = nil then begin metti_nodo_inizio := false; exit; end; (* lista vuota *) if p_primo = nil then begin p_primo := p; p_ultimo := p; n_nodi := 1; metti_nodo_inizio := true; exit; end; (* il nuovo nodo deve puntare in avanti all'ex primo nodo *) p^.p_prossimo := p_primo; (* l'ex primo nodo deve puntare all'indietro al nuovo nodo *) p_primo^.p_preced := p; (* il nuovo nodo diventa il primo *) p_primo := p; inc(n_nodi); metti_nodo_inizio := true; end; (* fine metti_nodo_inizio *) (* mette un nodo alla fine della lista; *) (* funziona anche con lista vuota *) function gestore_lista_num.metti_nodo_fine(p: p_nodo_num): boolean; begin if ok_metti_nodo = false then begin metti_nodo_fine := false; exit; end; if p = nil then begin metti_nodo_fine := false; exit; end; (* lista vuota *) if p_primo = nil then begin p_primo := p; p_ultimo := p; n_nodi := 1; metti_nodo_fine := true; exit; end; (* il nuovo nodo deve puntare all'indietro all'ex ultimo nodo *) p^.p_preced := p_ultimo; (* l'ex ultimo nodo deve puntare in avanti al nuovo nodo *) p_ultimo^.p_prossimo := p; (* il nuovo nodo diventa ultimo *) p_ultimo := p; inc(n_nodi); metti_nodo_fine := true; end; (* fine metti_nodo_fine *) (* inserisce un nuovo nodo prima di quello puntato da p_base *) function gestore_lista_num.metti_nodo_prima(p_base: p_nodo_num; p: p_nodo_num): boolean; var p_temp: p_nodo_num; begin if ok_metti_nodo = false then begin metti_nodo_prima := false; exit; end; if (p_base = nil) or (p = nil) then begin metti_nodo_prima := false; exit; end; (* il nodo base e' il primo della lista *) if p_base = p_primo then begin metti_nodo_prima := metti_nodo_inizio(p); exit; end; (* il nodo base non e' il primo della lista; *) (* si memorizza l'indirizzo del nodo che precede il nodo base *) p_temp := p_base^.p_preced; (* il nuovo nodo deve puntare in avanti al nodo base... *) p^.p_prossimo := p_base; (*...e all'indietro al nodo che precedeva il nodo base *) p^.p_preced := p_temp; (* il nodo di p_temp deve puntare in avanti al nuovo nodo *) p_temp^.p_prossimo := p; (* il nodo base deve puntare all'indietro al nuovo nodo *) p_base^.p_preced := p; p_temp := nil; inc(n_nodi); metti_nodo_prima := true; end; (* fine metti_nodo_prima *) (* inserisce un nuovo nodo dopo quello puntato da p_base *) function gestore_lista_num.metti_nodo_dopo(p_base: p_nodo_num; p: p_nodo_num): boolean; var p_temp: p_nodo_num; begin if ok_metti_nodo = false then begin metti_nodo_dopo := false; exit; end; if (p_base = nil) or (p = nil) then begin metti_nodo_dopo := false; exit; end; (* il nodo base e' l'ultimo della lista *) if p_base = p_ultimo then begin metti_nodo_dopo := metti_nodo_fine(p); exit; end; (* il nodo base non e' l'ultimo della lista; *) (* si memorizza l'indirizzo del nodo che segue il nodo base *) p_temp := p_base^.p_prossimo; (* il nuovo nodo deve puntare all'indietro al nodo base... *) p^.p_preced := p_base; (*...e in avanti al nodo che seguiva il nodo base *) p^.p_prossimo := p_temp; (* il nodo di p_temp deve puntare all'indietro al nuovo nodo *) p_temp^.p_preced := p; (* il nodo base deve puntare in avanti al nuovo nodo *) p_base^.p_prossimo := p; p_temp := nil; inc(n_nodi); metti_nodo_dopo := true; end; (* fine metti_nodo_dopo *) (*--------------------------------*) (* estrazione nodi da lista *) (* assegna nil ai puntatori di un nodo; *) (* il dato num resta invariato *) procedure gestore_lista_num.azzera_pp_nodo(p: p_nodo_num); begin if p <> nil then begin p^.p_preced := nil; p^.p_prossimo := nil; end; end; (* fine azzera_pp_nodo *) (* riceve in input il puntatore a un nodo e toglie dalla lista *) (* il nodo puntato; il nodo rimane allocato e mantiene il valore di num; *) (* i puntatori p_preced, p_prossimo del nodo tolto assumono valore nil; *) (* questo metodo puo' servire per la cancellazione di nodi (deallocandoli *) (* dopo averli tolti) oppure per spostare i nodi da una parte all'altra *) (* di una stessa lista o da una lista a un'altra con sposta_nodo *) function gestore_lista_num.togli_nodo(p: p_nodo_num): boolean; var p1, p2: p_nodo_num; begin if (p_primo = nil) or (p = nil) then begin togli_nodo := false; exit; end; (* lista con un solo nodo *) if p_primo = p_ultimo then begin if p = p_primo then begin p_primo := nil; p_ultimo := nil; n_nodi := 0; azzera_pp_nodo(p); togli_nodo := true; exit; end else begin togli_nodo := false; exit; end; end; (* il nodo da togliere e' il primo della lista *) if p_primo = p then begin (* l'ex secondo nodo diventa primo *) p_primo := p_primo^.p_prossimo; (* il nuovo primo nodo non ha nodi precedenti *) p_primo^.p_preced := nil; dec(n_nodi); azzera_pp_nodo(p); togli_nodo := true; exit; end; (* il nodo da togliere e' l'ultimo della lista *) if p_ultimo = p then begin (* l'ex penultimo nodo diventa ultimo *) p_ultimo := p_ultimo^.p_preced; (* il nuovo ultimo nodo non ha nodi successivi *) p_ultimo^.p_prossimo := nil; dec(n_nodi); azzera_pp_nodo(p); togli_nodo := true; exit; end; (* se arriva fin qui, significa che il nodo da togliere *) (* e' preceduto e seguito da altri nodi; *) (* memorizza gli indirizzi dei nodi precedente e successivo *) p1 := p^.p_preced; p2 := p^.p_prossimo; (* i nodi precedente e successivo devono puntarsi reciprocamente *) p1^.p_prossimo := p2; p2^.p_preced := p1; p1 := nil; p2 := nil; dec(n_nodi); azzera_pp_nodo(p); togli_nodo := true; end; (* fine togli_nodo *) (* toglie dalla lista il primo nodo e passa in uscita *) (* il puntatore al nodo tolto, che rimane allocato *) function gestore_lista_num.estraz_primo: p_nodo_num; var p_tolto: p_nodo_num; begin p_tolto := nil; (* lista vuota *) if p_primo = nil then begin estraz_primo := p_tolto; exit; end; (* lista con unico nodo; il metodo azzera_pp_nodo *) (* non viene usato, perche' i puntatori del nodo *) (* tolto valgono gia' nil *) if p_primo = p_ultimo then begin p_tolto := p_primo; p_primo := nil; p_ultimo := nil; n_nodi := 0; estraz_primo := p_tolto; exit; end; (* lista con piu' di un nodo *) p_tolto := p_primo; (* l'ex secondo nodo diventa primo *) p_primo := p_primo^.p_prossimo; (* il nuovo primo nodo non ha nodi precedenti *) p_primo^.p_preced := nil; dec(n_nodi); azzera_pp_nodo(p_tolto); estraz_primo := p_tolto; end; (* fine estraz_primo *) (* analoga alla precedente, per l'ultimo nodo *) function gestore_lista_num.estraz_ultimo: p_nodo_num; var p_tolto: p_nodo_num; begin p_tolto := nil; (* lista vuota *) if p_primo = nil then begin estraz_ultimo := p_tolto; exit; end; (* lista con unico nodo; il metodo azzera_pp_nodo *) (* non viene usato, perche' i puntatori del nodo *) (* tolto valgono gia' nil *) if p_primo = p_ultimo then begin p_tolto := p_primo; p_primo := nil; p_ultimo := nil; n_nodi := 0; estraz_ultimo := p_tolto; exit; end; (* lista con piu' di un nodo *) p_tolto := p_ultimo; (* l'ex penultimo nodo diventa ultimo *) p_ultimo := p_ultimo^.p_preced; (* il nuovo ultimo nodo non ha nodi successivi *) p_ultimo^.p_prossimo := nil; dec(n_nodi); azzera_pp_nodo(p_tolto); estraz_ultimo := p_tolto; end; (* fine estraz_ultimo *) (*--------------------------------*) (* cancellazione nodi *) (* cancella dalla lista il nodo identificato dal puntatore doppio pp; *) (* se l'operazione riesce, il puntatore puntato da pp assume valore nil *) function gestore_lista_num.cancella_nodo(pp: pp_nodo_num): boolean; var p: p_nodo_num; ok: boolean; begin (* l'operazione viene fatta con un puntatore semplice *) (* locale, per evitare il maneggio di un p. doppio *) p := pp^; ok := togli_nodo(p); if ok = true then begin dispose(p); p := nil; pp^ := p; end; cancella_nodo := ok; end; (* fine cancella_nodo *) (* cancella tutti i nodi contenenti il numero di input; *) (* rende in uscita il numero di nodi cancellati *) function gestore_lista_num.cancella_num(n: longint): longint; var conta: longint; p_corrente: p_nodo_num; p_temp: p_nodo_num; begin (* contatore dei nodi cancellati *) conta := 0; p_corrente := p_primo; while p_corrente <> nil do begin (* il nodo corrente deve essere cancellato *) if p_corrente^.num = n then begin (* il nodo da cancellare e' il primo *) if p_corrente = p_primo then begin (* il nodo e' primo e unico *) if p_primo = p_ultimo then begin cancella_nodo(@p_corrente); (* dopo la cancellazione p_corrente vale nil, *) (* quindi il ciclo si interrompe *) end (* il nodo e' primo, non unico *) else begin p_temp := p_corrente^.p_prossimo; cancella_nodo(@p_corrente); (* al prossimo passo esaminera' l'ex secondo nodo *) (* diventato primo *) p_corrente := p_temp; end; end (* il nodo da cancellare non e' il primo *) else begin (* il nodo e' l'ultimo *) if p_corrente = p_ultimo then begin cancella_nodo(@p_corrente); (* dopo la cancellazione p_corrente vale nil, *) (* quindi il ciclo si interrompe *) end (* il nodo non e' l'ultimo *) else begin p_temp := p_corrente^.p_prossimo; cancella_nodo(@p_corrente); (* al prossimo passo esaminera' il nodo successivo *) (* a quello cancellato *) p_corrente := p_temp; end; end; inc(conta); end (* il nodo corrente non deve essere cancellato *) else begin p_corrente := p_corrente^.p_prossimo; end; end; (* fine ciclo percorrenza lista *) cancella_num := conta; end; (* fine cancella_num *) (* opera solo con liste ordinate con ripetizioni; *) (* cancella i nodi con numeri ripetuti; *) (* rende in uscita il numero di nodi cancellati *) function gestore_lista_num.cancella_ripetiz: longint; var conta: longint; tipo_ord: byte; num_preced: longint; p_corrente: p_nodo_num; p_temp: p_nodo_num; begin (* contatore dei nodi cancellati *) conta := 0; tipo_ord := calcola_tipo_ordine; if tipo_ord <> 2 then begin cancella_ripetiz := conta; exit; end; num_preced := p_primo^.num; (* comincia la lettura dal secondo nodo *) p_corrente := p_primo^.p_prossimo; while p_corrente <> nil do begin if p_corrente^.num = num_preced then begin p_temp := p_corrente^.p_prossimo; togli_nodo(p_corrente); dispose(p_corrente); p_corrente := p_temp; inc(conta); end else begin num_preced := p_corrente^.num; p_corrente := p_corrente^.p_prossimo; end; end; cancella_ripetiz := conta; end; (* fine cancella_ripetiz *) (*--------------------------------*) (* ordinamento e inversione lista *) (* sposta i nodi per ottenere un ordinamento crescente; *) (* l'algoritmo non e' molto efficiente, conviene usarlo *) (* con liste di poche migliaia di nodi; con liste grandi *) (* bisogna ideare altri metodi (ad es., ordinamento con *) (* array) *) function gestore_lista_num.ordina: boolean; var p_primo_nuovo: p_nodo_num; p_ultimo_nuovo: p_nodo_num; num_nodi_inizio: longint; p_nodo_minimo: p_nodo_num; p_corrente: p_nodo_num; begin (* l'elaborazione viene fatta solo se la lista non e' ordinata *) if calcola_tipo_ordine <> 0 then begin ordina := false; exit; end; (* puntatori temporanei a primo e ultimo nodo della lista ordinata *) p_primo_nuovo := nil; p_ultimo_nuovo := nil; (* bisogna memorizzare il numero di nodi a inizio elaborazione *) num_nodi_inizio := n_nodi; (* ciclo esterno da eseguire fino a svuotamento della lista originale *) while p_primo <> nil do begin (* puntatore al nodo contenente il numero minimo trovato nella lista originale; *) (* all'inizio si presume che il numero minimo si trovi nel primo nodo *) p_nodo_minimo := p_primo; p_corrente := p_primo; (* ciclo interno di lettura della lista originale, *) (* per cercare il nodo con il numero minimo *) while p_corrente <> nil do begin if p_nodo_minimo^.num > p_corrente^.num then begin p_nodo_minimo := p_corrente; end; p_corrente := p_corrente^.p_prossimo; end; (* fine ciclo interno *) (* il nodo col numero minimo trovato viene estratto dalla lista *) (* originale, perche' bisogna spostarlo nella lista ordinata *) togli_nodo(p_nodo_minimo); (* lista ordinata ancora vuota *) if p_primo_nuovo = nil then begin p_primo_nuovo := p_nodo_minimo; p_ultimo_nuovo := p_nodo_minimo; end (* lista ordinata contenente gia' almeno un nodo *) else begin (* il nodo spostato deve puntare all'indietro all'ex ultimo nodo, *) (* che deve diventare penultimo *) p_nodo_minimo^.p_preced := p_ultimo_nuovo; (* l'ex ultimo nodo deve puntare in avanti al nodo spostato *) p_ultimo_nuovo^.p_prossimo := p_nodo_minimo; (* il nodo spostato e' il nuovo ultimo nodo *) p_ultimo_nuovo := p_nodo_minimo; end; end; (* fine ciclo esterno *) (* i valori dei puntatori primo/ultimo della lista ordinata *) (* vengono assegnati alla lista originale *) p_primo := p_primo_nuovo; p_ultimo := p_ultimo_nuovo; (* l'estrazione di nodi dalla lista originale ha azzerato il contatore *) (* dei nodi, quindi bisogna ripristinare il valore iniziale *) n_nodi := num_nodi_inizio; ordina := true; end; (* fine ordina *) (* inverte l'ordine dei numeri in lista *) function gestore_lista_num.inverti: boolean; var p_primo_nuovo: p_nodo_num; p_ultimo_nuovo: p_nodo_num; num_nodi_inizio: longint; p_sposta: p_nodo_num; begin if (p_primo = nil) or (p_primo = p_ultimo) then begin inverti := false; exit; end; (* puntatori temporanei a primo e ultimo nodo della lista invertita *) p_primo_nuovo := nil; p_ultimo_nuovo := nil; (* bisogna memorizzare il numero di nodi a inizio elaborazione *) num_nodi_inizio := n_nodi; (* ciclo eseguito fino a svuotamento della lista originale *) while p_primo <> nil do begin p_sposta := estraz_ultimo; (* lista invertita ancora vuota *) if p_primo_nuovo = nil then begin p_primo_nuovo := p_sposta; p_ultimo_nuovo := p_sposta; end (* lista invertita contenente gia' almeno un nodo *) else begin (* il nodo spostato deve puntare all'indietro all'ex ultimo nodo, *) (* che deve diventare penultimo *) p_sposta^.p_preced := p_ultimo_nuovo; (* l'ex ultimo nodo deve puntare in avanti al nodo spostato *) p_ultimo_nuovo^.p_prossimo := p_sposta; (* il nodo spostato e' il nuovo ultimo nodo *) p_ultimo_nuovo :=p_sposta; end; end; (* i valori dei puntatori primo/ultimo della lista invertita *) (* vengono assegnati alla lista originale *) p_primo := p_primo_nuovo; p_ultimo := p_ultimo_nuovo; (* l'estrazione di nodi dalla lista originale ha azzerato il contatore dei nodi, *) (* quindi bisogna ripristinare il valore iniziale *) n_nodi := num_nodi_inizio; inverti := true; end; (* fine inverti *) (*--------------------------------*) (* esportazione/importazione dati lista *) (* il puntatore doppio di input identifica il primo nodo *) (* di una lista esterna; il metodo inserisce in questa lista *) (* tutti i numeri contenuti nella lista dell'oggetto, che resta *) (* invariata; *) (* rende in uscita il numero di nodi messi nella lista esterna *) function gestore_lista_num.esporta(pp: pp_nodo_num): longint; var conta: longint; p: p_nodo_num; num: longint; p_nuovo: p_nodo_num; p_ultimo_nuovo: p_nodo_num; p_corrente: p_nodo_num; begin (* contatore dei nodi messi nella lista esterna *) conta := 0; (* puntatore semplice locale al primo nodo della lista esterna *) p := pp^; (* la lista esterna deve essere vuota *) if p <> nil then begin esporta := conta; exit; end; (* la lista interna deve avere almeno un nodo *) if p_primo = nil then begin esporta := conta; exit; end; (* operazione con primo nodo *) num := p_primo^.num; p_nuovo := alloca_nodo(num); if p_nuovo = nil then begin esporta := conta; exit; end; p := p_nuovo; inc(conta); (* puntatore a ultimo nodo messo in lista esterna *) p_ultimo_nuovo := p_nuovo; (* operazioni con altri eventuali nodi, partendo dal secondo *) p_corrente := p_primo^.p_prossimo; while p_corrente <> nil do begin num := p_corrente^.num; p_nuovo := alloca_nodo(num); if p_nuovo <> nil then begin (* il nuovo nodo deve puntare all'indietro all'ex ultimo *) p_nuovo^.p_preced := p_ultimo_nuovo; (* l'ex ultimo nodo deve puntare in avanti al nuovo nodo *) p_ultimo_nuovo^.p_prossimo := p_nuovo; (* il nuovo nodo diventa ultimo *) p_ultimo_nuovo := p_nuovo; inc(conta); p_corrente := p_corrente^.p_prossimo; end else begin (* se l'allocazione non e' riuscita, esce dal ciclo *) p_corrente := nil; end; end; pp^ := p; esporta := conta; end; (* fine esporta *) (* il puntatore di input punta al primo nodo di una lista esterna; *) (* il metodo copia tutti i numeri di tale lista nella propria *) (* lista interna; rende in uscita il numero di nodi messi nella *) (* lista interna *) function gestore_lista_num.importa(p: p_nodo_num): longint; var conta: longint; p_corrente: p_nodo_num; num: longint; ok: boolean; begin conta := 0; (* la lista esterna deve avere almeno un nodo *) if p = nil then begin importa := conta; exit; end; (* la lista interna deve essere vuota *) if p_primo <> nil then begin importa := conta; exit; end; p_corrente := p; while p_corrente <> nil do begin num := p_corrente^.num; ok := metti_fine(num); if ok = true then begin inc(conta); p_corrente := p_corrente^.p_prossimo; end else begin (* se l'inserimento a fine lista non e' riuscito, *) (* interrompe il ciclo *) p_corrente := nil; end; (* interrompe anche se ha collocato nella lista interna *) (* il numero massimo di nodi ammessi *) if (p_corrente <> nil) and (conta = max_nodi) then begin p_corrente := nil; end; end; importa := conta; end; (* fine importa *) (* fine definizione metodi classe gestore_lista_num *) (*--------------------------------*) (*--------------------------------*) (* funzione non appartenente alla classe gestore_lista_num; *) (* toglie dalla prima lista il nodo puntato da p e lo accoda *) (* nella seconda lista *) function sposta_nodo(var G_lista_1: gestore_lista_num; var G_lista_2: gestore_lista_num; p: p_nodo_num): boolean; begin (* la prima lista deve avere almeno un nodo *) if G_lista_1.leggi_n_nodi = 0 then begin sposta_nodo := false; exit; end; (* la seconda lista deve avere lo spazio disponibile *) if G_lista_2.ok_metti_nodo = false then begin sposta_nodo := false; exit; end; (* il puntatore al nodo da spostare non puo' essere nullo *) if p = nil then begin sposta_nodo := false; exit; end; G_lista_1.togli_nodo(p); G_lista_2.metti_nodo_fine(p); sposta_nodo := true; end; (* fine sposta_nodo *) (*--------------------------------*) END. (*--------------------------------*) (*--------------------------------*) (* fine lib_listanum.pas *)