Trie de tableaux à n colonnes

Sujets variés concernant le développement en PureBasic
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Trie de tableaux à n colonnes

Message par Dräc »

Un certain nombre de travaux existent sur le trie de tableaux à une colonne.
En revanche peu de choses le sont quant le nombre de colonnes du tableau augmente.
Aussi voici ce que j’ai bricolé à partir d’un des tries pour tableau à une colonne (voir http://purebasic.myforums.net/viewtopic ... =quicksort)
pour traiter le cas n colonnes.

L’algorithme est un QuickSort. Dans le code, il suffit de changer les valeurs xdim et ydim pour tester le trie sur un tableau de la taille souhaité.

Les arguments de la procédure sont les suivants :

QuickSort(*ptr, row.l, col.l, colmax.l)
avec,
*ptr : adresse du tableau array() à trier
row : jusqu’à quelle ligne du tableau array() doit etre fait le trie
col : colonne du tableau array() à trier
colmax: nombre total de colonne du tableau array()

D’autre part, pour bien fonctionner, la procédure nécessite la déclaration du tableau dummy()


Enfin, je vois trois axes d’améliorations à cette procédure :
1-Trouver le moyen d’incorporer la déclaration du tableau dummy() à la procédure
2-Ne procéder à la permutation de l’ensemble des colonnes qu’à la fin du trie --> le trie serait plus performant pour les tableaux à grand nombre de colonnes
3-Etendre la procedure de trie à tous les types de tableaux : Byte, Word, Float, String

Code : Tout sélectionner

xdim =5
ydim =2

Dim dummy.l(0)
Dim array.l(xdim,ydim)

Procedure QuickSortRecursive(s.l, e.l, col.l, colmax.l)
  i=s 
  j=e
  k= col + (colmax+1)*((i+j)/2)
  pivot=dummy(k)
  Repeat 
    a = i+j
    ki= col + (colmax+1)*i
    While dummy(ki) < pivot 
      i = i+1
      ki= col + (colmax+1)*i
    Wend 
    a = i+j
    kj= col + (colmax+1)*j
    While dummy(kj) > pivot 
      j = j-1
      kj= col + (colmax+1)*j
    Wend
    If i <= j
;      Debug Str(i)+"/"+Str(j)
      For k=0 To colmax
        ki=k + (colmax+1)*i
        kj=k + (colmax+1)*j
        tmp = dummy(ki) 
        dummy(ki) = dummy(kj) 
        dummy(kj) = tmp
      Next k
      i = i+1
      j = j-1
    EndIf 
  Until i > j 
  If j > s  :  QuickSortRecursive(s,j, col, colmax) : EndIf 
  If i < e  :  QuickSortRecursive(i,e, col, colmax) : EndIf 
EndProcedure

Procedure QuickSort(*ptr, row.l, col.b, colmax.b)
  ; *ptr: adress of the array to be sort
  ; row: row until the sort will be done
  ; col: colum of the sort
  ; colmax: total colum of the array to be sort
  dummy() = *ptr
  QuickSortRecursive(0, row, col, colmax)
EndProcedure
; 
; 
RandomSeed(0) 
For i=0 To xdim
  text$=""
  array(i,0)=i+1
  text$ = text$ + " " + Str(array(i,0))
  For k=1 To ydim
    array(i,k)=Random(ValF("2e9"))
    text$ = text$ + " " + Str(array(i,k))
  Next k
  Debug text$
  Next i
  
  Debug "Start Sort"
  start = GetTickCount_()
  QuickSort(@array(),xdim, 1, ydim)
  end1 = GetTickCount_() - start
  Debug "End Sort"
  
  For i=0 To xdim 
    text$=Str(array(i,0))
    For k=1 To ydim
      text$ = text$ + " " + Str(array(i,k))
    Next k
    Debug text$
  Next i
  Debug ""
  Debug "QuickSort :"+Str(end1)+"ms"
Dernière modification par Dräc le mar. 05/oct./2004 19:29, modifié 1 fois.
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

Voici le meme code après avoir réalisé l’amélioration n°1 : suppression du tableau dummy()
Au passage, le code est simplifié avec la disparition d’une procédure.
La nouvelle fonction est la suivante :
QuickSort(adress.l, s.l, e.l, col.l, colmax.l)
adress: adresse du tableau array() à trier
s (start) : indice de ligne du tableau array() a partir duquel le trie doit débuter
e (end) : indice de ligne du tableau array() a partir duquel le trie doit se terminer
col : indice de la colonne du tableau array() à trier
colmax: dernier indice de colonne du tableau array()

Étendre alors le trie aux autres types de variables (amélioration n°3) est assez simple : il suffit de remplacer PeekL et PokeL par leurs homologues souhaités et de ne pas oublier de modifier aussi le facteur 4 (longueur d’un Long) dans le calcul de l’adresse :)

