采纳答案成功!
向帮助你的同学说点啥吧!感谢那些助人为乐的人

快速排序和归并排序(优化版)用的都是老师您的代码哦= =
基本上测试结果:
归并排序都是0.2左右
快速排序都是0.9左右
处理的数据规模是1000000
差距就这么大!加上随机化试试看。简单的一步,效率就比归并快了。随机化那一步是快速排序的精髓。不然快排无法保证递归深度是logn这个级别。关于快排的时间复杂度分析,由于这步随机化,所以准确的分析非常难,需要的数学知识太多了,我在课程中没有讲。你可以简单地理解:没有随机化,整个快排的递归树将严重有偏;而归并排序的递归树,则一定保持着深度是logn这个级别的。这也是我在回答中说:每次随机选取pivot,在真正的快排实现中“必须“加入。我强调“必须“的原因。
另外,这种“有偏“是测试用例相关的。如果递归树恰好不那么偏,快排就会表现的比较快。但要明白这种快是一种“侥幸”。不管怎样,随机化是快排中标准的步骤,让快排在统计意义上一跃成为最快的排序算法。必须加入。
我这边也是这样的问题,归并排序效率比快速排序效率高(见下图, 100w的随机数据):

需要说明的是,我的代码中没有用标准库中的swap函数,因为效率更低,而是自己写了一个简单的交换函数
template<typename T>
void _swap(T &a, T &b) {
int tmp = a;
a = b;
b = tmp;
}// Quicksort, following Bentley and McIlroy,
// ``Engineering a Sort Function,'' SP&E November 1993.
上面这篇论文给出了cpu运算的执行时间,如下图

