Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

probleme de realloc

18 réponses
Avatar
Nicolas
Bonjour,

Je développe actuellement une librairie pour manipuler des tas.
Pour profiter pleinement des algorithmes déjà découvert en O(log(n)),
j'ai besoin d'un tableau d'inverses (tableau qui stocke le rang de
l'element du tas) pour avoir un accès direct à la mémoire sans parcourir
tout le tas.

Mon problème réside dans l'allocation de ce tableau car il est parfois
tronqué par le début. En effet, realloc permet de rappetisser ou
d'agrandir le tableau par la fin de celui-ci. Mais je voudrais le faire
aussi par le début.

Ex:

1 | 3 | 9 | 6 | 7

insertion par le debut: 55

55 | 1 | 3 | 9 | 6 | 7

Je pourrais bien évidemment realloquer le tableau et recopié toutes les
valeurs mais je perdrais l'avantage des algorithmes en O(log(N))

Comment faire?

Merci
Nicolas

10 réponses

1 2
Avatar
Marc Boyer
Nicolas wrote:
Bonjour,

Je développe actuellement une librairie pour manipuler des tas.
Pour profiter pleinement des algorithmes déjà découvert en O(log(n)),
j'ai besoin d'un tableau d'inverses (tableau qui stocke le rang de
l'element du tas) pour avoir un accès direct à la mémoire sans parcourir
tout le tas.

Mon problème réside dans l'allocation de ce tableau car il est parfois
tronqué par le début. En effet, realloc permet de rappetisser ou
d'agrandir le tableau par la fin de celui-ci. Mais je voudrais le faire
aussi par le début.

Ex:

1 | 3 | 9 | 6 | 7

insertion par le debut: 55

55 | 1 | 3 | 9 | 6 | 7

Je pourrais bien évidemment realloquer le tableau et recopié toutes les
valeurs mais je perdrais l'avantage des algorithmes en O(log(N))


Globalement, tu veux une file ou tu peux insérer/ajouter aux deux
bouts mais pas au milieu, c'est ça ?

Avec un buffer circulaire, tu peux faire ça, mais quand on augmentera la
capacité, on sera en O(n).

Après, on peut tenter un compromis type liste chainée de tableaux.

Mais ton conteneur là, as-tu besoin de faire des accès par un indice ?
Si la réponse est non, pourquoi pas une simple liste chainée ?

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.

Avatar
Nicolas
Marc Boyer wrote:
Nicolas wrote:

Bonjour,

Je développe actuellement une librairie pour manipuler des tas.
Pour profiter pleinement des algorithmes déjà découvert en O(log(n)),
j'ai besoin d'un tableau d'inverses (tableau qui stocke le rang de
l'element du tas) pour avoir un accès direct à la mémoire sans parcourir
tout le tas.

Mon problème réside dans l'allocation de ce tableau car il est parfois
tronqué par le début. En effet, realloc permet de rappetisser ou
d'agrandir le tableau par la fin de celui-ci. Mais je voudrais le faire
aussi par le début.

Ex:

1 | 3 | 9 | 6 | 7

insertion par le debut: 55

55 | 1 | 3 | 9 | 6 | 7

Je pourrais bien évidemment realloquer le tableau et recopié toutes les
valeurs mais je perdrais l'avantage des algorithmes en O(log(N))



Globalement, tu veux une file ou tu peux insérer/ajouter aux deux
bouts mais pas au milieu, c'est ça ?


Ouais, c'est ça.


Avec un buffer circulaire, tu peux faire ça, mais quand on augmentera la
capacité, on sera en O(n).


J y avais bien pensé mais ca ne se gère pas avec une structure de donnée
en tableau et du coup, je perd le O(log(n))!


Mais ton conteneur là, as-tu besoin de faire des accès par un indice ?
Si la réponse est non, pourquoi pas une simple liste chainée ?


