Week2 Assignment - Quicksort - Stanford - Algorithm: Design and Analysis Part I

来源:互联网 发布:fluc网络测试仪 编辑:程序博客网 时间:2024/05/29 09:55

题注

因为要给晚注册的同学们一些时间,Stanford的Coursera公开课《Algorithm: Design and Analysis Part I》延期了一周。本周的Programming Assignment终于在昨天公布了。本周的问题是Quicksort中,选择不同的Pivot对于总比较次数影响。题目本身不难,实现过程中也能很好地理解Quicksort的实现过程。

不过,因为本周我自己的事情确实比较多,因此没有完全自己实现代码。我参考了CSDN上另一位博友,Felven的代码,其博客地址为http://blog.csdn.net/zhaoxinfan。令人惊异的是,他的博客竟然有1000篇… 真是一个高产的博友啊!

题目

GENERAL DIRECTIONS:

Download the text file here. 

The file contains all of the integers between 1 and 10,000 (inclusive, with no repeats) in unsorted order. The integer in the ith row of the file gives you the ith entry of an input array.

Your task is to compute the total number of comparisons used to sort the given input file by QuickSort. As you know, the number of comparisons depends on which elements are chosen as pivots, so we'll ask you to explore three different pivoting rules.
You should not count comparisons one-by-one. Rather, when there is a recursive call on a subarray of length m, you should simply add m1 to your running total of comparisons. (This is because the pivot element is compared to each of the other m1elements in the subarray in this recursive call.)

WARNING: The Partition subroutine can be implemented in several different ways, and different implementations can give you differing numbers of comparisons. For this problem, you should implement the Partition subroutine exactly as it is described in the video lectures (otherwise you might get the wrong answer).

DIRECTIONS FOR THIS PROBLEM:

For the first part of the programming assignment, you should always use the first element of the array as the pivot element.

HOW TO GIVE US YOUR ANSWER:

Type the numeric answer in the space provided.
So if your answer is 1198233847, then just type 1198233847 in the space provided without any space / commas / other punctuation marks. You have 5 attempts to get the correct answer.
(We do not require you to submit your code, so feel free to use the programming language of your choice, just type the numeric answer in the following space.)

Question 2

GENERAL DIRECTIONS AND HOW TO GIVE US YOUR ANSWER:

See the first question.

DIRECTIONS FOR THIS PROBLEM:

Compute the number of comparisons (as in Problem 1), always using the final element of the given array as the pivot element. Again, be sure to implement the Partition subroutine exactly as it is described in the video lectures. Recall from the lectures that, just before the main Partition subroutine, you should exchange the pivot element (i.e., the last element) with the first element.


Question 3

GENERAL DIRECTIONS AND HOW TO GIVE US YOUR ANSWER:

See the first question.

DIRECTIONS FOR THIS PROBLEM:

Compute the number of comparisons (as in Problem 1), using the "median-of-three" pivot rule. [The primary motivation behind this rule is to do a little bit of extra work to get much better performance on input arrays that are nearly sorted or reverse sorted.] In more detail, you should choose the pivot as follows. Consider the first, middle, and final elements of the given array. (If the array has odd length it should be clear what the "middle" element is; for an array with even length 2k, use the kth element as the "middle" element. So for the array 4 5 6 7, the "middle" element is the second one ---- 5 and not 6!) Identify which of these three elements is the median (i.e., the one whose value is in between the other two), and use this as your pivot. As discussed in the first and second parts of this programming assignment, be sure to implement Partition exactly as described in the video lectures (including exchanging the pivot element with the first element just before the main Partition subroutine).

EXAMPLE: For the input array 8 2 4 5 7 1 you would consider the first (8), middle (4), and last (1) elements; since 4 is the median of the set {1,4,8}, you would use 4 as your pivot element.

SUBTLE POINT: A careful analysis would keep track of the comparisons made in identifying the median of the three candidate elements. You should NOT do this. That is, as in the previous two problems, you should simply add m1 to your running total of comparisons every time you recurse on a subarray with length m.

分析

首先,还是同样的问题,给定的File下载地址为http://spark-public.s3.amazonaws.com/algo1/programming_prob/QuickSort.txt,但是为了下载成功,大家需要用https访问并下载这个文件。真正的下载地址为https://spark-public.s3.amazonaws.com/algo1/programming_prob/QuickSort.txt。

QuickSort本身并不难,难在精确实现pivot的选择。Question 1中,永远选择第一个元素作为pivot。Question 2中,永远选择最后一个元素作为pivot。这两种选择都好说。第三个稍微麻烦一些,要求选择给定长度中第一个元素,最后一个元素,以及中间那个元素中,排序为中间的元素作为pivot。举个例子,如果给定数组第一个元素是9,最后一个元素是6,中间元素是3,由于6处于这三个数中间的位置,因此选择6作为pivot。