从图中可以看出,标准库里面的swap函数效率很低,是赋值50多倍,而即使是自己写的交换函数,效率也是比较低的。
归并排序中没有用到交换,而快排中主要操作就是交换,会不会是这个原因导致效率下降的呢?
就是这样的!赞研究精神。 不过自己写swap,会丧失编译器优化的性能。如果是使用VS做的实验,试试看在release模式下测试算法的性能?具体见这个问题: http://coding.imooc.com/learn/questiondetail/3603.html
如果使用VS做算法性能测试,请确保是在release模式下运行哦。具体可以看这个问题:http://coding.imooc.com/learn/questiondetail/3603.html
如果使用VS做算法性能测试,请确保是在release模式下运行哦。具体可以看这个问题:http://coding.imooc.com/learn/questiondetail/3603.html
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<time.h>
#include"SortTestHelper.h"
#define True 1
template<typename T>
void insertionSort(T arr[], int l, int r) {
for (int i = l + 1; i <= r; i++) {
T e = arr[i];
int j;
for (j = i; j > l && arr[j - 1] > e; j--)
arr[j] = arr[j - 1];
arr[j] = e;
}
return;
}
//===================================================================
template<typename T>
void __merge(T arr[], int l, int mid, int r) {
T *aux=new T[r-l+1];
for (int i = l; i <= r; i++)
aux[i - l] = arr[i];
int i = l, j = mid + 1;
for (int k = l; k <= r; k++) {
if (i > mid) { arr[k] = aux[j - l]; j++; }
else if (j > r) { arr[k] = aux[i - l]; i++; }
else if (aux[i - l] < aux[j - l]) { arr[k] = aux[i - l]; i++; }
else { arr[k] = aux[j - l]; j++; }
}
delete[] aux;
}
template<typename T>
void __mergeSort(T arr[], int l, int r) {
if (r - l <= 15) {
insertionSort(arr, l, r);
return;
}
int mid = (l + r) / 2;
__mergeSort(arr, l, mid);
__mergeSort(arr, mid + 1, r);
if (arr[mid] > arr[mid + 1])
__merge(arr, l, mid, r);
}
template<typename T>
void mergeSort(T arr[], int n) {
__mergeSort(arr, 0, n - 1);
}
//=======================================================================
//是对arr[l...r]进行partition操作
//返回p,使得arr[l...p-1]<arr[p];arr[p+1]>arr[p]
template<typename T>
int __partition(T arr[], int l, int r)
{
swap(arr[l], arr[rand() % (r - l + 1) + l]);
T v = arr[l];
int j = l;
for (int i = l + 1; i <= r; i++)
if (v > arr[i])
swap(arr[++j], arr[i]);
swap(arr[j], arr[l]);
return j;
}
//对arr[l...r]部分进行快速排序
template<typename T>
void __quicksort(T arr[], int l, int r)
{
//if (l >= r)
// return;
if (r - l <16)
{
insertionSort(arr, l, r);
return;
}
int p = __partition(arr, l, r);
__quicksort(arr, l, p - 1);
__quicksort(arr, p + 1, r);
return;
}
//快速排序!
template<typename T>
void quick_sort(T arr[], int n)
{
srand((int)time(NULL));
__quicksort(arr, 0, n - 1);
}
//=============================================================
//是对arr[l...r]进行partition操作
//返回p,使得arr[l...p-1]<arr[p];arr[p+1]>arr[p]
template<typename T>
int __partition2(T arr[], int l, int r)
{
swap(arr[l], arr[rand() % (r - l + 1) + l]);
T v = arr[l];
//arr[l+1...i)部分小于v,arr(j...r]部分大于v
int i = l + 1, j = r;
while (True)
{
while (i <= r&&arr[i] < v)
i++;
while (j >= l + 1 && arr[j] > v)
j--;
if (i > j)
break;
swap(arr[i], arr[j]);
i++;
j--;
}
swap(arr[l], arr[j]);
return j;
}
//对arr[l...r]部分进行快速排序
template<typename T>
void __quicksort2(T arr[], int l, int r)
{
//if (l >= r)
// return;
if (r - l <16)
{
insertionSort(arr, l, r);
return;
}
int p = __partition2(arr, l, r);
__quicksort2(arr, l, p - 1);
__quicksort2(arr, p + 1, r);
return;
}
//快速排序!
template<typename T>
void quick_sort2(T arr[], int n)
{
srand((int)time(NULL));
__quicksort2(arr, 0, n - 1);
}
//测试快速排序和归并排序的运行速度
int main()
{
//int time = 0,avm=0,avq=0,avq2=0;
int *arr1, *arr2, *arr3;
int n = 1000000;
//while (time < 1000000)
//{
arr1 = SortTestHelper::generateRandomArray(n, 0, n);
arr2 = SortTestHelper::copyIntArray(arr1, n);
arr3 = SortTestHelper::copyIntArray(arr1, n);
/*Guibing_BU_sort(arr1, n);
quick_sort(arr2, n);*/
//快排若没有随机化则会退化到o(n**2)级的算法
SortTestHelper::testSort("merge sort", mergeSort, arr1, n);
SortTestHelper::testSort("quick sort", quick_sort, arr2, n);
SortTestHelper::testSort("quick sort2", quick_sort2, arr3, n);
delete[] arr1;
delete[] arr2;
delete[] arr3;
/*}*/
putchar('\n');
int swaptime = 100;
arr1 = SortTestHelper::generateNearlyOrderedArray(n, swaptime);
arr2 = SortTestHelper::copyIntArray(arr1, n);
arr3 = SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("merge sort", mergeSort, arr1, n);
SortTestHelper::testSort("quick sort", quick_sort, arr2, n);
SortTestHelper::testSort("quick sort2", quick_sort2, arr3, n);
delete[] arr1;
delete[] arr2;
delete[] arr3;
putchar('\n');
n = 1000000;
arr1 = SortTestHelper::generateRandomArray(n, 0, 10);
//arr2 = SortTestHelper::copyIntArray(arr1, n);
arr3 = SortTestHelper::copyIntArray(arr1, n);
/*Guibing_BU_sort(arr1, n);
quick_sort(arr2, n);*/
//快排若没有随机化则会退化到o(n**2)级的算法
SortTestHelper::testSort("merge sort", mergeSort, arr1, n);
//SortTestHelper::testSort("quick sort", quick_sort, arr2, n);
SortTestHelper::testSort("quick sort2", quick_sort2, arr3, n);
delete[] arr1;
//delete[] arr2;
delete[] arr3;
putchar('\n');
putchar('\n');
system("pause");
}
插入,归并,用的都是您的代码!
难道是我电脑有问题?
我有我舍友的电脑测试了下,运行结果甚至比我的更差!
我在mac下实验你的这段代码,结果如下。目测vs实现的编译器有坑。。。 我在windows下试试看。。。 merge sort : 0.427345 s quick sort : 0.302787 s quick sort2 : 0.300788 s merge sort : 0.122907 s quick sort : 0.205381 s quick sort2 : 0.119227 s merge sort : 0.258978 s quick sort2 : 0.148382 s
我在vs下试验了一下,也是这种问题,然后搞明白了。因为你是在debug模式下运行的程序,vs在debug模式下做了很多其他事情,主要集中在std中。快排使用了std::swap,我发现就是这个函数拖慢了速度。你测试一下,会发现自己写一个swap都比调用std::swap快。。。 但是如果你在release模式下运行程序,就不会有这些问题了!试试看!你的代码没有问题:) 赞!欢迎使用多语言实现这些算法!一定会有很大收获的:)
如果使用VS做算法性能测试,请确保是在release模式下运行哦。具体可以看这个问题:http://coding.imooc.com/learn/questiondetail/3603.html
老师我加上随机化了,但还是,改变不大

