快排
- 设立基准值,以基准值为中心,根据分治思路把大于基准值放一边,小于基准值放另一边。
- 递归上一步的操作。
基准值获取想法
- 1.从最左或最右或中间或随机或三取中。
- 2.基准值的获取直接影响了时间算法的复杂度,理想情况是0(nlogn),最坏情况是n^2。
- 3.所以快排算法是不稳定的。
第一种:取最左边值为基准值
/ 左边为基准
public static int[] quickSortLeft(int[] num, int leftPos, int rightPos) {
if (rightPos < leftPos)
return num;
else {
// step1:选择基准数
int initLeftPos = leftPos;
int initRightPos = rightPos;
int pivot = num[leftPos];
while (rightPos > leftPos) {
// step2:从右边开始寻找第一个小于基准数的index
while (num[rightPos] >= pivot && rightPos > leftPos) {
rightPos--;
}
// step3:从左边开始寻找第一个大于基准数的index
while (num[leftPos] <= pivot && rightPos > leftPos) {
leftPos++;
}
// 如果符合条件则交换,就是把小于基准数的换到基准数左边
if (rightPos > leftPos)
swap(num, leftPos, rightPos);
}
// step4:把基准数归位
swap(num, leftPos, initLeftPos);
// step5:基准数左边继续做步骤step1~step4
quickSortLeft(num, initLeftPos, leftPos - 1);
// step6:基准数右边继续做步骤step1~step4
quickSortLeft(num, rightPos + 1, initRightPos);
return num;
}
}
第二种:取最右边值为基准值
要注意的是,与取左边为基准不一样的是,得先从右边开始查找第一个比基准数小的index,(取左边为基准时,先从左边查找比基准数大的index)
/右边为基准
public static int[] quickSortRight(int[] num, int leftPos, int rightPos) {
if (rightPos < leftPos)
return num;
else {
int initLeftPos = leftPos;
int initRightPos = rightPos;
int pivot = num[rightPos];
while (rightPos > leftPos) {
while (num[leftPos] <= pivot && rightPos > leftPos) {
leftPos++;
}
while (num[rightPos] >= pivot && rightPos > leftPos) {
rightPos--;
}
if (rightPos > leftPos)
swap(num, leftPos, rightPos);
}
swap(num, rightPos, initRightPos);
quickSortRight(num, initLeftPos, leftPos - 1);
quickSortRight(num, rightPos + 1, initRightPos);
return num;
}
}
第三种:取中间值为基准值
略
第四种:取随机index对应的值为基准值
可以是只取一次随机,然后直接使用取左边/右边为基准算的方法,这里是每次递归都取一次随机基准数
// 随机基准
public static int[] quickSortRand(int[] num, int leftPos, int rightPos) {
if (rightPos <= leftPos)
return num;
else {
int random = new Random().nextInt(rightPos+1) % (rightPos-leftPos) + leftPos;
// 把基准数换到左边
swap(num, leftPos, random);
// step1:选择基准数
int initLeftPos = leftPos;
int initRightPos = rightPos;
int pivot = num[leftPos];
while (rightPos > leftPos) {
// step2:从右边开始寻找第一个小于基准数的index
while (num[rightPos] >= pivot && rightPos > leftPos) {
rightPos--;
}
// step3:从左边开始寻找第一个大于基准数的index
while (num[leftPos] <= pivot && rightPos > leftPos) {
leftPos++;
}
// 如果符合条件则交换,就是把小于基准数的换到基准数左边
if (rightPos > leftPos)
swap(num, leftPos, rightPos);
}
// step4:把基准数归位
swap(num, leftPos, initLeftPos);
// step5:基准数左边继续做步骤step1~step4
quickSortRand(num, initLeftPos, leftPos - 1);
// step6:基准数右边继续做步骤step1~step4
quickSortRand(num, rightPos + 1, initRightPos);
return num;
}
}
第五种:三取中
基本思想:
- 取第一个数,最后一个数,第(N/2)个数即中间数,三个数中数值中间的那个数作为基准值。举个例子,对于int a[] = { 2,5,4,9,3,6,8,7,1,0};,‘2’、‘3’、‘0’,分别是第一个数,第(N/2)个是数以及最后一个数,三个数中3最大,0最小,2在中间,所以取2为基准值。
- 取第一个数,最后一个数,随机的一个数,三个数中数值中间的那个数作为基准值。
swap方法
//swap方法:将数组中leftPos和rightPos上的两个数值进行交换
public static void swap(int[] num, int leftPos, int rightPos) {
int temp = num[leftPos];
num[leftPos] = num[rightPos];
num[rightPos] = temp;
}
测试
public static void main(String[] args) {
int[] num = new int[]{9,1,5,3,10,8,2,7,6,4,4,5};
for (int a : quickSortRand(num, 0, num.length - 1)) {
System.out.print(a + " ");
}
}