2009-08-13 10 views
8

Ich versuche, mein C++ zu verbessern, indem ich ein Programm erstelle, das eine große Anzahl von Zahlen zwischen 1 und 10^6 benötigt. Die Buckets, die die Zahlen in jedem Durchgang speichern, sind ein Array von Knoten (wobei Knoten eine von mir erstellte Struktur ist, die einen Wert und ein nächstes Knotenattribut enthält).Radix Sort implementiert in C++

Nach dem Sortieren der Zahlen in Buckets nach dem geringstwertigen Wert, habe ich das Ende eines Bucket-Punktes an den Anfang eines anderen Buckets (damit ich die gespeicherten Zahlen schnell abrufen kann, ohne die Reihenfolge zu stören). Mein Code hat keine Fehler (entweder Compilieren oder Runtime), aber ich habe eine Wand in Bezug darauf getroffen, wie ich die verbleibenden 6 Iterationen lösen werde (da ich den Zahlenbereich kenne).

Das Problem, das ich habe, ist, dass zunächst die Zahlen der RadixSort-Funktion in Form eines int-Arrays geliefert wurden. Nach der ersten Iteration der Sortierung werden die Zahlen nun im Array von Strukturen gespeichert. Gibt es eine Möglichkeit, dass ich meinen Code überarbeiten könnte, so dass ich nur eine for-Schleife für die 7 Iterationen habe, oder brauche ich eine for-Schleife, die einmal ausgeführt wird, und eine weitere Schleife darunter, die 6 mal ausgeführt wird, bevor die vollständig sortiert zurückgegeben wird Liste?

#include <iostream> 
#include <math.h> 
using namespace std; 

struct node 
{ 
    int value; 
    node *next; 
}; 

//The 10 buckets to store the intermediary results of every sort 
node *bucket[10]; 
//This serves as the array of pointers to the front of every linked list 
node *ptr[10]; 
//This serves as the array of pointer to the end of every linked list 
node *end[10]; 
node *linkedpointer; 
node *item; 
node *temp; 

void append(int value, int n) 
{ 
    node *temp; 
    item=new node; 
    item->value=value; 
    item->next=NULL; 
    end[n]=item; 
    if(bucket[n]->next==NULL) 
    { 
     cout << "Bucket " << n << " is empty" <<endl; 
     bucket[n]->next=item; 
     ptr[n]=item; 
    } 
    else 
    { 
     cout << "Bucket " << n << " is not empty" <<endl; 
     temp=bucket[n]; 
     while(temp->next!=NULL){ 
      temp=temp->next; 
     } 
     temp->next=item; 
    } 
} 

bool isBucketEmpty(int n){ 
    if(bucket[n]->next!=NULL) 
     return false; 
    else 
     return true; 
} 
//print the contents of all buckets in order 
void printBucket(){ 
    temp=bucket[0]->next; 
    int i=0; 
    while(i<10){ 
     if(temp==NULL){ 
      i++; 
      temp=bucket[i]->next;      
     } 
     else break; 

    } 
    linkedpointer=temp; 
    while(temp!=NULL){ 
     cout << temp->value <<endl; 
     temp=temp->next; 
    } 
} 

void radixSort(int *list, int length){ 
    int i,j,k,l; 
    int x; 
    for(i=0;i<10;i++){ 
     bucket[i]=new node; 
     ptr[i]=new node; 
     ptr[i]->next=NULL; 
     end[i]=new node; 
    } 
    linkedpointer=new node; 

    //Perform radix sort 
    for(i=0;i<1;i++){ 
     for(j=0;j<length;j++){   
      x=(int)(*(list+j)/pow(10,i))%10;    
      append(*(list+j),x); 
      printBucket(x); 
     }//End of insertion loop 
     k=0,l=1; 

     //Linking loop: Link end of one linked list to the front of another 
     for(j=0;j<9;j++){ 
      if(isBucketEmpty(k)) 
       k++; 
      if(isBucketEmpty(l) && l!=9) 
       l++; 
      if(!isBucketEmpty(k) && !isBucketEmpty(l)){ 
       end[k]->next=ptr[l]; 
       k++; 
       if(l!=9) l++; 
      } 

     }//End of linking for loop 

     cout << "Print results" <<endl; 
     printBucket(); 

     for(j=0;j<10;j++) 
      bucket[i]->next=NULL;      
     cout << "End of iteration" <<endl; 
    }//End of radix sort loop 
} 

int main(){ 
    int testcases,i,input; 
    cin >> testcases; 
    int list[testcases]; 
    int *ptr=&list[0]; 
    for(i=0;i<testcases;i++){ 
     cin>>list[i]; 
    } 

    radixSort(ptr,testcases); 
    return 0; 
} 
+3

Nichts für ungut, aber Ihr Code sieht aus wie ein gutes Beispiel dafür, wie einfache Dinge zu tun kompliziert ;-) – hirschhornsalz

Antwort

10

Ich denke, dass Sie Ihre Lösung stark überkomplizieren. Sie können Radix mit dem einzelnen Array implementieren, das in der Eingabe empfangen wird, wobei die Buckets in jedem Schritt durch ein Array von Indizes dargestellt werden, die den Startindex jedes Buckets im Eingabearray markieren.

In der Tat könnte man tut es auch rekursiv:

// Sort 'size' number of integers starting at 'input' according to the 'digit'th digit 
// For the parameter 'digit', 0 denotes the least significant digit and increases as significance does 
void radixSort(int* input, int size, int digit) 
{ 
    if (size == 0) 
     return; 

    int[10] buckets; // assuming decimal numbers 

    // Sort the array in place while keeping track of bucket starting indices. 
    // If bucket[i] is meant to be empty (no numbers with i at the specified digit), 
    // then let bucket[i+1] = bucket[i] 

    for (int i = 0; i < 10; ++i) 
    { 
     radixSort(input + buckets[i], buckets[i+1] - buckets[i], digit+1); 
    } 
} 

Natürlich buckets[i+1] - buckets[i] einen Pufferüberlauf verursachen, wenn i 9 ist, aber ich weggelassen, um die zusätzliche Überprüfung oder willen Lesbarkeit; Ich vertraue darauf, dass du weißt, wie man damit umgeht.

Mit diesem müssen Sie nur anrufen radixSort(testcases, sizeof(testcases)/sizeof(testcases[0]), 0) und Ihr Array sollte sortiert werden.

+0

Ich bin nicht sicher, aber die Art, wie ich es verstehe, Sie werden in jeder Rekursion Schritt sortieren nur einen der Buckets im vorherigen Schritt. Wenn Sie mit dem am wenigsten signifikanten beginnen, bedeutet dies, dass Sie sie aufgrund der Beschränkung auf den Bucket im rekursiven Aufruf von der niedrigstwertigen zur höchstwertigen Klasse sortiert haben. Liege ich da falsch? – StampedeXV

+0

Es funktioniert beim Start mit der höchstwertigen Zahl, oder? – StampedeXV

+0

Ich verstehe nicht ganz, was Ihre Frage ist: Der Algorithmus oben ist Tiefe zuerst, in dem der zweite Bucket im ersten rekursiven Aufruf (Sortierung nach der niedrigstwertigen Ziffer) beginnt erst sortiert werden, sobald der erste Bucket hat wurde vollständig sortiert (bis zur höchstwertigen Stelle). Und ja, Radix-Sortierung funktioniert, wenn Sie von der höchstwertigen Stelle zur niedrigstwertigen gehen. – suszterpatt

1

Da Ihre Werte sind Ints im Bereich von 0 ... 1.000.000

Sie einen int-Array von der Größe 1000001, und tun das Ganze in zwei Durchgängen

Init das zweite Array erstellen alle Nullen.

Machen Sie einen Durchlauf durch Ihr Eingabe-Array und verwenden Sie den Wert als Index , um den Wert im zweiten Array zu erhöhen.

Sobald Sie das tun, ist der zweite Durchgang einfach. Spaziergang durch das zweite Array, und jedes Element sagt Ihnen, wie oft diese Nummer im ursprünglichen Array erschien. Verwenden Sie diese Informationen, um Ihr Eingabearray neu zu befüllen.

+0

Angenommen, Ihre Eingabe-Array-Größe ist 10. Sie werden 32 MB (32-Bit-Ints vorausgesetzt) ​​verwenden, um es zu sortieren? FYI, was Sie beschrieben haben, ist Radix-Sortierung mit einem 64-Bit-Radix. Eine der Herausforderungen bei der Radix-Sortierung besteht darin, eine geeignete Radix zu wählen, die nicht zu viel Platz benötigt. 8bit ist nicht ungewöhnlich, aber selbst eine 16-Bit-Radix würde 2^16 * sizeof (int) = 256 KB für den Hilfsspeicher nehmen. –

+3

Ich glaube, das nennt man Sort. –

1

Um den Prozess mit besserer Speicherverwaltung zu beschleunigen, erstellen Sie eine Matrix für die Zähler, die in Indizes umgewandelt werden, indem Sie einen einzelnen Durchlauf über das Array ausführen. Ordnen Sie ein zweites temp-Array der gleichen Größe wie das ursprüngliche Array zu und radix sort zwischen den beiden Arrays, bis das Array sortiert ist. Wenn eine ungerade Anzahl von Radix-Sortierdurchläufen ausgeführt wird, muss das temporäre Array am Ende in das ursprüngliche Array zurückkopiert werden.

Um den Prozess weiter zu beschleunigen, verwenden Sie Basis 256 statt Basis 10 für die Radix-Sortierung. Dies erfordert nur einen Scan-Durchlauf, um die Matrix- und vier Radix-Sortierdurchgänge zu erzeugen, um die Sortierung durchzuführen.Beispielcode:

typedef unsigned int uint32_t; 

uint32_t * RadixSort(uint32_t * a, size_t count) 
{ 
size_t mIndex[4][256] = {0};   // count/index matrix 
uint32_t * b = new uint32_t [COUNT]; // allocate temp array 
size_t i,j,m,n; 
uint32_t u; 
    for(i = 0; i < count; i++){   // generate histograms 
     u = a[i]; 
     for(j = 0; j < 4; j++){ 
      mIndex[j][(size_t)(u & 0xff)]++; 
      u >>= 8; 
     }  
    } 
    for(j = 0; j < 4; j++){    // convert to indices 
     m = 0; 
     for(i = 0; i < 256; i++){ 
      n = mIndex[j][i]; 
      mIndex[j][i] = m; 
      m += n; 
     }  
    } 
    for(j = 0; j < 4; j++){    // radix sort 
     for(i = 0; i < count; i++){  // sort by current lsb 
      u = a[i]; 
      m = (size_t)(u>>(j<<3))&0xff; 
      b[mIndex[j][m]++] = u; 
     } 
     std::swap(a, b);    // swap ptrs 
    } 
    delete[] b; 
    return(a); 
}