Cependant l’idéal serait que la meme procédure puisse détectée elle meme le type du tableau.

Code : Tout sélectionner

xdim =5
ydim =2

Dim array.l(xdim,ydim)

Procedure QuickSort(adress.l, s.l, e.l, col.l, colmax.l)
  i=s 
  j=e
  k= col + (colmax+1)*((i+j)/2)
  pivot=PeekL(adress+4*k)
  Repeat 
    a = i+j
    ki= col + (colmax+1)*i
    While PeekL(adress+4*ki) < pivot 
      i = i+1
      ki= col + (colmax+1)*i
    Wend 
    a = i+j
    kj= col + (colmax+1)*j
    While PeekL(adress+4*kj) > pivot 
      j = j-1
      kj= col + (colmax+1)*j
    Wend
    If i <= j
;      Debug Str(i)+"/"+Str(j)
      For k=0 To colmax
        ki=k + (colmax+1)*i
        kj=k + (colmax+1)*j
        val1 = PeekL(adress+4*ki) 
        val2 = PeekL(adress+4*kj)
        PokeL(adress+4*ki,val2)
        PokeL(adress+4*kj,val1) 
      Next k
      i = i+1
      j = j-1
    EndIf 
  Until i > j 
  If j > s  :  QuickSort(adress, s,j, col, colmax) : EndIf 
  If i < e  :  QuickSort(adress, i,e, col, colmax) : EndIf 
EndProcedure

; 
; 
RandomSeed(0) 
For i=0 To xdim
  text$=""
  array(i,0)=i+1
  text$ = text$ + " " + Str(array(i,0))
  For k=1 To ydim
    array(i,k)=Random(ValF("2e9"))
    text$ = text$ + " " + Str(array(i,k))
  Next k
  Debug text$
  Next i
  
  Debug "Start Sort"
  start = GetTickCount_()
  QuickSort(@array(), 0, xdim, 2, ydim)
  end1 = GetTickCount_() - start
  Debug "End Sort"
  
  For i=0 To xdim 
    text$=Str(array(i,0))
    For k=1 To ydim
      text$ = text$ + " " + Str(array(i,k))
    Next k
    Debug text$
  Next i
  Debug ""
  Debug "QuickSort :"+Str(end1)+"ms"
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

C'est bien, mais pour trier des grands tableaux tu devrais utiliser des pointeurs au lieu de Poke et Peek, pour une plus grande rapidité.

Code : Tout sélectionner

; PokeL(adress+4*ki,val2)
	PUSH   dword [esp+52]
	MOV    ebx,dword [esp+4]
	MOV    edi,dword [esp+44]
	SAL    edi,2
	ADD    ebx,edi
	MOV    eax,ebx
	CALL   PB_PokeL
A chaque Poke ou Peek, c'est comme si tu appelais une procédure.
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

Tu veux dire faire un truc comme ca ?

Code : Tout sélectionner

xdim =5
ydim =2

Dim array.l(xdim,ydim)
Structure Type
  l.l 
EndStructure

Procedure QuickSort(adress.l, s.l, e.l, col.l, colmax.l)
  Protected *ptr.Type
  i=s 
  j=e
  k= col + (colmax+1)*((i+j)/2)
  *ptr=adress+4*k
  pivot=*ptr\l
;  Debug pivot
;  Debug PeekL(adress+4*k)
  Repeat 
    ki= col + (colmax+1)*i
    *ptr=adress+4*ki
    While *ptr\l < pivot 
      i = i+1
      ki= col + (colmax+1)*i
      *ptr=adress+4*ki
    Wend 
    kj= col + (colmax+1)*j
    *ptr=adress+4*kj
    While *ptr\l > pivot 
      j = j-1
      kj= col + (colmax+1)*j
      *ptr=adress+4*kj
    Wend
    If i <= j
