【问题标题】:Confusion about my QuickSort algorithm & Mergesort algorithm对我的快速排序算法和合并排序算法感到困惑
【发布时间】:2015-06-25 17:56:53
【问题描述】:

我目前正在进行实证研究,以评估快速排序和归并排序算法的运行时复杂性。为此,我运行了一个随机数生成器,它将我指定的任意数量的数字存储在二进制文件中。这些数字的范围是 1-1,000,000。然后我从 100,000 个数字开始对每个算法进行测试,每次递增 50,000,直到最后一次运行时对 1,000,000 个数字进行排序。所以每个测试 20 次。我已经成功地完成了每个算法,但我的结果有点令人费解。这是显示我的结果的图表。

我知道快速排序的最坏情况是 O(n2) 时间,但通常是 O(n·lg(n)) 时间。合并排序有 Θ(n·lg(n)) 时间。

我还想指出,当我启动计时器时,我只是使用了 time.h 中的 clock(),并计算了经过的时间。在调用排序函数之前,我启动了我的计时器一行代码。

我不明白的是,与快速排序相比,我的图表如何显示合并排序的时间总是加倍,而对数字进行排序的时间却是三倍。

我唯一的想法是,对于我的合并排序算法,每次我将数组分成两半时,我都会使用 malloc 为每一半创建一个新的整数数组。当然,这意味着考虑到我正在排序的数字大小,会对 malloc 进行大量调用。

int* mergeSort(int* nums, int size){

int* left; 
    int* right;
int middle = size/2;

if(size <= 1)
    return nums;

split(nums, size, &left, &right, middle);

//I dont understand why the code below wouldnt work in place of the split()
//when i run it, in main, nothing gets printed out. I guess i lose my pointer to the beginning of my array.
//left = nums;
//right = nums+middle;

left = mergeSort(left, middle);
right = mergeSort(right, size - middle);

merge(nums,left,right,middle,size - middle);
free(left);
free(right);
    return nums;
}

void split(int* nums, int size, int** left, int** right, int middle){

int *lft = (int*) malloc ((sizeof(int) * middle));
int *rght = (int*) malloc ((sizeof(int) * size - middle));
    int mid = middle;
    int upMid = size - middle;
int i;
for(i=0; i < mid; i++)
    lft[i] = nums[i];
for(i=0; i < upMid; i++)
    rght[i] = nums[i+middle];
    *left = lft;
    *right = rght;
}

void merge(int* num, int* left, int* right, int sizeLeft, int sizeRight){

int i,j,k,n;

i=j=k=0;
n=sizeLeft + sizeRight;

while(k < n){
    if(i< sizeLeft){
        if(j<sizeRight){
            insert(num,left,right,&i,&j,&k);
        }
        else{
            append(num, left, sizeLeft, &i, &k);
        }
    }
    else{
        append(num,right,sizeRight,&j,&k);
    }   
  }
}

void insert(int* num, int* left, int* right, int* i, int* j, int* k){

/*int i,j,k,n;*/

if(left[*i]<right[*j]){
    num[*k] = left[*i];
    (*i)++;
}
else{
    num[*k] = right[*j];
    (*j)++;
    }
 (*k)++;
}

void append(int* num, int* half, int sizeHalf, int* i, int* k){

while(*i < sizeHalf){
    num[*k]= half[*i];
    (*i)++; (*k)++;
 }
}

对于我的这个问题的任何反馈,以及关于可能使我的归并排序功能更高效的任何建议,我将不胜感激。谢谢!!

【问题讨论】:

  • 查看有关合并排序的维基百科文章的Variants 部分,以获取有关减少空间量或复制的方法的建议。如果空间不是问题,一种解决方案是预先分配一个与 ORIGINAL 长度相同的 NEW 数组,然后交替合并(并附加)来自 ORIGINAL->NEW 或 NEW->ORIGINAL 的子列表。
  • 啊,谢谢。我想我可能会改变的是,而不是每次都分配新的数组。我将把我的 *left 和 *right 分配给 nums 数组中每个期望值的地址。并且只需处理缩短数组视图的数字即可。希望我能让它正常工作

标签: objective-c time-complexity quicksort mergesort


【解决方案1】:

我已经实现了一个归并排序算法,你可以看看。我在mergeSort 的开头 malloc 一个 bak 数组,之后每次合并都使用它。

#include <string>
#include <stdlib.h>

void _mergeSort(int *array, int *bakArray, int len) ;

void mergeSort(int *array, int len)
{
    int *bak = (int *)malloc(sizeof(int)*len) ;
    _mergeSort(array, bak, len) ;
    free(bak) ;
}

void _mergeSort(int *array, int *bakArray, int len)
{
    if (len >= 2) {
        int leftLen = len/2 ;
        _mergeSort(array, bakArray, leftLen) ;
        _mergeSort(array+leftLen, bakArray, len-leftLen) ;
        int *pa = array ;
        int *pb = array+leftLen ;
        int aIndex = 0 ;
        int bIndex = 0 ;
        while (aIndex < leftLen && bIndex < len-leftLen) {
            int a = pa[aIndex] ;
            int b = pb[bIndex] ;
            if (a < b) {
                bakArray[aIndex+bIndex] = a ;
                ++aIndex ;
            } else if (a == b) {
                bakArray[aIndex+bIndex] = a ;
                bakArray[aIndex+bIndex+1] = a ;
                ++aIndex ;
                ++bIndex ;
            } else {
                bakArray[aIndex+bIndex] = b ;
                ++bIndex ;
            }
        }
        if (aIndex < leftLen) {
            memcpy(bakArray+aIndex+bIndex, pa+aIndex, sizeof(int)*(leftLen-aIndex)) ;
        } else if (bIndex < len-leftLen) {
            memcpy(bakArray+aIndex+bIndex, pb+bIndex, sizeof(int)*(len-leftLen-bIndex)) ;
        }
        memcpy(array, bakArray, sizeof(int)*len) ;
    }
}

static const int MaxArraySize = 100 ;
int main()
{
    srand(time(NULL)) ;
    int array[MaxArraySize] ;
    for (int i = 0 ; i < MaxArraySize; ++i) {
        array[i] = rand() % 10000 ;
    }
    mergeSort(array, MaxArraySize) ;
    for (int i = 0 ; i < MaxArraySize; ++i) {
        printf("%d ", array[i]) ;
    }
    printf("\n") ;
    return 0 ;
}

【讨论】:

  • 谢谢您的回答。我了解您为解决它所做的工作,但我只是觉得我的拆分函数的编写方式缺少一些东西。现在我正在调试它,我的 split 函数现在只是设置 left 指向我的 nums 数组的开头,而 right 指向中间。我不明白这如何不会产生相同的结果。我也不知道如何用代码示例发表评论,所以我编辑我的帖子以显示我认为应该工作的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-14
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多