实验4:递归与分治策略的应用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
课程实验报告
结
果
运行到一定规模:
快速排序:
运行到一定规模:堆排序:
运行到一定规模:
矩阵乘法:
1朴素算法:
2Strassen矩阵乘算法一定规模后:
总
结
横坐标计算规模:1:8129 2:65536 3:131072 4:262144 5:1048576
随着输入规模的增大,通过三种算法的时间记录做成折线图观察不难发现,在初期,三种算法所用时间几乎相等,随着输入规模的不断增大,堆排序和快速排序仍然能够保持相对较小的增长,而并归排序所用时间复杂度开始大幅度增加。
快速排序果然是快,数据越大优势越明显,并且实现上也较为简单。理论上它的平均时间和归并排序,堆排序都是一样的(在最坏情况还还不如它们),都是O(nlog2n),但实际运行来看比它们两者的速度都快一倍以上。COOL!
合并排序需要额外相同规模的数组,空间复杂度为O(n)。从具体实现来看,这只是一种理论上的优秀算法,想法比较简单直接,但实现上比quicksort 复杂,运行时间也差,在数据很大的时候运行时间是heapsort的两倍,更不用说quicksort
了。
堆排序利用了二分树的结构,将时间复杂度降到O(nlog2n),理论上和实现上表现都不错,并且发现在数据量是10 000 000时,甚至优于快排,可能是运行时数据的问题。
对于strassen 算法对其时间复杂度分析:T(n)=7T(n/2)+O(n);而朴素算法的时间复杂度为n的三次方。
随着数据增大,也出现乘方级别的时间复杂度差距。
附录//头文件
#include
#include
#include
#include
#include
#define PARENT(i) (i/2) //几个较简单函数
#define LEFT(i) (2*i+1)
#define RIGHT(i) (2*i+2)
using namespace std;
//定义所需要变量等
#define MAX 100000
int a[MAX]; //数组存储原始顺序
int temp[MAX]; //临时数组存储临时排序值
int num; //计算统计逆序对数
int N = 2; //数据规模
clock_t begintimes, endtimes; //clock_t为clock()函数返回的变量类型double duration; //运行时间计算
int heapsize; //堆长度
//随机生成数函数
int number(){
int a;
a = rand() % 10000 + 1; //随机生成1到一万之间的整数
return a;
}
//初始化函数对数组a[]初始化。
void init(){
memset(temp,0, MAX * sizeof(int)); //临时数组清零
for (int i = 0; i < N; i++){ //新数组赋值
a[i] = number();
}
return;
}
//单次并归挑选
void Merge(int left, int mid, int right) //需要三个参数,将原来数组分割
{
int i = left, j = mid + 1, n = 0, length = right - left;//i开始为左半部分最左边,j为右半部分最左边
while (i <= mid && j <= right){ //未超限进行循环填数
if (a[i]>a[j]){ //左边比右边大
temp[n++] = a[j++];
num += mid - i + 1; //从i到mid都比a[j]大
}
else{
temp[n++] = a[i++];
}
}
if (i>mid){ //左边全部填满了,填右边
while (j <= right){
temp[n++] = a[j++];
}
}
else{ //右边填满,填左边
while (i <= mid){
temp[n++] = a[i++];
}
}
for (int k = 0; k <= length; k++){ //最后临时数组赋值到原数组
a[left + k] = temp[k];
}
//递归进行并归排序
void MergeSort(int left, int right)
{
if (left int mid = (left + right) / 2; MergeSort(left, mid); MergeSort(mid + 1, right); Merge(left, mid, right); } } //快速排序一次 int Partition(int left, int right) { int i = left - 1; for (int j = left; j <= right - 1; j++){ if (a[j] < a[right]){ //把right作为轴 i++; //这个i坐标左边的值是比a[right]小的 swap(a[i], a[j]); //交换 } } swap(a[i + 1], a[right]); //最后把i+1和right交换,这样轴就是i+1了必须是保证i+1上当初就是作为标杆的a[right]啊。 return i + 1; } //递归进行快排整体 void QuickSort(int left, int right){ if (left int q = Partition(left, right); QuickSort(left, q - 1); QuickSort(q + 1, right); } } //堆排序,函数太多,新建一个命名空间 namespace MySort{ template void Max_Heapify(T*arr, int i, size_t heapSize){ //从元素A[i]、A[LEFT(i)]、A[RIGHT(i)]中找出最大的,并将其下标保存在Largest中 //size_t heapSize = sizeof(arr) / sizeof(*(arr)); 也就是数量n