快速排序图解( 二 )


intp=分区(arr、l、r);
输出(arr,l,p-1);
(经常预算):
}
专用静态(同internationalorganizations)国际组织部件
(可比[] arr,intl,intr) {
//在arr[l…r]范围内随机选择一个值作为校准点轴心
swap(arr,l,(int)(math. random*(rl^ 1))l);
可比v=arr[l];
intj=l;
for(inti=l1;i=r;i) {
if(arr[i] 。compareto(v) 0)
swap(arr,j1,i);
j.
}
}
swap(arr,l,j);
返回j;
}
双向快速排序
对于包含大量重复元素的数组,上面的快速排序效率很低,因为在我们上面的判断中,如果元素小于v,那么元素就放在v部分,如果元素大于等于v,那么就放在v部分 。这时如果数组中有大量重复的元素,v部分会变得很长,导致左右两边不平衡,性能降低 。
双向快速排序的步骤如下:
1.把v和v放在数组的两端,用i指向v的下一个元素,用j指向v的前一个元素 。
2.从i向后遍历,如果遍历的元素ev继续向后遍历,直到遍历的元素e=v,那么停止遍历 。从j开始向前遍历,如果遍历的元素为ev,继续向前遍历,直到遍历的元素e=v,然后停止遍历 。
3.交换一下我指向的元素和j指向的元素,然后我,j继续比较下一个 。
双向快速排序代码:
公共静态无效排序(可比[] arr) {
intn=arr.length
sort(arr,0,n1);
}
私有静态空排序(可比[] arr,intl,intr) {
//对于小规模数组,使用插入排序
if(rl=15){
insertionsort.sort(arr,l,r);
返回;
}
intp=partition(arr,l,r);
排序(arr,l,p1);
sort(arr,p1,r);
}
私有静态int分区(可比[] arr,intl,intr) {
//在arr[l…r]范围内随机选择一个值作为校准点轴心
swap(arr,l,(int)(math. random*(rl^ 1))l);
可比v=arr[l];
inti=l1,j=r;
while(true) {
//注意这里的边界,arr[i] 。compareto(v) 0,不能是arr[i] 。compareto(v)=0
//如果不加等号,此时会退出while循环,也就是交换i和j的值,这样对于一个包含大量相同元素的数组,交换两边相等的数据,可以在一定程度上保证两路的数据平衡 。
//从i向后遍历,如果遍历的元素ev,继续向后遍历,直到遍历的元素e=v,然后停止遍历
while(i=rarr[i] 。compareto(v) 0)
i;
}
//从j开始向前遍历,如果遍历的元素为ev,继续向前遍历,直到遍历的元素e=v,然后停止遍历
while(j=l^ 1 arr[j] 。compareto(v) 0)
j;
}
if(i=j) {
打破;
}
swap(arr,i,j);
i;
j;
}
//此时j指向的元素是数组中小于v的比较后一个元素,i指向的元素是数组中大于v的第一个元素 。
swap(arr,l,j);
返回j;
}
三向快速排序
三向快速排序的步骤如下:
1.在双向快速排序的基础上,我们将等于v的元素作为单一部分 。lt指向小于v部分的比较后一个元素,gt指向大于v部分的第一个元素 。
2.从i向后遍历,如果遍历的元素e=v,e直接合并到=v部分,然后i继续遍历 。如果你遍历元素ev,交换e部分的第一个元素和=v(lt1指向的元素),然后lt,我继续遍历 。如果遍历的元素ev,则交换e和v的前一个元素(gt-1指向的元素),然后gt,但此时不需要改变i,因为i位置的元素与gt位置之前的空白元素交换 。
3.遍历之后,i=gt,然后用lt-pointing元素交换l-pointing元素 。
4.在v形零件和v形零件上执行上述操作 。
三向快速排序相对于双向快速排序的优势在于,减少了重复元素的比较操作,因为重复元素在一次排序中已经被排列为单一部分,然后只需要对不等于重复元素的其他元素进行排序 。