2017-05-01 24 views
0

こんにちはすべて私はC++に新しく、検索とソートのアルゴリズムに没頭していて、自分で作成しようと決めました。クイックソートの実装

int main() 
{ 
    // Announce the program 
    cout << "\nImplementing the QuickSort Algorithm\n"; 
    // Declare useful values 
    const char BLANK = ' '; 
    size_t i = 0; 
    // Initialize our test data arrays 
    const size_t SIZE1 = 10; 
    int data1[]= {34, 33, 9, 45, 1, -1, 9, -18, 75, 100 }; 
    const size_t SIZE2 = 15; // Number of elements in the array to be sorted 
    int data2[]= {100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86 }; 
    const size_t SIZE3 = 1000; 
    int data3[SIZE3]; 
    // Initialize the third array to random int values 
    for (i = 0; i < SIZE3; i++) 
     data3[i] = rand(); 
    // Beginning of quick sort tests 
    // Sort the arrays and print the result with two blanks after each number 
    quicksort(data1, SIZE1); 
    cout << "\nSorted First Array: " << endl; 
    for (i = 0; i < SIZE1; i++) 
     cout << data1[i] << BLANK << BLANK; 
    cout << endl; 
    quicksort(data2, SIZE2); 
    cout << "\nSorted Second Array: " << endl; 
    for (i = 0; i < SIZE2; i++) 
     cout << data2[i] << BLANK << BLANK; 
    cout << endl; 
    // On the large third array, just print the first ten and last ten values 
    quicksort(data3, SIZE3); 
    cout << "\nSorted Third Array (first ten): " << endl; 
    for (i = 0; i < 10; i++) 
     cout << data3[i] << BLANK << BLANK; 
    cout << endl; 
    cout << "Sorted Third Array (last ten): " << endl; 
    for (i = SIZE3 - 10; i < SIZE3; i++) 
     cout << data3[i] << BLANK << BLANK; 
    cout << endl << endl; 
    system("Pause"); 
    return EXIT_SUCCESS; 
} 

と私は、関数の定義開始している:私は私のmainテストが書かれている

void quicksort(int data[ ], size_t n); 
// Precondition: data is an array with at least n components. 
// Postcondition: The elements of data have been rearranged so 
// that data[0] <= data[1] <= ... <= data[n-1]. 

void partition(int data[ ], size_t n, size_t& pivot_index); 
// Precondition: n > 1, and data is an array (or subarray) 
// with at least n elements. 
// Postcondition: The function has selected some "pivot value" 
// that occurs in data[0]..data[n-1]. The elements of data 
// have then been rearranged, and the pivot index set so that: 
// -- data[pivot_index] is equal to the pivot; 
// -- Each item before data[pivot_index] is <= the pivot; 
// -- Each item after data[pivot_index] is > the pivot. 

void setPivot(int data[ ], size_t n); 
// Precondition: n > 1 and data is an array or subarray 
// Postcondition: data[0] holds the selected pivot value 
// The original value of data[0] has been swapped with the selected pivot value 

:ここに私のプロトタイプはある

void quicksort(int data[ ], size_t n) 
// Library facilities used: cstdlib 
{ 
    size_t pivot_index; // Array index for the pivot element 
    size_t n1;   // Number of elements before the pivot element 
    size_t n2;   // Number of elements after the pivot element 

    if (n > 1) 
    { 
     // Partition the array, and set the pivot index. 
     partition(data, n, pivot_index); 

     // Compute the sizes of the subarrays. 
     n1 = pivot_index; 
     n2 = n - n1 - 1; 

     // Recursive calls will now sort the subarrays. 
     quicksort(data, n1); 
     quicksort((data + pivot_index + 1), n2); 
    } 
} 

void partition(int data[ ], size_t n, size_t& pivot_index) 
// Library facilities used: algorithm, cstdlib 
{ 
    assert(n > 1); 
    setPivot(data, n); 
} 

void setPivot(int data[ ], size_t n) 
// Library facilties used: algorithm, cstdlib 
// This function chooses a pivot value as the median of three 
// randomly selected values. The selected pivot is swapped with 
// data[0] so that the pivot value is in the first position of the array 
{ 
    assert(n > 1); 

} 

