【问题标题】:Why is my implementation of selectionSort faster than my implementation of bubbleSort?为什么选择排序的实现比冒泡排序的实现快?
【发布时间】:2021-05-13 22:40:25
【问题描述】:

我正在尝试在 c 中实现选择排序算法。我不知道这是否是一个正确的实现,以及为什么我的算法比冒泡排序快得多。因此,我想问您是否可以告诉我是否正确以及我必须做出的任何改进。

main(){
    
    srand(time(NULL));
    system("color b");
    
    int A[NUM],i;
    
    for(i=0;i<NUM;i++){
        A[i] = rand()%30000;
    }
    
    displayArray(A);
    SelectionSort(A);   
    displayArray(A);
        
    system("pause");
}

void displayArray(int * A){
    
    int i;
    for(i=0;i<NUM;i++){
        printf("%6d ", A[i]);
    }
    printf("\n");
}


void SelectionSort(int * A){
    
    int i,j,k, pos; 
    for(i=0;i<NUM;i++){
    
        k = A[i];
        for(j=i+1;j<NUM;j++){
            if(k >= A[j]){
                pos = j;
                k = A[j];
            }
        }
        A[pos] = A[i];
        A[i] = k;
        
    }
    
}

【问题讨论】:

  • 似乎大部分都具有正确的结构,输出是否符合预期?
  • 可能属于codereview
  • displayArray()(和SelectionSort())通常将数组的大小作为参数,而不是使用defined(或全局)值...void displayArray(int *A, size_t n);
  • 回复@mousetail,输出如预期。
  • O(n^2) 是渐近时间复杂度 - 不要认为这意味着两个算法都是 O(n^2) 将在相同的输入上同时运行。

标签: arrays c sorting integer selection-sort


【解决方案1】:

是的,在这种特殊情况下,您的函数是正确的,但总的来说,该函数至少存在三个或多或少的严重缺陷。

第一个是函数依赖于幻数NUM。因此,您不能将该函数与具有不同元素数量的任何数组一起使用。

第二个是你不应该交换具有相等值的数组元素。那是代替这个条件

if(k >= A[j]){

你应该使用以下条件

if(k > A[j]){

第三个是你不能使用该函数对数组进行降序排序或使用其他一些排序标准。

至少你的函数不应该依赖于幻数。

对于整数数组,我将通过以下方式声明和定义函数。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void selection_sort( int a[], size_t n, int cmp( const void *, const void * ) )
{
    for ( size_t i = 0; i < n; i++ )
    {
        size_t pos = i;
        
        for ( size_t j = i + 1; j < n; j++ )
        {
            if ( cmp( a + j, a + pos ) < 0 )
            {
                pos = j;
            }
        }
        
        if ( pos != i )
        {
            int tmp = a[i];
            a[i] = a[pos];
            a[pos] = tmp;
        }
    }
}

int ascending_order( const void *p1, const void *p2 )
{
    int a = *( int * )p1;
    int b = *( int * )p2;
    
    return ( b < a ) - ( a < b );
}

int descending_order( const void *p1, const void *p2 )
{
    int a = *( int * )p1;
    int b = *( int * )p2;
    
    return ( a < b ) - ( b < a );
}

int main(void) 
{
    enum { N = 20 };
    int a[N];
    
    srand( ( unsigned int )time( NULL ) );
    
    for ( size_t i = 0; i < N; i++ )
    {
        a[i] = rand() % N;
    }
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%d ", a[i] );
    }
    putchar( '\n' );
    
    selection_sort( a, N, ascending_order );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%d ", a[i] );
    }
    putchar( '\n' );
    
    selection_sort( a, N, descending_order );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%d ", a[i] );
    }
    putchar( '\n' );
    
    return 0;
}

程序输出可能看起来像

2 10 1 2 14 8 0 17 13 11 5 12 9 3 13 13 3 12 4 1 
0 1 1 2 2 3 3 4 5 8 9 10 11 12 12 13 13 13 14 17 
17 14 13 13 13 12 12 11 10 9 8 5 4 3 3 2 2 1 1 0 

当函数可以应用于类似于标准 C 函数qsort 的任何类型的数组时,可以以更通用的形式编写该函数。但这是一项更复杂的任务。

【讨论】:

    【解决方案2】:

    您应该使用qsort() 的输出检查它。
    用这个循环填充 2 个数组

    int A[NUM], B[NUM], i, n;
    
    for(i=0;i<NUM;i++){
        n = rand()%99999*rand()%99999;
        A[i] = B[i] = n;
    }
    

    然后定义一个比较函数,像这样:

    int cmpfunc (const void * a, const void * b) {
       return ( *(int*)a - *(int*)b );
    }
    

    并用它从标准库中调用qsort()并对B进行排序

    void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
    

    最后一步是比较 A 和 B 以获得大量随机生成的数组。 如果它们相等,则您的实现有效。
    当然,这不是数学证明,但如果您正在研究选择排序,那么您可以进行经验测试

    【讨论】:

      【解决方案3】:

      正如 L.Grozinger 已经commented,具有相同复杂性的两种算法并不意味着它们会同样快。这只是意味着如果你将输入缩放某个因子,两种算法的运行时间都会以相同的比例增加。

      例如,假设您首先对 100 个元素的输入同时运行 bubbleSort 和 selectionSort。例如,您可能会发现 bubbleSort 需要 4 毫秒,而 selectionSort 只需要 3 毫秒。如果您现在将输入缩放两倍,即到 200 个元素,您会发现两种算法的运行时间大约是原来的四倍:bubbleSort 的运行时间从 4 毫秒跳到 16 毫秒,而 selectionSort 的运行时间从 3 毫秒跳到 12 毫秒。

      BubbleSort 实际上比 selectionSort 慢。要了解为什么会出现这种情况,请考虑比较排序算法(bubbleSort 和 selectionSort 都是其中的成员)需要做两种事情:比较和交换。两种算法都需要执行 O(N^2) 比较才能对列表进行排序,这就是为什么两者的总体复杂度都是 O(N^2)。但是 selectionSort 只需要 O(N) 次交换,而 bubbleSort 需要 O(N^2) 次交换。大 O 表示法通常隐藏了这一事实,因为它抽象出有关特定操作的细节。

      quickSort 和 heapSort 也有类似的情况。它们都是 O(n log n),但是 heapSort 比 quickSort 产生更多的缓存未命中。这就是为什么 quickSort 要快得多,咳咳,更快。

      BubbleSort 仅用于教育目的;它在各方面都比 insertSort 和 selectionSort 差。事实上,这就是它用于教育目的的原因。

      【讨论】:

      • 第三段中@Julian 的意思是“都是 comparison sort 的成员”吗?
      • 是的,bubbleSort 和 selectionSort 都是(比较排序算法家族)的成员。
      猜你喜欢
      • 2019-02-26
      • 2011-12-03
      • 2021-11-24
      • 2012-07-23
      • 2018-03-28
      • 2014-12-04
      • 2017-03-11
      • 2017-03-18
      相关资源
      最近更新 更多