其实呢,这种方法的本质就是让pivot随机化,以避免出现特殊情况,导致算法复杂度由nlogn变成n^2。但是,由于每个上课的同学使用的是不同的语言,不同语言随机数的产生也不同,因此题目不能真正让大家随机取pivot,然后计算比较次数。如果这样的话,答案就不唯一了。其实呢,我倒是建议可以再给定一个简单的随机数生成算法,就生成1——10000的数。然后给定一个数作为大家共同的随机数产生种子。这样一来,既保证了pivot的随机性,又保证了答案的唯一性。

好啦,其他的也就没什么好说的了。这道题比较恶心的是,只有5次尝试的机会,而且谁也不知道,也无法验证答案的正确性,因此实现过程中要仔细考虑每一步中是否进行了比较。给定的源代码核心算法遵从了Felven的代码,但是写的更加一般化,一次显示了所有的答案,相比来说更好用一些。

源代码

import java.util.Arrays;public class Quicksort {public enum Mode {First, Last, Middle,}private int a[] = new int[10000];private static long numCompares = 0;private Mode mode;public Quicksort(Mode mode, int a[]) {this.a = a;this.mode = mode;numCompares = 0;}/** * Returns first element as pivot *  * @param start * @param end * @return */public int chooseFirstElementAsPivot(int start, int end) {return start;}/** * Returns the last element as pivot *  * @param start * @param end * @return */public int chooseLastElementAsPivot(int start, int end) {// Move pivot to start index.int temp = a[start];a[start] = a[end];a[end] = temp;return start;}/** * Returns the median of start, end and mid as pivot *  * @param start * @param end * @return */public int chooseMedianOfThreeAsPivot(int start, int end) {int pivotIndex = -1;int mid = ((end - start) / 2) + start;int b[] = new int[3];b[0] = a[start];b[1] = a[mid];b[2] = a[end];Arrays.sort(b);if (b[1] == a[start]) {pivotIndex = start;} else if (b[1] == a[mid]) {pivotIndex = mid;} else {pivotIndex = end;}// Move pivot to start index.int temp = a[start];a[start] = a[pivotIndex];a[pivotIndex] = temp;return start;}/** * Partitions the array about the pivot *  * @param start * @param end * @param pivot */public int partition(int start, int end, int pivotIndex) {// Update comparisonsCountnumCompares += (long) (end - start);// Partitionint i = start;int pivot = a[pivotIndex];for (int j = start; j <= end; j++) {if (a[j] < pivot) {i++;int temp = a[i];a[i] = a[j];a[j] = temp;}}// Put pivot into correct positionint temp = a[i];a[i] = pivot;a[pivotIndex] = temp;return i;}/** * Quick sort *  * @param start * @param end */public void sort(int start, int end) {if (end - start == 1) {// Base case, no recursive calls. 2 Element, just sort them.if (a[start] > a[end]) {int temp = a[start];a[start] = a[end];a[end] = temp;}// Increment comparisons count by 1 as there is 1 comparison// happening here.numCompares++;} else if (end <= start) {// Base case, only one element. Nothing to do.} else {// change pivot options hereint pivotIndex;switch (this.mode) {case First:pivotIndex = this.chooseFirstElementAsPivot(start, end);break;case Last:pivotIndex = this.chooseLastElementAsPivot(start, end);break;case Middle:pivotIndex = this.chooseMedianOfThreeAsPivot(start, end);break;default:throw new RuntimeException();}int partitionIndex = partition(start, end, pivotIndex);sort(start, partitionIndex - 1);sort(partitionIndex + 1, end);}}/** * @param args */public static void main(String[] args) {int a[] = new int[10000];In in = new In("QuickSort.txt");for (int i = 0; i < a.length; i++) {a[i] = in.readInt();}int unsorted[] = new int[a.length];System.arraycopy(a, 0, unsorted, 0, a.length);Quicksort quicksortFirst = new Quicksort(Mode.First, unsorted);quicksortFirst.sort(0, unsorted.length - 1);System.out.println("First: " + numCompares);System.arraycopy(a, 0, unsorted, 0, a.length);Quicksort quicksortLast = new Quicksort(Mode.Last, unsorted);quicksortLast.sort(0, unsorted.length - 1);System.out.println("Last: " + numCompares);System.arraycopy(a, 0, unsorted, 0, a.length);Quicksort quicksortMiddle = new Quicksort(Mode.Middle, unsorted);quicksortMiddle.sort(0, unsorted.length - 1);System.out.println("Middle: " + numCompares);}}


0 0
原创粉丝点击