if(new->next == NULL) {
first->i = new->i;
first->prev = new->prev;
first->next = new->next; // jusqu'ici ca va
first->prev->prev = NULL; // ici et ensuite je ne maîtrise plus
first->next->next = new;
return first;
}
if(new->next != NULL) { /* une address: plus d'un noeud */
struct dlist *head = init(0);
/* Avance jusqu'au dernier noeud... volontairement enlevé, sinon à
partir du dernier noeud, pointe le nouveau qui devient head*/
new->i = head->i; // jusqu'ici ca va
new->prev = head->prev;
new->next = head->next;
Par contre, eviter new en nom de variable est toujours une bonne idee
struct dlist *first = init(0), *head = init(0);
if(new->next == NULL) { first->i = new->i; first->prev = new->prev; first->next = new->next; // jusqu'ici ca va first->prev->prev = NULL; // ici et ensuite je ne maîtrise plus first->next->next = new; return first; }
Fais ton test de pointeur nul beaucoup plus tard. Tu t'inventes des cas particuliers pour rien.
if(new->next != NULL) { /* une address: plus d'un noeud */ struct dlist *head = init(0);
/* Avance jusqu'au dernier noeud... volontairement enlevé, sinon à partir du dernier noeud, pointe le nouveau qui devient head*/
new->i = head->i; // jusqu'ici ca va new->prev = head->prev; new->next = head->next;
Apres, l'interet des listes doublement chainees, c'est generalement d'avoir un acces direct au dernier element.
Je te recommande de voir plutot ca comme une liste circulaire. Il suffit d'arreter le parcours lorsque tu es revenu au premier element.
Si tu veux une vraie liste doublement chainee, traditionnellement, on se definit un entete, qui va pointer sur le 1er et le dernier element de la liste (donc une structure separee de liste et d'element).
In article <m2hakcj3dg.fsf@orange.fr>, <vivelesexe@orange.fr> wrote:
J'aurais besoin d'un coup de main à déboguer cette liste doublement
chainée, en particulier les fonctions append(), appbeg() voici le code:
Par contre, eviter new en nom de variable est toujours une bonne idee
struct dlist *first = init(0), *head = init(0);
if(new->next == NULL) {
first->i = new->i;
first->prev = new->prev;
first->next = new->next; // jusqu'ici ca va
first->prev->prev = NULL; // ici et ensuite je ne maîtrise plus
first->next->next = new;
return first;
}
Fais ton test de pointeur nul beaucoup plus tard. Tu t'inventes des cas
particuliers pour rien.
if(new->next != NULL) { /* une address: plus d'un noeud */
struct dlist *head = init(0);
/* Avance jusqu'au dernier noeud... volontairement enlevé, sinon à
partir du dernier noeud, pointe le nouveau qui devient head*/
new->i = head->i; // jusqu'ici ca va
new->prev = head->prev;
new->next = head->next;
Apres, l'interet des listes doublement chainees, c'est generalement
d'avoir un acces direct au dernier element.
Je te recommande de voir plutot ca comme une liste circulaire. Il suffit
d'arreter le parcours lorsque tu es revenu au premier element.
Si tu veux une vraie liste doublement chainee, traditionnellement, on
se definit un entete, qui va pointer sur le 1er et le dernier element de
la liste (donc une structure separee de liste et d'element).
Par contre, eviter new en nom de variable est toujours une bonne idee
struct dlist *first = init(0), *head = init(0);
if(new->next == NULL) { first->i = new->i; first->prev = new->prev; first->next = new->next; // jusqu'ici ca va first->prev->prev = NULL; // ici et ensuite je ne maîtrise plus first->next->next = new; return first; }
Fais ton test de pointeur nul beaucoup plus tard. Tu t'inventes des cas particuliers pour rien.
if(new->next != NULL) { /* une address: plus d'un noeud */ struct dlist *head = init(0);
/* Avance jusqu'au dernier noeud... volontairement enlevé, sinon à partir du dernier noeud, pointe le nouveau qui devient head*/
new->i = head->i; // jusqu'ici ca va new->prev = head->prev; new->next = head->next;
Apres, l'interet des listes doublement chainees, c'est generalement d'avoir un acces direct au dernier element.
Je te recommande de voir plutot ca comme une liste circulaire. Il suffit d'arreter le parcours lorsque tu es revenu au premier element.
Si tu veux une vraie liste doublement chainee, traditionnellement, on se definit un entete, qui va pointer sur le 1er et le dernier element de la liste (donc une structure separee de liste et d'element).
Xavier Roche
Le 15/03/2013 12:42, a écrit :
struct dlist {
Remarque très personnelle: je n'aime pas les listes chaînées. En général, il faut bien se poser la question de l’intérêt de la chose (ie. le seul amha est d'insérer un élément avant la fin en O(1)), mais bon, ce n'est pas la question là.
int i; struct dlist *prev; struct dlist *next; };
Du coup "prev" sur le premier élément c'est quoi ? NULL ou le dernier élément ? (on va supposer le dernier pour un truc circulaire)
On pourra typedef'er la struct dlist pour éviter les "struct dlist" partout (typedef struct dlist dlist;)
Moi j'aurais sorti la chaine complète: (nota: une petite macro CHECK n'est pas inutile pour valider certains invariants, histoire d'avoir un arrêt propre en cas de problème)
static void print(dlist *p) { dlist *const first = p; assert(p != NULL); do { CHECK(p); printf("<%d>", p->i); p = p->next; } while(p != first); printf("n"); }
struct dlist *append(struct dlist *new) {
C'est un poil compliqué. Le truc, dans les listes chaînées, c'est d'avoir un pointeur qui est positionné sur l'élément à allouer/écrire, c'est à dire ici un dlist**.
Donc a vue de nez je commencerai en: void append(dlist **new); pour écrire dans un dlist*
avec du coup dans le main: dlist *list = NULL; append(&list, 42);
Pour l'ajout, le mieux est toujours de dessiner ce qui se passe:
départ ici----// =>last<=>[first]<=>second<=...
on insère la-// =>last<=>item===[first]<=>second<=...
Après, pour chaîner, il faut modifier quatre pointeurs: les deux pointeurs prev/next du nouvel élément créé, qui vont pointer respectivement sur l'ancien dernier élément, et sur le premier ; et le chaînage next de l'ancien dernier élément et prev du premier élément, qui vont pointer sur notre nouvel élément.
Du coup le code est très simple:
static void append(dlist **new, int j) { /* we have to create a new item in all cases */ dlist *const item = init(j);
/* We have to chain 'item' ; ie. * change current last 'next' member * change current first 'prev' member
=>last<=>[first]<=>second<=...
// =>last<=>item===[first]<=>second<=... / / here here */
/* previous last element or item */ dlist *const last = *new != NULL ? (*new)->prev : item;
/* pointer to current last element pointer or pointer to item */ dlist **const plast = *new != NULL ? &(*new)->prev : new;
Le 15/03/2013 12:42, vivelesexe@orange.fr a écrit :
struct dlist {
Remarque très personnelle: je n'aime pas les listes chaînées. En
général, il faut bien se poser la question de l’intérêt de la chose (ie.
le seul amha est d'insérer un élément avant la fin en O(1)), mais bon,
ce n'est pas la question là.
int i;
struct dlist *prev;
struct dlist *next;
};
Du coup "prev" sur le premier élément c'est quoi ? NULL ou le dernier
élément ? (on va supposer le dernier pour un truc circulaire)
On pourra typedef'er la struct dlist pour éviter les "struct dlist"
partout (typedef struct dlist dlist;)
Moi j'aurais sorti la chaine complète: (nota: une petite macro CHECK
n'est pas inutile pour valider certains invariants, histoire d'avoir un
arrêt propre en cas de problème)
static void print(dlist *p) {
dlist *const first = p;
assert(p != NULL);
do {
CHECK(p);
printf("<%d>", p->i);
p = p->next;
} while(p != first);
printf("n");
}
struct dlist *append(struct dlist *new) {
C'est un poil compliqué. Le truc, dans les listes chaînées, c'est
d'avoir un pointeur qui est positionné sur l'élément à allouer/écrire,
c'est à dire ici un dlist**.
Donc a vue de nez je commencerai en:
void append(dlist **new);
pour écrire dans un dlist*
avec du coup dans le main:
dlist *list = NULL;
append(&list, 42);
Pour l'ajout, le mieux est toujours de dessiner ce qui se passe:
départ ici----\//
=>last<=>[first]<=>second<=...
on insère la-\//
=>last<=>item===[first]<=>second<=...
Après, pour chaîner, il faut modifier quatre pointeurs: les deux
pointeurs prev/next du nouvel élément créé, qui vont pointer
respectivement sur l'ancien dernier élément, et sur le premier ; et le
chaînage next de l'ancien dernier élément et prev du premier élément,
qui vont pointer sur notre nouvel élément.
Du coup le code est très simple:
static void append(dlist **new, int j) {
/* we have to create a new item in all cases */
dlist *const item = init(j);
/*
We have to chain 'item' ; ie.
* change current last 'next' member
* change current first 'prev' member
=>last<=>[first]<=>second<=...
\//
=>last<=>item===[first]<=>second<=...
/ /
here here
*/
/* previous last element or item */
dlist *const last = *new != NULL ? (*new)->prev : item;
/* pointer to current last element pointer or pointer to item */
dlist **const plast = *new != NULL ? &(*new)->prev : new;
Remarque très personnelle: je n'aime pas les listes chaînées. En général, il faut bien se poser la question de l’intérêt de la chose (ie. le seul amha est d'insérer un élément avant la fin en O(1)), mais bon, ce n'est pas la question là.
int i; struct dlist *prev; struct dlist *next; };
Du coup "prev" sur le premier élément c'est quoi ? NULL ou le dernier élément ? (on va supposer le dernier pour un truc circulaire)
On pourra typedef'er la struct dlist pour éviter les "struct dlist" partout (typedef struct dlist dlist;)
Moi j'aurais sorti la chaine complète: (nota: une petite macro CHECK n'est pas inutile pour valider certains invariants, histoire d'avoir un arrêt propre en cas de problème)
static void print(dlist *p) { dlist *const first = p; assert(p != NULL); do { CHECK(p); printf("<%d>", p->i); p = p->next; } while(p != first); printf("n"); }
struct dlist *append(struct dlist *new) {
C'est un poil compliqué. Le truc, dans les listes chaînées, c'est d'avoir un pointeur qui est positionné sur l'élément à allouer/écrire, c'est à dire ici un dlist**.
Donc a vue de nez je commencerai en: void append(dlist **new); pour écrire dans un dlist*
avec du coup dans le main: dlist *list = NULL; append(&list, 42);
Pour l'ajout, le mieux est toujours de dessiner ce qui se passe:
départ ici----// =>last<=>[first]<=>second<=...
on insère la-// =>last<=>item===[first]<=>second<=...
Après, pour chaîner, il faut modifier quatre pointeurs: les deux pointeurs prev/next du nouvel élément créé, qui vont pointer respectivement sur l'ancien dernier élément, et sur le premier ; et le chaînage next de l'ancien dernier élément et prev du premier élément, qui vont pointer sur notre nouvel élément.
Du coup le code est très simple:
static void append(dlist **new, int j) { /* we have to create a new item in all cases */ dlist *const item = init(j);
/* We have to chain 'item' ; ie. * change current last 'next' member * change current first 'prev' member
=>last<=>[first]<=>second<=...
// =>last<=>item===[first]<=>second<=... / / here here */
/* previous last element or item */ dlist *const last = *new != NULL ? (*new)->prev : item;
/* pointer to current last element pointer or pointer to item */ dlist **const plast = *new != NULL ? &(*new)->prev : new;