快排一种分而治之的算法,目前有较为常用的有两种方法:双指针,填挖法。
双指针
改方法通过前后两个左右指针分别向右和左进行移动,左指针找比Pivot的数,右指针找比Pivot小的数,然后进行交互。
// 双指针法
public int partitionTwoPointers(int[] data, int lo, int hi) {
int v = data[lo];
int i = lo;
int j = hi + 1;
while (true) {
while (data[++i] <= v) {// 直到一个比v大的
if (i == hi) {
break;
}
}
while (data[--j] >= v) {// 找到一个比v小的
if (j == lo) {
break;
}
}
if (i >= j) {// 两个指针相遇,跳出循环
break;
}
// 交换位置
swap(data, i, j);
}
// data[j]要么比v小,要么等于j==lo
swap(data, j, lo);// 此时将较小的j移动到lo处,以保证data[lo..j-1]<=data[j]<=data[j+1..hi]
return j;
}
填挖法
所谓填挖,分两个操作一个挖,一个填。第一步就是将Pivot处挖出来,第二步然后从右开始找一个比Pivot小的数,挖出来填过去,第三步从左找个大于Pivot的值,挖出来填到刚刚右侧的地方。然后重复到左右在挖的地方相遇,这个时候把pivot值填过去。
public int partitionLomuto(int[] data, int lo, int hi) {
int pivot = data[lo];
int holeIndex = lo;
int i = lo+1 ;
int j = hi;
boolean isFromRightToLeft = true;
while (i <=j) {
if (isFromRightToLeft) {//从右到左扫描
if (data[j] < pivot) {// swap
swap(data, holeIndex, j);
holeIndex = j;
isFromRightToLeft = false;//交换方向
}
j--;//继续扫描
} else {//从左到右扫描
if (data[i] > pivot) {// swap
swap(data, holeIndex, i);
holeIndex = i;
isFromRightToLeft = true;//交换方向
}
i++;//继续扫描
}
}
data[holeIndex]=pivot;//填充回去
return holeIndex;
}
sort方法
public void sort(int[] data, int lo, int hi) {
if (lo >= hi) {
return;
}
int partition = partitionXXX(data, lo, hi);
sort(data, lo, partition - 1);
sort(data, partition + 1, hi);
}
复杂度
快排本身受原始数据顺序影响较大,取决于pivot是否能够很好的均分整个数据。最差情况为O(n^2),平均情况O(nlogn)