Chapter 4 QuickSort & Randomized Algorithm

QuickSort

  • futures

    • Divide and conquer paradigm
    • Sorts “in place” (就地排序)
    • Very practical (with tuning)
  • Divide and Conquer

    • Divide:Partition array into 2 subarrays around pivot x such that elems in lower subarrays <=x <= elems in upper subarray
      Ex. array A = (6,10,13,5,8,3,2,11),choose the first element 6 as the pivot.Then we want to partition A into 2 arrays such that A has the form like follows(Here x=6,where the left and the right can regard as 2 subarrays):
      在这里插入图片描述
    • Conquer: Recursively sort 2 subarrays
    • Combine:This is trivial for doing almostly nothing.
  • Key Point:Linear-time Θ(n) for partition subroutine.

    • Pseudocode for partition subroutine.
      Here, the subroutine return i as an partition for the next recurrence.
partiton(A,p,q)
    x ← A[p]
    i ← p
    for j ← p+1 to q
        do if A[j] <= x
            then i ← i+1
                exch A[i] ←→ A[j]
    exch A[p] ←→ A[i]
    return i
  • Pseudocode for recusive algorithm
quicksort(A,p,q)
    if p < q
    then r ← partition(A,p,q)
        quicksort(A,p,r-1)
        quicksort(A,r+1,q)
initCall()
    quicksort(A,1,n)

Attention: This basic algorithm is suitable for processing data without duplicates, and those with duplicates can use Hoare algorithm.

Ex .

partiton(A,p,q)
    x ← A[p]
    i ← p
    for j ← p+1 to q
        do if A[j] <= x
            then i ← i+1
                exch A[i] ←→ A[j]
    exch A[p] ←→ A[i]
    return i
    
initial array A: 6 10 13 5 8 3 2 11(choose 6 as pivot)
               i j->move j to find elem<pivot(We find 5,then i++,swap(A[i],A[j])
        We have: 6 5 13 10 8 3 2 11
        		   i     j->move j to find elem<pivot(We find 3,then i++,swap(A[i],A[j])
        We have: 6 5 3 10 8 13 2 11
        			 i      j>move j to find elem<pivot(We find 2,then i++,swap(A[i],A[j])
        We have: 6 5 3 2 8 13 10 11
        			   i      j >move j to find elem<pivot(None)
        Finally,We exchange(A[p],A[i])
        We have: 2 5 3 6 8 13 10 11

It is worth mentioning that there’s something wrong what the prefessor said in the example,the i should self-add before each swap rather than swap finished.

  • Java code
    Here I made some comparison between disorder input and order input ,which shows that disorder input case has better time consuming.
    在这里插入图片描述
package nov21;
import java.util.Arrays;
import java.util.Random;
public class QuickSortTester {
	public int[] list;
	public QuickSortTester(int num)
	{
		list = new int[num];
		for(int i=0;i<num;i++)
		{
			list[i] = (int)(Math.random()*20000+2);
		}
	}
	
	public  static void main(String[] args) {
		int[] a = new QuickSortTester(10000).list;
		int[] b = disrupt(a);// 打乱后的数组
		
		long t1 = System.currentTimeMillis();
		quickSort(a,0,a.length-1);
		// System.out.println(Arrays.toString(a));
		long t2 = System.currentTimeMillis();
		System.out.println("Running Time: "+(t2-t1)+" ms");
		
		
		long t3 = System.currentTimeMillis();
		quickSort(b,0,b.length-1);
		long t4 = System.currentTimeMillis();
		System.out.println("Disrupt-Running Time: "+(t4-t3)+" ms");
		
		// 用已经排好序的数组a
		long t5 = System.currentTimeMillis();
		quickSort(a,0,a.length-1);
		// System.out.println(Arrays.toString(a));
		long t6 = System.currentTimeMillis();
		System.out.println("Sorted_Running Time: "+(t6-t5)+" ms");
		
		int[] c = disrupt(a);// 打乱后的数组
		long t7 = System.currentTimeMillis();
		quickSort(c,0,c.length-1);
		// System.out.println(Arrays.toString(a));
		long t8 = System.currentTimeMillis();
		System.out.println("Disrupted-Sorted_Running Time: "+(t8-t7)+" ms");
		
		
		
	}
	
	public static  void quickSort(int[] a,int p,int q)
	{
		if(p<q)
		{
			int r = partition(a,p,q);
			quickSort(a,p,r-1);
			quickSort(a,r+1,q);
		}
	}
	
	public static int[] disrupt(int arr[]) {
		int arrTemp[] = new int[arr.length];
		int size = arr.length-1;
		Random rd = new Random();
		for(int i = 0 ; i < arr.length ; i++) {
			int rand = rd.nextInt(size+1);
			arrTemp[i] = arr[rand];
			arr[rand] = arr[size];
			size--;
		}
		return arrTemp;
		
	}

	public static int partition(int[] a,int p,int q)
	{
		int pivot = a[p];
		int i = p;
		for(int j=p+1;j<q;j++)
		{
			if(a[j]<=pivot)
			{
				i++;
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
		int temp = a[i];
		a[i] = pivot;
		a[p] = temp;
		return i;
	}
}

  • Runing time
    Analysis-assume all elems are distinct.

    • T(n) = worst-case time when

      • input sorted or reverse sorted
      • one side of partition has no elems
        then T(n) = T(0)+T(n-1)+Θ(n) = Θ(n ^2) (Arith series,like insertion sort).
        We can alse use recursion-tree :
        在这里插入图片描述
    • T(n) = best-case time when

      • we’are lucky to partition splits the arrays always n/2:n/2
        then T(n) = T(n)=2T(n/2)+Θ(n)=Θ(nlgn) (master method in case 2)
    • Suppose we’are able to partition splits the arrays always n/10:9n/10
      T(n) = T(n/10)+T(9n/10)+Θ(n)
      then we can use recursion-tree to konw
      在这里插入图片描述
      Conclusion:cnlog(10) n + Θ(n) <= T(n) <= cnlog(10/9) n + Θ(n)

  • Suppose we can alternate lucky,unlucky case :

L(n)=2U(n/2)+Θ(n)(lucky)
U(n)=L(n-1)+ Θ(n)(unlucky)
Then L(n)=2(L(n/2-1))+Θ(n/2))+Θ(n)
         =2L(n/2-1)+Θ(n)
         =Θ(nlgn)

Randomized Algorithm for Quick-Sort

advantages

  1. running time is independent of input ordering.
  2. No assumption about input distribution.
  3. No specific input elicit worst-case behavior.
  4. worst-case determined by random number generator.
  • Idea: randomly choose pivot use a random variant then we can get E[T(n)] is Θ(nlogn) with proof.
    The detailed proof is as follows:
    Sorry that my note is like draft.
    在这里插入图片描述
发布了80 篇原创文章 · 获赞 332 · 访问量 70万+

猜你喜欢

转载自blog.csdn.net/qq_40527086/article/details/103184193