|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
[C] Implementazione lista di liste
Salve a tutti,
per una consegna universitaria mi trovo a dover consegnare un programma che lavora su una struttura dati che in realtà è una lista di lista, come rappresentato in questa immagine: ![]() Creando questa lista di liste in poche parole si vuole creare una "matrice dinamica", ovvero, ci sarà una lista principale composta da due puntatori e di questi due puntatori: Uno punterà all'elemento successivo della lista; Uno punterà ad un'altra lista che in realtà rappresenterà un intera colonna della matrice; Per farla breve una lista servirà per scorrere per le colonne, arrivata alla colonna desiderata si punterà alla seconda lista che a sua volta conterrà gli elementi veri e propri della colonna in questione. Il problema è che questo esame non è di Algoritmi e strutture dati, che ancora non ho fatto essendo solo al primo anno, ma è un esame di laboratorio di informatica in cui ci è stato appena accennato come funziona una lista, e non riesco bene a definire come far funzionare una lista di liste. Mi sono bloccato già solo alla creazione di una funzione che inizializzi la lista. Ovvero che allochi lo spazio, passandogli semplicemente un puntatore ed il numero di righe e di colonne. Stavo pensando ad allocare, con un primo ciclo tutti gli elementi della prima lista, e man mano che si alloca il singolo elemento della prima lista, con un'altro ciclo anniato, gli si alloca la seconda lista ad esso collegata. Ho però tante idee e ben confuse, quindi se potreste aiutarmi a creare e a gestire questa struttura dati ve ne sarei ben grato. Magari non sono il primo a voler creare una lista di liste. Vi ringrazio in anticipo, guylmaster. |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Fermati a pensare un attimo sulla struttura di questa sorta di "matrice" che stai creando.
Come noti tu stesso, è una lista di liste. Se riesci a rappresentare una lista come un puntatore al nodo in testa, allora il resto è molto semplice: visto che ogni nodo contiene un valore di qualche tipo, puoi fare per prima cosa una lista di colonne. I nodi di questa lista potranno contenere, come valore, il puntatore alla testa di una lista con le celle da memorizzare in quella colonna. Il fatto che tu lo stia facendo in C ti complicherà leggermente la vita, ma se farai le scelte giuste non sarà difficile. ciao
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Sto provando ad iniziare per gradi ovvero di provare inanzi tutto a realizzare una semplice lista.
Ho trovato su internet un codice piu complicato che ho provato a semplificare. Ho tre file, il main.c, funzioni.c (contenente le funzioni di inserimento), funzioni.h (contenendo le definizioni delle strutture), e sono le seguenti: main.c Codice:
#include <stdio.h>
#include <stdlib.h>
#include "funzioni.h"
int main(int argc, char *argv[])
{
struct elemento *lista = NULL;
lista = aggiungiContatto(lista);
system("PAUSE");
return 0;
}
Codice:
/*Elementi pubblici della libreria funzioni*/
//Struttura dati
struct elemento
{
float inf;
struct elemento *pun;
};
//Prototipi funzioni
struct elemento *aggiungiContatto(struct elemento *p);
Codice:
#include <stdio.h>
#include <stdlib.h>
#include "funzioni.h"
struct elemento *aggiungiContatto(struct elemento *p)
{ // aggiungiContatto() - OPEN
// Dichiaro le variabili
float daInserire;
struct elemento *punt;
// Popolo la variabile daInserire
printf (" Float > ");
scanf ("%f", daInserire);
if(p != NULL)
{ // IF - OPEN
/* creazione elementi successivi */
// Alloco la memoria necessaria
punt = (struct elemento *)malloc(sizeof(struct elemento));
// Metto daInserire nell'informazione del puntatore
punt->inf = daInserire;
// Metto il puntatore in testa alla lista
punt->pun = p;
} else { // ELSE
/* creazione primo elemento */
// Alloco la memoria necessaria
p = (struct elemento *)malloc(sizeof(struct elemento));
// Metto daInserire nell'informazione del puntatore
p->inf = daInserire;
// p punta a NULL, ovvero il marcatore di fine lista
p->pun = NULL;
// Assegno p a punt
punt = p;
} // IF - CLOSE
// Esce dalla funzione e restituisce la lista
return(punt);
}
Il problema è che il programma arriva a leggere il valore float e poi crasha inspiegabilmente. Da cosa può dipendere? Ma anche non avresti qualche guida che spiega in linguaggio C, magari in maniera dettaggliata (e codice copiabile direttamente) come sviluppare una semplice lista senza fronzoli? Perchè secondo me mi mancano proprio le basi. Ho una dispensa del professore i cui stessi esempi non funzionano e non sto riuscendo a trovare in internet programmi in C di liste ridotte all'osso. Se potresti aiutarmi anche in tal senso te ne sarei grato. |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Ho trovato anche questo codice per le liste, molto piu stringato ma con il problema di non avere nemmeno un commento a disposizione:
Codice:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
typedef struct node_s {
void *data;
struct node_s *next;
} NODE;
NODE *list_create(void *data)
{
NODE *node;
if(!(node=malloc(sizeof(NODE)))) return NULL;
node->data=data;
node->next=NULL;
return node;
}
NODE *list_insert_after(NODE *node, void *data)
{
NODE *newnode;
newnode=list_create(data);
newnode->next = node->next;
node->next = newnode;
return newnode;
}
NODE *list_insert_beginning(NODE *list, void *data)
{
NODE *newnode;
newnode=list_create(data);
newnode->next = list;
return newnode;
}
int list_remove(NODE *list, NODE *node)
{
while(list->next && list->next!=node) list=list->next;
if(list->next) {
list->next=node->next;
free(node);
return 0;
} else return -1;
}
int list_foreach(NODE *node, int(*func)(void*))
{
while(node) {
if(func(node->data)!=0) return -1;
node=node->next;
}
return 0;
}
NODE *list_find(NODE *node, int(*func)(void*,void*), void *data)
{
while(node) {
if(func(node->data, data)>0) return node;
node=node->next;
}
return NULL;
}
int printstring(void *s)
{
printf("%s\n", (char *)s);
return 0;
}
int findstring(void *listdata, void *searchdata)
{
return strcmp((char*)listdata, (char*)searchdata)?0:1;
}
int main()
{
NODE *list, *second, *inserted;
NODE *match;
/* Create initial elements of list */
list=list_create((void*)"First");
second=list_insert_after(list, (void*)"Second");
list_insert_after(second, (void*)"Third");
printf("Initial list:\n");
list_foreach(list, printstring);
putchar('\n');
/* Insert 1 extra element in front */
list=list_insert_beginning(list, "BeforeFirst");
printf("After list_insert_beginning():\n");
list_foreach(list, printstring);
putchar('\n');
/* Insert 1 extra element after second */
inserted=list_insert_after(second, "AfterSecond");
printf("After list_insert_after():\n");
list_foreach(list, printstring);
putchar('\n');
/* Remove the element */
list_remove(list, inserted);
printf("After list_remove():\n");
list_foreach(list, printstring);
putchar('\n');
/* Search */
if((match=list_find(list, findstring, "Third")))
printf("Found \"Third\"\n");
else printf("Did not find \"Third\"\n");
system("PAUSE");
return 0;
}
Codice:
NODE *list_insert_after(NODE *node, void *data)
{
NODE *newnode;
newnode=list_create(data);
newnode->next = node->next;
node->next = newnode;
return newnode;
}
Anche perchè ho provato a fare "newnode->next = NULL;" e non va più l'ultima funzione di ricerca di un elemento. |
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Dec 2007
Città: Palestro
Messaggi: 1960
|
Quote:
Per semplicità, immaginiamo che tu voglia inserire dopo il primo elemento (quindi in seconda posizione). Quale sarà il successore del nuovo nodo, cioè quello che ORA dovrà essere in terza posizione? Quello che PRIMA era in seconda posizione, quindi nodo_dopo_il_quale_inserire->next. Per questo fai newnode->next=node->next; L'istruzione node->next=newnode, invece serve per indicare che il successore del nodo è il nuovo nodo creato. Spero di essere stato chiaro.. A->C->D; devi inserire B dopo la A, quindi chiami insert_after(&A,&B). A questo punto crei il nodo con i dati di B (lo chiamo B per semplicità). Chi sarà il successore di B? C, quindi A->next. E il successore di A? B. Con l'esempietto dovrebbe essere decisamente più semplice da capire di quanto ho scritto sopra! |
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Quote:
Ma come mai data lo da come puntatore di tipo void? Se volessi modificare questo esempio per far si che questa lista abbia come elementi l'inizio di un'altra lista, come da post originario, come potrei fare? |
|
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Quote:
Ma come mai data lo da come puntatore di tipo void? Se volessi modificare questo esempio per far si che questa lista abbia come elementi l'inizio di un'altra lista, come da post originario, come potrei fare? Ho provato anche solo a modificare i tipi in float in questo modo ma mi va in loop: Codice:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
//Struttura dati
typedef struct node_s {
//void *data;
float data;
struct node_s *next;
} NODE;
//Prototipi funzioni
NODE *list_create(float data);
NODE *list_insert_after(NODE *node, float data);
NODE *list_insert_beginning(NODE *list, void *data);
int list_remove(NODE *list, NODE *node);
int list_foreach(NODE *node, int(*func)(float));
NODE *list_find(NODE *node, int(*func)(void*,void*), void *data);
int printstring(void *s);
int findstring(void *listdata, void *searchdata);
//funzioni
NODE *list_create(float data)
{
NODE *node;
if(!(node=malloc(sizeof(NODE)))) return NULL;
node->data=data;
node->next=NULL;
return node;
}
NODE *list_insert_after(NODE *node, float data)
{
NODE *newnode;
newnode=list_create(data);
newnode->next = node->next;
//newnode->next = NULL;
node->next = newnode;
return newnode;
}
/*
NODE *list_insert_beginning(NODE *list, void *data)
{
NODE *newnode;
newnode=list_create(data);
newnode->next = list;
return newnode;
}
int list_remove(NODE *list, NODE *node)
{
while(list->next && list->next!=node) list=list->next;
if(list->next) {
list->next=node->next;
free(node);
return 0;
} else return -1;
}
*/
int list_foreach(NODE *node, int(*func)(float))
{
while(node) {
if(func(node->data)!=0) return -1;
node=node->next;
}
return 0;
}
/*
NODE *list_find(NODE *node, int(*func)(void*,void*), void *data)
{
while(node) {
if(func(node->data, data)>0) return node;
node=node->next;
}
return NULL;
}
*/
int printstring(void *s)
{
printf("%s\n", (char *)s);
return 0;
}
/*
int findstring(void *listdata, void *searchdata)
{
return strcmp((char*)listdata, (char*)searchdata)?0:1;
}
*/
//main
int main()
{
NODE *list, *second, *inserted;
NODE *match;
/* Create initial elements of list */
list=list_create(1);
second=list_insert_after(list, 2);
//list_insert_after(second, 3);
printf("Initial list:\n");
list_foreach(list, printstring);
putchar('\n');
system("PAUSE");
return 0;
}
Codice:
int list_foreach(NODE *node, int(*func)(void*)) |
|
|
|
|
|
|
#8 | |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Quote:
Il dato nella lista è di tipo void* per dare una certa "universalità" all'implementazione (ci puoi virtualmente infilare ciò vuoi, quindi quella singola implementazione della lista è adattabile ad ogni contenuto).
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Per altro con la insert_after riesco ad inserire un nodo solo in mezzo a due nodi.
Se volessi invece inserire un nodo a fine lista come potrei fare? |
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Ti basta inserirlo... dopo l'ultimo nodo della lista.
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Per fare l'inserimentro a fine lista ho provato ad implementare la seguente funzione:
Codice:
NODE *Inserisci_alla_fine(NODE *node, float data)
{
NODE2 *newnode;
while(node)
{
if(node->next != NULL)
{
node = node->next;
}
else
{
newnode = list_create2(data);
node->next = newnode;
newnode->next = NULL;
}
}
return newnode;
}
Codice:
typedef struct node_s2 {
float data;
struct node_s2 *next;
} NODE2;
Codice:
NODE2 *list_create2(float data)
{
NODE2 *node;
if(!(node=malloc(sizeof(NODE2)))) return NULL;
node->data=data;
node->next=NULL;
return node;
}
|
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
|
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Non va perché l'aggiunta la fai dentro il while, dal quale non uscirai mai perché appena trovi la fine della lista inserisci un nuovo blocco e non aggiorni più il puntatore node, per cui non smetterai mai di ripetere l'aggiunta dell'ultimo blocco.
Fai prima un ciclo while dove imponi come condizione che siano validi sia il blocco attuale che il blocco successivo. Appena fallirà la condizione, uscirai dal ciclo while stando sull'ultimo blocco. Avrai due casi: o ti fermerai su NULL (nel qual caso la lista è vuota), o ti fermerai su un qualche nodo, sul quale potrai usare la list_insert_after(). Se sai che dovrai fare un gran numero di inserimenti in coda o in testa, prendi in considerazione l'idea di usare liste circolari.
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Quote:
|
|
|
|
|
|
|
#15 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Abbozzo uno pseudocodice:
Codice:
nodo_t x = lista->testa;
finché (x non è nullo) e (x->next non è nullo) {
x = x->next;
}
aggiungi_dopo(x, nuovoValore);
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Quote:
Codice:
NODE *Inserisci_alla_fine(NODE *node, float data)
{
NODE2 *newnode;
while(node && node->next)
{
node = node->next;
}
list_insert_after2(node, data);
return newnode;
}
|
|
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
No, non ti concatena uno zero, è che... newnode chi lo inizializza?
E ricordati di gestire il caso in cui node è nullo!
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Quote:
Ho visto che se sostituito " newnode=list_create(data);" con " newnode=list_create(333.333);" funziona. Ovvero se invece di passargli la variabile data metto direttamente il numero float. Possibile? |
|
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Che poi l'inizializzazione non la fa esattamente la riga di codice:
Codice:
newnode=list_create(data); |
|
|
|
|
|
#20 |
|
Senior Member
Iscritto dal: Aug 2002
Messaggi: 2518
|
Cioè attualmente il codice della mia funzione è questo:
Codice:
NODE *Inserisci_alla_fine(NODE *node, float data)
{
NODE2 *newnode;
while(node->next != NULL)
{
node = node->next;
}
newnode=list_create(data);
node->next = newnode;
return newnode;
}
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:19.





















