SSD5_Optional Exercise 5分析
欢迎访问我的博客,接下来就是第十一周的Optional Exercise 5了
这个题目是要求我们学会排序算法--------选择排序和快速排序,具体算法也不用自己写,只是看就可以了,自己要写的真的不多,比较简单
题目是根据很多的数据排序来反映选择排序与快速排序的时间复杂度的不同
Description
The program to be completed for this assessment demonstrates the runtime differences between a stable and non-stable sort. The stable sort examined in this assessment is selection sort and the non-stable algorithm examined in this assessment is quicksort.
Each algorithm is encapsulated in a corresponding class. Method init of these classes populates an array. This function populates the array with data that triggers either the average or worst case of the algorithm. For the stable sort algorithm, selection sort, the average and worst case are identical. The quicksort algorithm, on the other hand, has distinct worst and average cases. A supplied main routine repeatedly initializes and sorts these arrays to demonstrate the differences between the stable and non-stable sort algorithms.
The correct implementation of method init requires the generation of random numbers. Use the rand library function to generate a random integer.
主要任务就是完成两个cpp的init函数实现
complete the implementation of method init for class selectionsort. Since this algorithm is stable, this implementation should be the same for the worst and average case. The implementation should populate the inherited numbers array with data that, when sorted, triggers the average case.
finish the implementation of method init for class quicksort. Since this algorithm is non-stable, this method should populate the inherited numbers array with different data to trigger the worst and average cases. Test your implementation by compiling and running the supplied main.cpp. The times reported for the worst case of the quicksort should be relatively close to the times reported for the average case of the selection sort.
不多说了,看写好的代码吧
main.cpp
#include <iostream> #include <cstdlib> #include "sort.h" #include "selectionsort.h" #include "quicksort.h" using namespace std; //意思是你的机子慢的话就减少排序的个数
//日期:2013/5/6
/* * This runs the sorts with your workloads and collects * timing information. Depending on the speed of your machine, it * could take hours to run. We suggest that, to collect your results, * you run it paramaterized as shown above. But, you probably want to * test your workloads with much smaller lists and fewer iterations, * first. * * If you abolutely can't wait for the results, reduce the number * of ITERATIONS, perhaps all the way to 1. This makes your results * a little less reliable, since outliers can get in the way, but... * If it is still going to slowly for you to finish on time, try * only MAX_SIZE=12000 ...or even MAX_SIZE=6000 iterations. * If you have to reduce MAX_SIZE below 24000, also reduce MIN_LIST * to 1500 or 750. */ int main (int argc, char *argv[]) { //选择排序平均情况 cout << "Selection sort: Average case" << endl; for (int n = MIN_SIZE; n <= MAX_SIZE; n *= 2) { selectionsort *selection = new selectionsort(n, AVG_CASE); selection->report(); delete selection; } cout << endl; //快速排序平均情况 cout << "Quick sort: Average case" << endl; for (int n = MIN_SIZE; n <= MAX_SIZE; n *= 2) { quicksort *quick = new quicksort(n, AVG_CASE); quick->report(); delete quick; } //快速排序最差情况 cout << "Quick sort: Worst case" << endl; for (int n = MIN_SIZE; n <= MAX_SIZE; n *= 2) { quicksort *quick = new quicksort(n, WORST_CASE); quick->report(); delete quick; } return EXIT_SUCCESS; }
然后是基类sort.h及sort.cpp
#ifndef SORT_H #define SORT_H #include <ctime> #include <cstdlib> #include <iostream> using namespace std; //定义各个常量 const int ITERATIONS = 10; const int MIN_SIZE = 3000; // Smallest size list to test const int MAX_SIZE = 24000; // largest size list to test const int BEST_CASE = 1; const int AVG_CASE = 2; const int WORST_CASE = 3; class sort { protected: //<time.h>中的clock_t clock_t start_time; //要排序的数组 int numbers[MAX_SIZE]; // list of numbers to sort (and then sorted) //统计交换次数 long numswaps; //incremented after each swap //总得要比较的数据和比较的情况 int how_many, workload_type; //交换两个数 void swapNumbers (int x, int y); //起始时间 void startTiming(); //结束时间 clock_t getElapsedTime(); //初始化数组 virtual void init(int how_many, int workload_type) = 0; public: //重置 void reset(); //结果 void report (); //输出 void printNumbers(); //核心排序方法,基类纯虚 virtual void sortNumbers() = 0; }; #endif
#include "sort.h" using namespace std; /* * This resets a Sort object to an unsorted list with exactly the same * parameters, so tests can be rerun for accuracy */ void sort::reset() { init(how_many, workload_type); } /* * This method performs multiple iterations of the same * test and reports the average. It is used for accuracy. */ void sort::report () { float avg_swaps = 0; clock_t start = clock(); //进行ITERATIONS次试验,然后得到平均值 for (int count=0; count < ITERATIONS; count++) { //一系列方法就不介绍了 reset(); numswaps=0; sortNumbers(); avg_swaps += ((float)numswaps/ITERATIONS); } //结束时间 clock_t elapsed_time = (clock()- start) / (CLK_TCK / 1000); cout << how_many << " items: " << elapsed_time/ITERATIONS << " msec " << (int)(avg_swaps+0.5) << " swaps" << endl; } /* * This method simply prints the list of number in whatever * order they happen to be in */ void sort::printNumbers() { for (int i = 0; i < how_many; i++) cout << numbers[i] << "\t" << "***" << endl; } /* * This method is just here as a convenience to the * derived sorts. Many of the sorts will need to swap * numbers within the list. */ void sort::swapNumbers (int x, int y) { if (x == y) return ; //不相等用临时变量交换,并使交换次数加一 numswaps++; int t = numbers[x]; numbers[x] = numbers[y]; numbers[y] = t; }
下面就是实现类了
选择排序
selectionsort.h
#ifndef SELECTIONSORT_H #define SELECTIONSORT_H #include "sort.h" class selectionsort : public sort { //从基类来的,没什么 protected: void init (int how_many, int workload_type); public: selectionsort(int how_many, int workload_type); void sortNumbers(); }; #endif
selectionsort.cpp
#include "selectionsort.h" /* * You should implement this. It is the meat of the constructor * and is also used by the reset() method. * * It will create the SelectionSort object with an "unsorted" list. * * - how_many is the number of elements in the list. * - workload_type is BEST_CASE, WORST_CASE, or AVG_CASE */ void selectionsort::init (int how_many, int workload_type) { /* * IMPORTANT NOTE: You need to allocate the numbers array declared in * the sort class so that it can hold "how_many" numbers, and you * need to fill numbers (integers) into this array. The ordering * should be determined by the workload. * * Since you may be using the same workload for many different sorts * and configurations of the same sort, you might want to use * helper methods. Helper methods that should be accessible to * all of the sorts should be "protected (not public or private) and * placed in the Sort class. Helper methods used by only this sort * can stay in this file and be made "private". * * This method should NOT sort the array. */ //自己要写的代码,如何生成正的随机数 // seed the random number generator srand(clock()/1000); for (int i = 0; i < how_many; i++) { numbers[i] = rand(); if (numbers[i] < 0) numbers[i] *= -1; //numbers[i] = numbers[i] % how_many; } } /* * This is the constructor. It is nothing more than a shell to * call init(). This allows init() to be used by both the constructor * and also the parent class's reset() method */ selectionsort::selectionsort (int how_many, int workload_type) { this->how_many = how_many; this->workload_type = workload_type; init (how_many, workload_type); } /* * This is the implementation of the selection sort algorithm that * extends the Sort class's abstract sortNumbers() method. */ //选择排序核心算法 void selectionsort::sortNumbers() { for (int look_for=0; look_for<(how_many-1); look_for++) { int small = look_for; for (int candidate=look_for+1; candidate<how_many; candidate++) { if (numbers[candidate] < numbers[small]) small = candidate; } swapNumbers (look_for, small); } }
快速排序
quicksort.h
#ifndef QUICKSORT_H #define QUICKSORT_H #include "sort.h" class quicksort : public sort { //快速排序新增的函数 private: void sortPartition (int left, int right); int findPivot (int left, int right); int partition (int left, int right); //继承重写的 protected: void init (int how_many, int workload_type); public: quicksort(int how_many, int workload_type); void sortNumbers(); }; #endif
quicksort.cpp
#include "quicksort.h" /* * You should implement this. It is the meat of the constructor * and is also used by the reset() method. * * It will create the QuickSort object with an "unsorted" list. * * - how_many is the number of elements in the list. * - workload_type is BEST_CASE, WORST_CASE, or AVG_CASE */ void quicksort::init (int how_many, int workload_type) { /* * IMPORTANT NOTE: You need to allocate the numbers array declared in * the sort class so that it can hold "how_many" numbers, and you * need to fill numbers (integers) into this array. The ordering * should be determined by the workload. * * Since you may be using the same workload for many different sorts * and configurations of the same sort, you might want to use * helper methods. Helper methods that should be accessible to * all of the sorts should be "protected (not public or private) and * placed in the Sort class. Helper methods used by only this sort * can stay in this file and be made "private". * * This method should NOT sort the array. */ srand(clock() / 1000); /* * 自己要补充的代码 * 比选择排序要麻烦一点,因为在main中有两种快速排序,平均和最差 * 所以要加入选择结构 * 平均还是随机数 * 最差就要每个都比,看下面的如果左边小于右边则比较,所以可以直接让数据随i递增 * */ switch (workload_type) { case (BEST_CASE): case (AVG_CASE): for (int i = 0; i < how_many; i++) { numbers[i] = rand(); if (numbers[i] < 0) numbers[i] *= -1; } break; case (WORST_CASE): for (int i = 0; i < how_many; i++) { numbers[i] = i; } break; } } /* * This is the constructor. It is nothing more than a shell to * call init(). This allows init() to be used by both the constructor * and also the parent class's reset() method */ //下面是快速排序的核心算法 quicksort::quicksort (int how_many, int workload_type) { this->how_many = how_many; this->workload_type = workload_type; init (how_many, workload_type); } /* * This is the implementation of the quick sort algorithm that * extends the Sort class's abstract sortNumbers() method. * * It is really a wrapper for the private helper method, sortPartition(), * which does the real "divide and conquer". */ void quicksort::sortNumbers() { sortPartition (0, how_many - 1); } /* * This is a helper method called by sortNumbers(). It sorts * an individual partition about the pivot point. */ int quicksort::partition (int left, int right) { int pivot = numbers[left]; int l = left + 1; int r = right; while (l <= r) { while (l <= right && numbers[l] <= pivot) { l++; } while (r >= left && numbers[r] > pivot) { r--; } if (l < r) { swapNumbers(l, r); l++; r--; } } swapNumbers(left, r); // put pivot in middle return r; } /* * This is a helper method called by sortNumbers(). It recursively * calls itself on subpartitions to sort the numbers. The actual * sorting within the partition is done by sortPartition(), which * is iterative. */ void quicksort::sortPartition (int left, int right) { int placed = partition (left, right); if ((placed - left) > 1) sortPartition (left, placed - 1); if ((right - placed) > 1) sortPartition (placed + 1, right); }
可以看出本题做起来比较容易,但是把代码完全看好还是需要时间的,所以自己体会这两个排序算法吧
如果不太清楚,可以找其他选择和快速排序的例子