1.partiton实现
partition(int[] a, int left, int right)
int x = a[right];这行代码选中一个主元,这里我们每次选择的都是当前序列中最右边那个。int p = left - 1;这行代码保存了一个变量p,用来记录比主元小的所有元素中,在序列中存放的位置最靠右的那个。接下来是个循环,从当前序列的第一个循环到倒数第二个(right-1)元素,来进行和主元比较。因为最后一个已经是主元了,所以就没有必要循环到right了。循环里面先是一个比较if (a[i] <= x)。这里写的是小于等于,更改这个就可以改变序列式由小到大还是由大到小排列。这里则是由小到大排列。如果进入了if语句,则说明a[i](当前元素)比主元小,还记得之前的变量p吗,保存着比主元小的元素最右边的位置,这里先p++,接着把a[i]和a[p]交换,就是说把a[p]右边的元素和当前元素换位置。a[p]右边的元素是什么呢?可能就是当前元素,也可能是比主元大的元素。这样,就完成了比主元小的元素的处理。
可是如果a[i]>x呢,则不进入if执行这两行代码,也就是不动那个比主元大的元素。
这样直到循环结束,整个序列就变成了三部分,从a[left..p]是比主元小的元素,a[p+1..right-1]是比主元大的元素,a[right]则是主元。而我们划分的目的是将主元放在这两个序列的中间,则再执行一行语句swap(a, p+1, right);,将主元和比它大序列的第一个元素互换位置,就大功告成了。
书上的图解非常的清晰:(标号是根据上面代码所标,和书上不太一样,但意思是一样的)
2.应用
1.排序
将数组以某个中间元素为轴,划分成两部分,左边比轴小,右边比轴大
int Partition(int *arr, int start, int end)
{
srand((unsigned)time(0));
int index = rand()%(end-start+1) + start;
swap(arr[index],arr[end]);
int small = start - 1;
for(index = start; index < end; ++index)
{
if ( arr[index] <= arr[end])
{
++small;
if(small != index)
swap(arr[index],arr[small]);
}
}
++small;
swap(arr[small],arr[end]);
return small;
}
2.分割字符串,数组
将数组中奇数移到左边,偶数移到右边
void partion(int A[],int p ,int r)
{
int i = p-1;
int j;
for( j=p; j<=r;j++)
{
if(A[j]%2 ==1)
{
i++;
swap(A[j],A[i]);
}
}
// swap(A[j],A[i+1]);
}
将字符串中*号移到左边,字母移到右边,保持字母相对顺序不变
char* StrMv(char* str, int n)
{
int high=0;
int i=n-2;
while(*(str+i)!='*') i--;
high=i;
while(i>=0)
{
if(*(str+i)=='*') i--;
else
{
Swap(*(str+i), *(str+high));
high--;
}
}
return str;
}
3,线性选择
求第K大的数
{
srand((unsigned)time(0));
int x,i,j,tmp;
x = rand()%(r-p+1) + 1;
swap (arr[x],arr[r]);
int pivot = arr[r];
i = p -1;
for (j = p; j <= r-1; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(arr[j],arr[j]);
}
}
swap(arr[r],arr[i+1]);
return i+1;
}
int Randomizedselect(int *arr,int p,int r,int i)
{
if (p==r)
return arr[p];
int q = Randomizedpatition(arr,p,r);
int k = q-p+1;
if(k < i)
return Randomizedselect(arr,q+1,r,i-k);
else if (k==i)
return arr[q];
else
return Randomizedselect(arr,p,q-1,i);
}