クイックソート
テン古典的なソートアルゴリズム!
序文
してください必ずこれを見て:準備のアルゴリズム事前知識+コード環境をソートします。
上記の内容は準備ができたら、のはすぐにソートそれを始めましょう!
クイックソート
実装プロセス:
- ①から配列を選択するピボット点要素(ピボット)
要素点の軸の各選択要素0位置を仮定 - ②ピボット2のサブシーケンスに分割される
ピボット要素(左)前面にピボットよりも小さい
バックピボットピボット要素(右側)よりも大きくなる
放電素子側缶ピボットに等しいです - ①②③サブ操作シーケンス
ない再分割(配列で唯一の要素)まで
図は、クイックソートの性質がある示しています。
- 各要素は徐々にピボット点要素に変換されます
コンフィギュレーション・ピボットポイント
シーケンス6 { A、8 A、8 B、2 ,. 6 B、4 ,. 9 ,. 5 ,. 7} 構成軸点:
- まず、バックアップ要素0位置、ピボット点要素。
- 究極の目標は、構築することである中心要素シーケンスとしてピボット点:
左半分は、以下のピボット点要素以外の配列 ;
右側は、ピボット点要素よりも大きいの配列 ;
以下:
それでは、どのようにそれを構築するのですか?
最初の位置を配列決定するために開始し、
- ;以下シャフト要素よりも、サイトの要素を探して、右から左へのスキャン
後に見つけ、その後++、開始、所定の位置に始まり、見つけることが逆。 - 軸要素よりも大きい点要素を探し、左から右へスキャン、
後見出さ、端位置に、END-、次いで見つけるために逆。 - 次に、左及び右のオーバースキャン記載されている、==端を開始すると、バックアップ開始の中央に要素の旋回点。
このプロセスは混乱ビットです、あなたは後でまで見つけるために左から右へ左へ右、プロセスのサイクルから見る必要がある要素の左半分にピボットポイント未満のすべての要素を、ピボットポイントより大きいすべての要素要素の右半分に、ピボットポイントの完全な建設へ。
コンフィギュレーションのピボットポイント - のコード
コードを実装する方法左から右にスキャンすると、右から左のスキャンにそれを交互?コードを見てみると、その理由が理解されるであろう。。。
/**
* 构造出 [begin, end) 范围的轴点元素
* @return 轴点元素的最终位置
*/
private int pivotIndex(int begin, int end){
// 备份begin位置的元素
T pivot = array[begin];
// end指向最后一个元素
end--;
while(begin < end){
while(begin < end){ // 从右往左扫描
if(cmp(pivot, array[end]) < 0){ // 右边元素 > 轴点元素
end--;
}else{ // 右边元素 <= 轴点元素
array[begin++] = array[end];
break;
}
}
while(begin < end){ // 从左往右扫描
if(cmp(pivot, array[begin]) > 0){ // 左边元素 < 轴点元素
begin++;
}else{ // 左边元素 >= 轴点元素
array[end--] = array[begin];
break;
}
}
}
// 将轴点元素放入最终的位置
array[begin] = pivot;
// 返回轴点元素的位置
return begin; // begin==end
}
コンフィギュレーションのピボットポイント - 最適化
均一のピボット点の周りの要素の数だけでなく、比較するのに最良のケースを:
- T(N)= 2 * T(N / 2)+ O(N)= O(nlogn)
ピボットポイントの周りの要素の数が非常に不均一である場合は、最悪の場合:
- T(N)= T(N - 1)+ O(N)= O(N 2)
アプローチは、一般的であると解釈される最悪の場合の確率を減少させるために:
- ランダムに選択されたピボット点要素は、
ピボット点要素、ランダム要素のシーケンスの要素が位置を交換し始める前にバックアップすることができます。
// 随机选择轴点元素, 将 begin 位置的元素与序列中的随机元素交换一下
swap(begin, begin + (int)Math.random()*(end - begin));
// 备份begin位置的元素
T pivot = array[begin];
.....
思考?ピボット点要素に等しいです
配列のすべての要素は、ピボット点の要素に等しい場合、上記のアルゴリズムを使用して、シャフト要素は、2つのサブ均一に点列であってもよいです
思考:上記のコード、裁判官のCMP位置が変更された≤、≥どのような効果が再生されますか?
結果:
- シーケンスピボットポイント要素が非常に不均一なセグメント化
- 時間計算量Oの中で最悪の結果(N- 2)
クイックソート完全なコード
/**
* 快速排序
*/
public class QuickSort<T extends Comparable<T>> extends Sort<T> {
@Override
protected void sort() {
sort(0, array.length);
}
/**
* 对 [begin, end) 范围的元素进行快速排序
*/
private void sort(int begin, int end){
if(end - begin < 2) return;
// 确定轴点位置 O(n)
int mid = pivotIndex(begin, end);
// 对子序列进行快速排序
sort(begin, mid);
sort(mid + 1, end);
}
/**
* 构造出 [begin, end) 范围的轴点元素
* @return 轴点元素的最终位置
*/
private int pivotIndex(int begin, int end){
// 随机选择轴点元素
swap(begin, begin + (int)Math.random()*(end - begin));
// 备份begin位置的元素
T pivot = array[begin];
// end指向最后一个元素
end--;
while(begin < end){
while(begin < end){ // 从右往左扫描
if(cmp(pivot, array[end]) < 0){ // 右边元素 > 轴点元素
end--;
}else{ // 右边元素 <= 轴点元素
array[begin++] = array[end];
break;
}
}
while(begin < end){ // 从左往右扫描
if(cmp(pivot, array[begin]) > 0){ // 左边元素 < 轴点元素
begin++;
}else{ // 左边元素 >= 轴点元素
array[end--] = array[begin];
break;
}
}
}
// 将轴点元素放入最终的位置
array[begin] = pivot;
// 返回轴点元素的位置
return begin; // begin==end
}
}
20000の値は[1、10000]乱数でソートされ生成されます。
複雑性と安定性
複雑さとクイックソートの安定性:
- 好ましくは、平均時間計算:O(nlogn)
- 最悪時間計算量:O(N- 2)
- そのための再帰的な O(LOGN):呼び出された理由、スペースの複雑さ
- 属する不安定ソート