;      Debug Str(i)+"/"+Str(j)
      For k=0 To colmax
        ki=k + (colmax+1)*i
        kj=k + (colmax+1)*j
        *ptr=adress+4*ki
        val1 = *ptr\l
        *ptr=adress+4*kj
        val2 = *ptr\l
        *ptr\l = val1
        *ptr=adress+4*ki
        *ptr\l = val2
      Next k
      i = i+1
      j = j-1
    EndIf 
  Until i > j 
  If j > s  :  QuickSort(adress, s,j, col, colmax) : EndIf 
  If i < e  :  QuickSort(adress, i,e, col, colmax) : EndIf 
EndProcedure

; 
; 
RandomSeed(0) 
For i=0 To xdim
  text$=""
  array(i,0)=i+1
  text$ = text$ + " " + Str(array(i,0))
  For k=1 To ydim
    array(i,k)=Random(ValF("2e9"))
    text$ = text$ + " " + Str(array(i,k))
  Next k
  Debug text$
  Next i
  
  Debug "Start Sort"
  start = GetTickCount_()
  QuickSort(@array(), 0, xdim, 2, ydim)
  end1 = GetTickCount_() - start
  Debug "End Sort"
  
  For i=0 To xdim 
    text$=Str(array(i,0))
    For k=1 To ydim
      text$ = text$ + " " + Str(array(i,k))
    Next k
    Debug text$
  Next i
  Debug ""
  Debug "QuickSort :"+Str(end1)+"ms"
Je n’y avais pas pensé et c’est très astucieux…
Du coup, je dois pouvoir traiter différents types en complétant la structure "Type" et en appliquant le bon offset pour le calcul de l’adresse afin de se trouver sur le bon type (c’est clair non ? ;) )
En tous les cas merci pour l’éclairage !

PS : comment accèdes-tu au fichier assembleur généré ?
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Question fréquement posée

voir le post ici

http://purebasic.hmt-forum.com/viewtopic.php?t=198


Pour plus d'infos sur les commandes en lignes, voir la doc Purebasic

Utilisation du compilateur SHELL
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Oui, un truc comme ça. Je fais souvent des tri de tableaux à plusieurs colonnes et je n'avais jamais pensé à faire une procédure "universelle". Je réécrivais le code à chaque fois, grâce à toi, je vais pouvoir faire des copies collées de ta procédure. Merci.
Pour accéder au code assembleur, j'utilise mon propre outil : PureASM.
En deux clic de souris ton code apparaissait sous mes yeux en assembleur. Je vais faire quelques modifications et ajouter quelques fonctions supplémentaires, puis je posterai PureASM dans la rubrique truc et astuce dans les prochaines semaines... :D
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

erix14 a écrit :Pour accéder au code assembleur, j'utilise mon propre outil : PureASM.
En deux clic de souris ton code apparaissait sous mes yeux en assembleur. Je vais faire quelques modifications et ajouter quelques fonctions supplémentaires, puis je posterai PureASM dans la rubrique truc et astuce dans les prochaines semaines... :D
Excellent!
erix14, demande au soldat inconnu s'il peut le mettre dans un message qui reste en haut de l'écran pour ne pas avoir à faire une recherche dans le forum
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

pourquoi moi, j'ai rien fait :mrgreen:
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

Denis a écrit : Question fréquement posée

voir le post ici

http://purebasic.hmt-forum.com/viewtopic.php?t=198
Un peu sur les crocs le Denis !!!
erix14 a écrit : Pour accéder au code assembleur, j'utilise mon propre outil : PureASM.
En deux clic de souris ton code apparaissait sous mes yeux en assembleur. Je vais faire quelques modifications et ajouter quelques fonctions supplémentaires, puis je posterai PureASM dans la rubrique truc et astuce dans les prochaines semaines... :D
mais en tous les cas je suis content d'avoir posée la question !
C’est avec impatience que j’attend ton outils erix14 :)
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Dräc a écrit :
Denis a écrit : Question fréquement posée

voir le post ici

http://purebasic.hmt-forum.com/viewtopic.php?t=198
Un peu sur les crocs le Denis !!!
Pas du tout, je t'ai mis le lien :wink:

J'aurais simplement pu te dire de chercher mais j'ai fait une recherche pour toi (ma bonté me perdra :mrgreen: )

Si je met "déjà posé", c'est que j'ai déjà répondu à cette question plusieurs fois; j'aimerais que l'on puisse avoir ca dans une rubrique "question fréquement posée" du type de celle du forum anglais qui demande aux nouveaux de lire cette rubrique avant de poser la question. :idea:


Je ne suis pas admin du forum alors je ne fait que des suggestions. :D
Dräc
Messages : 526
Inscription : dim. 29/août/2004 0:45

Message par Dräc »

:)
Répondre