Comme c'est un tas, j'insère toujours en O(log(n)). Par contre,
le problème est l'insertion d'un élément qui éxiste déjà.
Je pourrais gérer le tas pour inserer l'element a la suite mais
je serais alors en O(log(n)) ou n est le nombre d'éléments...
Je serais plus interressé par un algo en O(log(n)) où n est le nombre de
dates distinctes - d'où le tableau d'inverse pour connaître en 1 passe
le rang dans le tas de cette date.
La liste chainée ne convient donc pas car je ne suis plus en 1 passe
mais en n passes! De nouveau, je perd le O(log(n))...

J'avais pensé à un tableau indexé à l'envers (la case 0 se trouvant à
la fin du tableau) mais j'ai toujours le même problème lors du
redimensionnement du tableau dans l'autre sens!

Je crois bien que je suis coincé!
D'autres idées?

Nicolas


Avatar
cedric
Tu n'as qu'à utiliser deux tableaux : l'un du milieu à la fin,
l'autre du milieu au début...
Avatar
Nicolas
Je ne sais pas ce qu'est un algo en zero-log-de-machin (je ne connais
pas les théories sur les algo) donc je vais probablement dire une
connerie (autant l'annoncer avant)...


Ce n'est zero mais la lettre O, ca signifie 'de l'Ordre de' et cela
correspond à la complexité d'un algo...


Quand tu veux tronquer au début, tu incrémente ce pointeur. Quand tu en
ajouter, tu le décrémente.
C'est plutôt une bonne idée (c'est même la première que j'ai implémenté)

mais les realloc se plante à coup sûr si tu ne lui files pas le ptr
qui à été malloc/realloc la première fois!


C'est d'ailleurs souvent ce que je fais pour mes tableau où j'ajoute ou
supprime à la fin, pour éviter de désalouer ce que j'aurais probablement
besoin de réallouer quelques instants plus tard (ce qui peut parfois
obliger à copier, si la place libérée a été récupérée par ailleurs)


Dans mon cas non, je desalloue pour de bon...



Merci en tout cas!
Nico

Avatar
Nicolas
cedric wrote:
Tu n'as qu'à utiliser deux tableaux : l'un du milieu à la fin,
l'autre du milieu au début...


Effectivement... Pourquoi n'y ai je pas pensé plus tôt?!
Merci, c'est une super idée!

@+
Nico

Avatar
Marc Boyer
Nicolas wrote:
Marc Boyer wrote:
Nicolas wrote:
Je développe actuellement une librairie pour manipuler des tas.
Pour profiter pleinement des algorithmes déjà découvert en O(log(n)),
j'ai besoin d'un tableau d'inverses (tableau qui stocke le rang de
l'element du tas) pour avoir un accès direct à la mémoire sans parcourir
tout le tas.

Mon problème réside dans l'allocation de ce tableau car il est parfois
tronqué par le début. En effet, realloc permet de rappetisser ou
d'agrandir le tableau par la fin de celui-ci. Mais je voudrais le faire
aussi par le début.

Ex:

1 | 3 | 9 | 6 | 7

insertion par le debut: 55

55 | 1 | 3 | 9 | 6 | 7

Je pourrais bien évidemment realloquer le tableau et recopié toutes les
valeurs mais je perdrais l'avantage des algorithmes en O(log(N))


Globalement, tu veux une file ou tu peux insérer/ajouter aux deux
bouts mais pas au milieu, c'est ça ?


Ouais, c'est ça.

Avec un buffer circulaire, tu peux faire ça, mais quand on augmentera la
capacité, on sera en O(n).


J y avais bien pensé mais ca ne se gère pas avec une structure de donnée
en tableau et du coup, je perd le O(log(n))!


Hum. Un buffer circulaire de taille fixe offre les opération
d'accès en O(1), et ajout/suppression en tête et queue en O(1).

Mais ton conteneur là, as-tu besoin de faire des accès par un indice ?
Si la réponse est non, pourquoi pas une simple liste chainée ?


Comme c'est un tas, j'insère toujours en O(log(n)). Par contre,
le problème est l'insertion d'un élément qui éxiste déjà.


C'est un multi-ensemble ?

Je pourrais gérer le tas pour inserer l'element a la suite mais
je serais alors en O(log(n)) ou n est le nombre d'éléments...
Je serais plus interressé par un algo en O(log(n)) où n est le nombre de
dates distinctes - d'où le tableau d'inverse pour connaître en 1 passe
le rang dans le tas de cette date.


Donc, le tableau d'inverse, tu le parcours toujours, tu ne fais
pas d'accès direct ou dichotomique. Donc, ce tableau d'inverse
peut être une liste.

La liste chainée ne convient donc pas car je ne suis plus en 1 passe
mais en n passes! De nouveau, je perd le O(log(n))...


?

J'avais pensé à un tableau indexé à l'envers (la case 0 se trouvant à
la fin du tableau) mais j'ai toujours le même problème lors du
redimensionnement du tableau dans l'autre sens!


Par symétrie, on inverse les avantages et les inconvénients ;-)

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.



