大二时候学的快排和堆排现在忘的差不多了。。。重新学习了下快排并根据左神的视频进行了优化
经典快排是以最后一个元素作为基准点,随机快排是从集合中随机选择一个数和最后一个元素交换作为基准点,因此经典快排和随机快排的代码相差不大,但是随机快排的复杂度是通过期望得到的,是个概率上的复杂度,运用的更广泛。
优化后的快排主要是参考了荷兰国旗问题,将和基准数相等的数归为一类,这样在接下来的排序中,与基准数相同的数就不再需要排序了。
未优化的快速排序
public class test {
public static void main(String args[]){
int a[] = new int[(int) (Math.random()*20 + 1)];
for (int i = 0 ; i<a.length ;i++){
a[i] = (int) (Math.random()*100);
}
quickSort(a);
for (int i = 0 ; i<a.length ;i++){
System.out.println(a[i]);
}
}
public static void quickSort(int a[]){
if (a.length < 2 || a==null)
return;
quickSort(a,0,a.length-1);
}
public static void quickSort(int a[] , int l ,int r){
if(l < r){
int p = partition(a, l ,r);
quickSort(a, l, p-1); //递归排序
quickSort(a, p+1, r);
}
}
public static int partition(int a[], int l ,int r){
int pivot = a[r];
int i = l;
int j = r;
while (i < j){
while(i < j && a[i] <= pivot) i++;
while(i < j && a[j] >= pivot)j--;
if(i < j)
swap(a, i , j);
}
swap(a , r , j);
return i;
}
public static void swap(int arr[],int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
优化过的快排:
public class QuickSort {
public static void main(String args[]){
int a[] = new int[(int) (Math.random()*20 + 1)];
for (int i = 0 ; i<a.length ;i++){
a[i] = (int) (Math.random()*100);
}
quickSort(a);
for (int i = 0 ; i<a.length ;i++){
System.out.println(a[i]);
}
}
public static void quickSort(int a[]){
if (a.length < 2 || a==null)
return;
quickSort(a,0,a.length-1);
}
public static void quickSort(int a[] , int l ,int r){
if(l < r){
int p[] = partition(a, l ,r);
quickSort(a, l, p[0]-1);
quickSort(a,p[1]+1 , r);
}
}
public static int[] partition(int a[], int l ,int r){
int less = l-1; //比基准数小的区域
int more = r; //比基准数大的区域
while (l < more){
if (a[l] < a[r]){
swap(a, ++less , l++); //数比基准小,小区域向右移动
}else if(a[l] > a[r]){
swap(a, --more, l); //数比基准大,大区域向左移动
}else{
l++; //找到和基准相同的数,相等区域向右移
}
}
swap(a, more ,r);
return new int []{less+1,more }; //返回相等区域的首尾下标
}
public static void swap(int arr[],int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
随机快排和经典快排其实只差了一句代码,在partition函数中随机选一个数作为基准,将这个数和末尾数交换即可
public static int[] partition(int a[], int l ,int r){
swap(a, l + (int) (Math.random() * (r - l + 1)), r); //随机交换
int less = l-1; //比基准数小的区域
int more = r; //比基准数大的区域
while (l < more){
if (a[l] < a[r]){
swap(a, ++less , l++); //数比基准小,小区域向右移动
}else if(a[l] > a[r]){
swap(a, --more, l); //数比基准大,大区域向左移动
}else{
l++; //找到和基准相同的数,相等区域向右移
}
}
swap(a, more ,r);
return new int []{less+1,more }; //返回相等区域的首尾下标
}
基于非递归的快排,实则是将左右指针压入栈得到的,partition函数不需要更改,更改sort函数即可
public static void quickSort(int a[] , int l ,int r){
Stack <Integer> temp = new Stack<Integer>();
temp.push(r);
temp.push(l);
int i = l;
int j = r;
while (temp.empty() != true){
i=temp.pop();
j=temp.pop();
if(i < j){
int k = partition(a, i , j);
if ( k > i){
temp.push(k-1);
temp.push(i);
}
if ( k < j) {
temp.push(j);
temp.push(k+1);
}
}
}
}