Page 1 sur 1

Trie de tableaux à n colonnes

Publié : lun. 04/oct./2004 0:11
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"

Publié : mar. 05/oct./2004 19:08
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"

Publié : mar. 05/oct./2004 20:11
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.

Publié : mar. 05/oct./2004 23:09
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é ?

Publié : mer. 06/oct./2004 3:41
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

Publié : mer. 06/oct./2004 20:35
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

Publié : jeu. 07/oct./2004 6:00
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

Publié : jeu. 07/oct./2004 13:15
par Le Soldat Inconnu
pourquoi moi, j'ai rien fait :mrgreen:

Publié : jeu. 07/oct./2004 21:29
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 :)

Publié : ven. 08/oct./2004 6:30
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

Publié : ven. 08/oct./2004 20:29
par Dräc
:)