2016-04-07 9 views
1

Ich habe den folgenden randomisierten Quicksort-Code mit Tail-Rekursion geschrieben. Ich wollte den Effekt sehen, keine Tail-Rekursion zu verwenden und wollte sehen, wie die Ausführungszeit und die Laufzeit beeinflusst werden. Wie können wir die Schwanzrekursion aus dem folgenden randomisierten Quicksort-Code entfernen?Quicksort ohne Schwanz Rekursion

#include<iostream> 
#include<cstdlib> 
using namespace std; 

int partition(int low,int high,int a[]) 
{ 
    int index=(rand()%(high-low))+low; 
    //cout<<endl<<index<<"----"<<endl; 
    int temp1=a[index]; 
    a[index]=a[low]; 
    a[low]=temp1; 
    int left,right,pivot_item=a[low]; 
    left=low; 
    right=high; 

    while(left<right) 
    { 
     while(a[left]<=pivot_item) 
      left++; 
     while(a[right]>pivot_item) 
      right--; 
     if(left<right) 
     { 
      int temp=a[right]; 
      a[right]=a[left]; 
      a[left]=temp; 
     } 
    } 
    a[low]=a[right]; 
    a[right]=pivot_item; 
    return right; 
} 

void quicksort(int low,int high,int a[]) 
{ 
    int pivot; 
    if(low<high) 
    { 
     pivot=partition(low,high,a); 
     quicksort(low,pivot-1,a); 
     quicksort(pivot+1,high,a); 
    } 
} 

int main() 
{ 
    srand(time(NULL)); 
    int n; 
    n=50; 
    int a[n]; 
    int i; 
    for(i=0;i<n;i++) 
     a[i]=(rand()%(1000-1)); 

    quicksort(0,n-1,a); 
    cout<<endl; 

    for(i=0;i<n;i++) 
     cout<<a[i]<<endl; 
    return 0; 
} 

EDIT: Gibt es eine Möglichkeit, den zweiten rekursive Aufruf in der quicksort Funktion sogar komplett zu löschen. Dies würde das Entfernen der Schwanzrekursion bedeuten und würde auch die Zeit signifikant beeinflussen.

+0

'Wie können wir die Schwanzrekursion aus dem folgenden randomisierten Quicksort-Code entfernen?' Und was hast du schon versucht? – Bonatti

+0

Ich habe versucht, entlang der Linien von http://www.geeksforgeeks.org/tail-recursion/ zu denken, aber habe nicht wirklich verstanden, wie ich es umsetzen könnte. – RaviTej310

+0

Bitte lesen Sie [diese (wie Sie fragen)] (http://stackoverflow.com/help/how-to-ask) und [diese (mcve)] (http://stackoverflow.com/help/mcve) vor Fragen, als diese werden Ihnen helfen, mehr und bessere Antworten von der Gemeinschaft zu bekommen. – Bonatti

Antwort

0

Compiler haben in der Regel eine Option zum Aktivieren und Deaktivieren bestimmter Optimierungen.

Im Fall von g ++ und verwandten Compilern können Sie die Tail Call-Optimierung mit den Optionen -foptimize-sibling-calls and -fno-optimize-sibling-calls aktivieren und deaktivieren. Wenn Sie einen anderen Compiler verwenden, lesen Sie das Handbuch.

Ich würde empfehlen, diese zu verwenden, um den Effekt der Schwanzrekursion zu vergleichen, weil es Ihnen erlaubt, denselben Algorithmus zu verwenden.


Quicksort ist natürlich tail rekursiv, es ist also nicht einfach, nicht-tail-recurve zu machen. Auf der einen Seite ist es einfach: Mach einfach etwas nach dem Rekursionsaufruf. Voilà, der Algorithmus ist nun nicht mehr tail rekursiv. Aber was Sie nach der Rekursion tun, ist wichtig. Es muss einen Nebeneffekt haben, sonst kann es weg optimiert werden. Aber dann würde es die Leistung beeinträchtigen und Sie messen nicht mehr nur den Effekt der Tail-Call-Optimierung.

Hier ist eine Idee. Implementieren Sie zwei identische Funktionen, die sie statt, wenn ich in dem Schwanz Anruf nennen:

void quicksort1(int low,int high,int a[]) 
{ 
    int pivot; 
    if(low<high) 
    { 
     pivot=partition(low,high,a); 
     quicksort1(low,pivot-1,a); 
     quicksort2(pivot+1,high,a); 
    } 
} 

void quicksort2(int low,int high,int a[]) 
{ 
    int pivot; 
    if(low<high) 
    { 
     pivot=partition(low,high,a); 
     quicksort2(low,pivot-1,a); 
     quicksort1(pivot+1,high,a); 
    } 
} 

Es ist immer noch möglich Endaufruf Optimierung auf beiden Seiten rekursiven Funktionen zu tun, so dass ich nicht garantieren, dass ein Smart-Compiler nicht Figur was los ist. Die Optimierung wird jedoch schwieriger zu implementieren sein, sodass einige Compiler dies möglicherweise nicht versuchen. Überprüfen Sie die Baugruppe, wenn Sie sicher sein wollen. Dies kann sich auch auf den Anweisungscache auswirken, was sich auf die Leistung auswirken kann, und nicht nur die Optimierung des Tail-Aufrufs deaktiviert.

+0

Was könnte das sein, was es nicht tail rekursiv macht, aber gleichzeitig die Optimierung der Algorithmen nicht behindert? Wie könnte ich das auch umsetzen? – RaviTej310

+0

@Sibi Ich weiß nicht einmal, ob Sie * etwas * implementieren können, das die Leistung sonst nicht beeinträchtigt. Deshalb schlage ich vor, dass Sie dem Compiler einfach sagen, die Optimierung nicht zu machen. – user2079303

+0

Gibt es trotzdem den zweiten rekursiven Aufruf zu entfernen und ihn durch etwas anderes zu ersetzen? Dies würde bedeuten, eine Schwanzrekursion zu vermeiden. – RaviTej310

0

Eine einfache Möglichkeit, die Tail-Rekursion zu entfernen, besteht darin, nach dem rekursiven Aufruf etwas anderes in der Funktion auszuführen. Unten habe ich die Funktion geändert, um einen Wert anstelle von void zurückzugeben, und eine return-Anweisung hinzugefügt, um etwas zurückzugeben, nachdem der rekursive Aufruf beendet wurde. Dies sollte minimale Auswirkungen auf die Leistung haben.

int quicksort(int low,int high,int a[]) 
{ 
    int pivot; 
    if(low<high) 
    { 
     pivot=partition(low,high,a); 
     quicksort(low,pivot-1,a); 
     quicksort(pivot+1,high,a); 
    } 
    return 0; 
} 
+0

Aber das macht nichts, um den Algorithmus zu optimieren, und ich denke nicht, dass das Hinzufügen es verlangsamen würde. Wie unterscheidet sich das zu meinem ursprünglichen Code? – RaviTej310

+0

Es optimiert nicht den Algorithmus, es verhindert nur Tail-Rekursion. Ich dachte, das ist es, was Sie vergleichen wollten - derselbe Algorithmus mit oder ohne Schwanzrekursion. – Barmar

+0

Gibt es sowieso den zweiten rekursiven Aufruf zu entfernen und durch etwas anderes zu ersetzen? Dies würde bedeuten, eine Schwanzrekursion zu vermeiden. – RaviTej310