私の質問は、最良の方法だろう何をスピードに関してvoid partition(int data[], size_t n, size_t& pivot_indexvoid setPivot(int data[], size_t n)を終了しますか?

+1

'std :: partition'を試してください。 –

答えて

0

これは少し難解な質問ですが、私は両方の足であなたのジャンプが好きです。したがって、コンパイラを構築するときには、何らかの命令が他の命令と比較してどれくらいの時間単位に基づいて命令を選択するかを選択します。 Raymondのアドバイスを使用して、あらかじめ作成されたコードを使用するだけで、それで多くのことを学ぶことはできません。比較ソートアルゴリズムで最も高価な2つの命令は、配列内の比較とスワップであり、それらを最小限に抑えることです。

まず、良いパーティション分割アルゴリズムの背後にある数学について説明します。ピボットがデータ[0]にあると仮定し、その高価なスワップを最小限に抑える最良の方法を検討しましょう。配列を使用して...

[34, 33, 9, 45, 1, -1, 9, -18, 75, 100] 

良いパーティショニングは、私たちはソートされません(私たちは周りの場所から何かを移動する回数を最小限に抑えることができないので、我々はピボットを移動する回数を最小限にしますもしできれば)。

wall:=1 
for(i:=1; i < n; ++i){ 
    if(data[0]>data[i]){ 
     swap(data, wall, i) 
     ++wall 
    } 
} 

swap(data, wall-1, 0) 
pivot_index:=wall-1 

ここで、なぜこれを行うのが最も効率的な方法であるか答えてください。

  1. は、それは追加の数を最小限に抑えることが
  2. 高価スワップの数を最小限に抑えることが
  3. それは、100%が高速ですINC%のREGアセンブリ命令に変換される++を使用しているん追加保証されていないレジスタに1を加えるよりも(...しかし、おそらくそうである)。 (これを行うには本当に賢い)

次はピボットを選択するスマートな方法です。コメントには中央値が表示されますが、統計的な理由からその値を変更し、3つの乱数を選択します。実行時の複雑さはです。クイックソートはすべてピボットの選択についてです。誤って選んでください。それはO(n^2)であり、右を選ぶとO(n * log(n))に近似します。ピボットの最良の選択肢は、配列を2つの等しい長さに均等に分割する数です。あなたのデータポイントの50%がピボットよりも高く、50%が下にあります.e.i.平均。人口の平均を計算するのは遅く、道のりの平均ステップを計算する必要がある場合は私たちが得られるパフォーマンスが損なわれるため、サンプルの平均を人口の平均を推定するためにのみ使用します。

void setPivot(int data[ ], size_t n) 

    index1:= rand_uniform()*n 
    index2:= rand_uniform()*n 
    index3:= rand_uniform()*n 

    mean:=(data[index1]+data[index2]+data[index3])/3 

    offset1:=abs(index1-mean) 
    offset2:=abs(index2-mean) 
    offset3:=abs(index3-mean) 

    if(offset1 < offset2 && offset1 < offset3) 
     swap(data,0,index1) 
    else if(offset2 < offset1 && offset2 < offset3) 
     swap(data,0,index2) 
    else if(offset3 < offset1 && offset3 < offset2) 
     swap(data,0,index3) 

多くのオーバーヘッドが選ばれたpiviotが統計的に起こっているので、この方法は、しかしsetPivotが十分大きなnは、それはより速く、それをこのようにやっているため意味一定の時間複雑であり、それをやっていることは明らかですデータを2つの等しい部分に分割する頻度が高くなります。これは、良好な除算と征服アルゴリズムの全体点です。

+0

すごい!非常に有益!大規模なデータベースの場合、QuickSortがより高速なオプションになると言いますか?私はデータが元々ソートされている方法に応じてそれを知っています。降順または少なくともいくらかの昇順に並べ替えると、他の並べ替え方法が優先されますか?クイックソートのみを使うべきですか? –

+0

@AlexChapman異なるソートアルゴリズムがどのように機能するかを学ぶことはできますが、一度どのように動作するか分かると、一般的に標準ライブラリ(std :: sort')を使用するだけです。 – crashmstr

+0

*クイックソートには最高の時間があるので、私は言いません。それは平均的に良いランタイムを持ち、スマートなピボット選択を用いたこの実装は、O(n^2)の最悪の時間に実行する可能性は非常に低いです。 * HeapSort *という名前のO(n * log(n))時間で常に実行されるヒープを利用する別のソートアルゴリズムがあります。これは間違いなくチェックアウトする必要があります。実際に最適化したい場合は、n * void partition *が* void setPivot *より速いサイズを計算し、素朴なピボット選択に切り替えることができます。 – Kryler

関連する問題