partition操作代码`
public int partition(char[] arr,int low,int high)
{
char pivot = arr[low];
//外层循环
while (low < high)
{
/*
内层循环
*/
//此次循环用来将一个比pivot小的数放到数组的前半部分
while (low < high && arr[high] > pivot) high--;
arr[low] = arr[high];
//此次循环用来将一个比pivot大的数放到数组的后半部分
while (low < high && arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
几段不易理解的点解析:
- 在内层的两个while循环的顺序不能够颠倒,因为初始时将pivot设置为arr[low],如果颠倒顺序将造成arr[high]值·的丢失。
- 每次循环都先将arr[high]的值赋给上次循环low所指向的arr[low],然后再将本次循环arr[low]的值赋给arr[high],这样就会造成外层循环结束之后arr[low]处的值在数组中已经存在于arr[high]的位置,所以最后再把pivot(也就是枢纽点)的值再赋值给arr[low],这样就完成了一次partition操作。
partition操作的一个应用
在一个无序数组中取得第key大的值,时间复杂度为O(n)。
QuickSort qs = new QuickSort();
int low = 0;
int high = arr.Length - 1;
int currentPivotKey = qs.partition(arr, low, high);
//currentPivotKey代表当前枢纽所处的位置,key代表枢纽的最终位置。
while (currentPivotKey != key)
{
if(currentPivotKey > key)
{
high = currentPivotKey - 1;
currentPivotKey = qs.partition(arr, low, high);
}
else
{
low = currentPivotKey + 1;
currentPivotKey = qs.partition(arr, low, high);
}
}
对于这段代码设计的感悟:
- 其实我在写代码时总有一种习惯,去思考这段代码如何运行,这种思考问题的方式有些时候是没必要的。比如这段代码,我只要知道一个总体的逻辑就可以,并不用了解计算机如何运行,把运行的问题交给计算机,我们只要告诉计算机怎么做就可以。下面第二点介绍一下设计思路。
- 对于该程序,首先要找到一个结束代码的点(什么时候结束),显而易见,当currentPivotKey == key时,就达到我们的目的,代码就可以结束,所以循环判断可以设置成二者不等则继续循环。循环未结束,只可能出现两种情况,currentKey大于或小于key。这时我们要做的就是告诉计算机两种情况分别该做什么即可。