下面是源代码
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<time.h>
#include"SortTestHelper.h"
#include"Sort_collection.h"
using namespace std;
//是对arr[l...r]进行partition操作
//返回p,使得arr[l...p-1]<arr[p];arr[p+1]>arr[p]
template<typename T>
int __partition(T arr[], int l, int r)
{
swap(arr[l] , arr[rand() % (r - l + 1) + l]);
T v = arr[l];
int j = l;
for (int i = l + 1; i <= r; i++)
if (v > arr[i])
swap(arr[++j], arr[i]);
swap(arr[j], arr[l]);
return j;
}
//对arr[l...r]部分进行快速排序
template<typename T>
void __quicksort(T arr[], int l, int r)
{
//if (l >= r)
// return;
if (r - l <16)
{
charu_guibing_sort(arr, l, r);
return;
}
int p = __partition(arr, l, r);
__quicksort(arr, l, p - 1);
__quicksort(arr, p + 1, r);
return;
}
//快速排序!
template<typename T>
void quick_sort(T arr[],int n)
{
srand((int)time(NULL));
__quicksort(arr, 0, n - 1);
}
//测试快速排序和归并排序的运行速度
int main()
{
char c;
do {
int n = 1000000;
int *arr1 = SortTestHelper::generateRandomArray(n, 0, n);
int *arr2 = SortTestHelper::copyIntArray(arr1,n);
/*Guibing_BU_sort(arr1, n);
quick_sort(arr2, n);*/
//快排若没有随机化则会退化到o(n**2)级的算法
SortTestHelper::testSort("merge sort", Guibing_sort, arr1, n);
SortTestHelper::testSort("quick sort", quick_sort, arr2, n);
delete[] arr1;
delete[] arr2;
int swaptime = 100;
arr1 = SortTestHelper::generateNearlyOrderedArray(n, swaptime);
arr2 = SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("merge sort", Guibing_sort, arr1, n);
SortTestHelper::testSort("quick sort", quick_sort, arr2, n);
delete[] arr1;
delete[] arr2;
} while ((c = getchar()) == '\n');
system("pause");
}我试了一下你的代码。其中的插入排序和归并排序用的我的代码,没有问题。检查一下你的charu_guibing_sort(arr, l, r)实现是否有问题? 你的这个程序和我的课程中这一小节的程序做的事情是一样的。运行一下我的代码,看看是不是也是这个结果? https://github.com/liuyubobobo/Play-with-Algorithms/tree/master/03-Sorting-Advance/06-Quick-Sort-Deal-With-Nearly-Ordered-Array
抱歉,我刚看到这个问题后来我就一直没有回复了。使用VS的同学,在做算法性能测试的时候,请一定使用Release模式运行程序!不然,VS会在Debug模式下的标准库中做一些其他事情,另外运行器也使用的是未优化的版本,从而拖慢算法的执行速度,使得算法性能的比较不准确。可以尝试测试一下,在VS Debug模式下,std::swap的速度非常慢,甚至比自己写的swap还要慢。而我们在归并排序中,没有使用std::swap,所以在debug模式下就会比快排还要快了。具体见这个问题: http://coding.imooc.com/learn/questiondetail/3603.html
登录后可查看更多问答,登录/注册