Avatar
Nicolas
Marc Boyer wrote:
Nicolas wrote:

Marc Boyer wrote:

Nicolas wrote:

Je développe actuellement une librairie pour manipuler des tas.
Pour profiter pleinement des algorithmes déjà découvert en O(log(n)),
j'ai besoin d'un tableau d'inverses (tableau qui stocke le rang de
l'element du tas) pour avoir un accès direct à la mémoire sans parcourir
tout le tas.

Mon problème réside dans l'allocation de ce tableau car il est parfois
tronqué par le début. En effet, realloc permet de rappetisser ou
d'agrandir le tableau par la fin de celui-ci. Mais je voudrais le faire
aussi par le début.

Ex:

1 | 3 | 9 | 6 | 7

insertion par le debut: 55

55 | 1 | 3 | 9 | 6 | 7

Je pourrais bien évidemment realloquer le tableau et recopié toutes les
valeurs mais je perdrais l'avantage des algorithmes en O(log(N))


Globalement, tu veux une file ou tu peux insérer/ajouter aux deux
bouts mais pas au milieu, c'est ça ?


Ouais, c'est ça.


Avec un buffer circulaire, tu peux faire ça, mais quand on augmentera la
capacité, on sera en O(n).


J y avais bien pensé mais ca ne se gère pas avec une structure de donnée
en tableau et du coup, je perd le O(log(n))!



Hum. Un buffer circulaire de taille fixe offre les opération
d'accès en O(1), et ajout/suppression en tête et queue en O(1).


Heu... Certe, mais la recherche d'un élément précis se fait en O(n)...



Mais ton conteneur là, as-tu besoin de faire des accès par un indice ?
Si la réponse est non, pourquoi pas une simple liste chainée ?


Comme c'est un tas, j'insère toujours en O(log(n)). Par contre,
le problème est l'insertion d'un élément qui éxiste déjà.


C'est un multi-ensemble ?


Oui


Je pourrais gérer le tas pour inserer l'element a la suite mais
je serais alors en O(log(n)) ou n est le nombre d'éléments...
Je serais plus interressé par un algo en O(log(n)) où n est le nombre de
dates distinctes - d'où le tableau d'inverse pour connaître en 1 passe
le rang dans le tas de cette date.



Donc, le tableau d'inverse, tu le parcours toujours, tu ne fais
pas d'accès direct ou dichotomique. Donc, ce tableau d'inverse
peut être une liste.


Faux!
En fait, je traite des dates (c'est une simulation à évenements
discrets). Mon tas est donc composé d'évenements. Mon tableau d'inverse,
lui, d'indice de date... Il est composé de (date_max - date_min) cases.
Donc, j'ai un accès direct car il me suffit de vérifier que
inv[date_inserée] existe et ainsi j'ai le rang dans le tas!
(je vais quand même aller jeter un oeil du coté des tables de
hachage...)


La liste chainée ne convient donc pas car je ne suis plus en 1 passe
mais en n passes! De nouveau, je perd le O(log(n))...



?


??


J'avais pensé à un tableau indexé à l'envers (la case 0 se trouvant à
la fin du tableau) mais j'ai toujours le même problème lors du
redimensionnement du tableau dans l'autre sens!



Par symétrie, on inverse les avantages et les inconvénients ;-)
Oui, je m'en suis rendu compte... ;-)





Avatar
Nicolas
Nicolas wrote:
cedric wrote:

Tu n'as qu'à utiliser deux tableaux : l'un du milieu à la fin,
l'autre du milieu au début...



Effectivement... Pourquoi n'y ai je pas pensé plus tôt?!
Merci, c'est une super idée!

@+
Nico


Encore une super idée qui marche pas ... :-(
En effet, ça marcherait du tonnerre si mon tas était de taille fixe.
Mais ça pose problème quand je dois insérer un élément dans le tas
car les deux tableaux d'inverses changent et je dois recopier
la moitié d'un tableau à chaque fois (enfin seulement si le nombre
d'éléments distincts du tas est pair).

Mais comme je l'ai dit dans un autre post, plus haut, je vais essayer de
me diriger vers les tables de hachage. Qu'en pensez vous?

Nico


Avatar
Marc Boyer
Nicolas wrote:
Avec un buffer circulaire, tu peux faire ça, mais quand on augmentera la
capacité, on sera en O(n).


J y avais bien pensé mais ca ne se gère pas avec une structure de donnée
en tableau et du coup, je perd le O(log(n))!


Hum. Un buffer circulaire de taille fixe offre les opération
d'accès en O(1), et ajout/suppression en tête et queue en O(1).


Heu... Certe, mais la recherche d'un élément précis se fait en O(n)...


c'est pour cela que je te demandais si dans ce tableau là,
tu faisais des accès ou seulement des parcours.

Mais ton conteneur là, as-tu besoin de faire des accès par un indice ?
Si la réponse est non, pourquoi pas une simple liste chainée ?


Comme c'est un tas, j'insère toujours en O(log(n)). Par contre,
le problème est l'insertion d'un élément qui éxiste déjà.


C'est un multi-ensemble ?


Oui


OK

Je pourrais gérer le tas pour inserer l'element a la suite mais
je serais alors en O(log(n)) ou n est le nombre d'éléments...
Je serais plus interressé par un algo en O(log(n)) où n est le nombre de
dates distinctes - d'où le tableau d'inverse pour connaître en 1 passe
le rang dans le tas de cette date.


Donc, le tableau d'inverse, tu le parcours toujours, tu ne fais
pas d'accès direct ou dichotomique. Donc, ce tableau d'inverse
peut être une liste.


Faux!


Ben, quand je lis "passe", pour moi, il y parcours du début
à la fin, c'est pour cela que je comprenais pas. En fait,
ce sont des recherches/accès que tu fais, pas des passes.

En fait, je traite des dates (c'est une simulation à évenements
discrets). Mon tas est donc composé d'évenements. Mon tableau d'inverse,
lui, d'indice de date... Il est composé de (date_max - date_min) cases.
Donc, j'ai un accès direct car il me suffit de vérifier que
inv[date_inserée] existe et ainsi j'ai le rang dans le tas!
(je vais quand même aller jeter un oeil du coté des tables de
hachage...)


Mais si ce sont des dates, pourquoi ne pas faire un tas
de piles de dates ?
As-tu jamais besoin d'accéder à un événement particulier,
ou seulement à un événement de date d, sans t'intéresser
à leur ordre dans la date.

La liste chainée ne convient donc pas car je ne suis plus en 1 passe
mais en n passes! De nouveau, je perd le O(log(n))...


?


??


La notion de "passe" implique généralement une traversée de tous
les éléments. Elles sont toutes en O(n).
Ce dont tu me parles, c'est d'un accès.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.




Avatar
Marc Boyer
Nicolas wrote:
Mais comme je l'ai dit dans un autre post, plus haut, je vais essayer de
me diriger vers les tables de hachage. Qu'en pensez vous?


Que tant que tu nous auras pas expliqué précisement tes
besoins et seulement des sous-parties (j'ai toujours pas
compris précisément le principe des indices inverses), on
aura du mal à trouver une solution optimale.

Rapidement, une table de hashage, ça a plusieurs inconvénients:
1) tu perds l'ordre, donc, dans un simu à événement discrets,
tu ne peux pas connaitre sans parcours total la prochaine
date à lequelle un év. va se produire
2) ça se redimensionne pas bien si je me souviens bien

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.

1 2