【问题标题】:Quicksort error on CC上的快速排序错误
【发布时间】:2017-04-17 17:24:51
【问题描述】:

您好,我编写了以下程序来输入一个数字数组并对其进行排序。

但对于 1.3333331 等数字,我仍然得到错误的答案!

什么问题?!

#include <stdio.h>

void quicksort( double array[], long long left, long long right);

long long partition( double array[], long long left, long long right);

int fDig( double x);

int main( void) {
    long long quantity = 0LL, counter = 0LL;
    int dig = 0;
    scanf("%lli", &quantity);

    double beard[quantity];

    for( counter = 0LL; counter < quantity; counter++) {
        scanf("%lf", &beard[counter]);
    }

    quicksort( beard, 0LL, quantity - 1LL);

    for( counter = 0LL; counter < quantity; counter++) {
        dig = fDig( beard[counter]);
        printf("%.*lf", dig, beard[counter]);
        if( counter == quantity - 1LL) {
            break;
        }

        printf(" ");
    }

    return 0;
}

int fDig( double x) {
    int result = 0;
    while( x !=  floor(x)) {
        x *= 10;
        result++;
    }

    return result;
} 

/* Quick sort recursive function */ 

void quicksort( double array[], long long left, long long right){
    if ( left < right) {
        long long middle = partition( array, left, right);
        quicksort( array, left, middle - 1LL);
        quicksort( array, middle + 1LL, right);
    }
}

/* Partition :
   Modifies the array :
   SMALLER , PIVOT , GREATER
   Returns the index for pivot because pivot is placed in the final position
*/

long long partition( double array[], long long left, long long right) {
    long long middle;

    double x = array[left];
    long long l = left;
    long long r = right;

    while( l < r) {
        while( ( array[l] <= x) && ( l < right)) {
            l++;
        }

        while( ( array[r] > x) && ( r >= left)) {
            r--;
        }

        if( l < r) {    
            double temp = array[l];
            array[l] = array[r];
            array[r] = temp;
        }
    }

    middle = r;

    double temp = array[left];
    array[left] = array[middle] ;
    array[middle] = temp;

    return middle ;
}

鉴于数组元素是最多 8 位小数的浮点数,我正在尝试对数组进行排序! (我使用了正确的算法吗?)

【问题讨论】:

  • 有什么问题? (即输入和输出是什么)
  • 是错误的排序,还是fDig 和输出格式?尝试硬编码实际输入的最大位数,然后看看会发生什么。
  • 1.3333331等数字的错误答案这个需要详细解释一下。
  • 使用long long - 9223372036854775807 似乎有点不寻常?另外,您是否需要/想要编写自己的排序?因为 C 有 qsort 如果这不是必需的。
  • 为了让我们理解问题,您需要向我们提供您的输入、预期输出和实际输出。否则任何答案都只是猜测。

标签: c arrays algorithm sorting quicksort


【解决方案1】:

这是来自 Kernighan & Ritchie 的“The C Programming Language”,第 87 页的 qsort。

他们的代码最初是int v[] 我将其更改为double v[],因为您的数据是实数。 我不会将long long 用于索引变量,long int 将是一个 64 位数字,允许最大索引值为 9,223,372,036,854,775,807。如果你有一个双精度数组,其中一个双精度占用 8 个字节,你将需要超过 6700 万兆兆字节的内存。

void swap ( double v[], long int i, long int j )
{
   double temp;

   temp = v[i];
   v[i] = v[j];
   v[j] = temp;
}


void qsort ( double v[], long int left, long int right )
{
   long int i;
   long int last;

   if ( left >= right )
      return;  /* do nothing if array contains fewer than 2 elements */

   swap( v, left, (left+right)/2 );  /* move partition element */
   last = left;
   for ( i = left + 1; i <= right; i++ )
   {
      if ( v[i] < v[left] )
         swap( v, ++last, i );
   }
   swap( v, left, last );
   qsort( v, left, last - 1 );
   qsort( v, last + 1, right );
}

【讨论】:

    【解决方案2】:

    你遇到的错误,其实可能不是错误,而是对浮点类型的误解。这是非常不准确的,尤其是对于十进制的浮点文字,因为它们实际上是以二进制形式存储的。以下代码(使用您的fDig)可能暗示了这种不准确性:

    #include <stdio.h>
    #include <math.h>
    
    int fDig(double x) {
        int result = 0;
        while (x !=  floor(x)) {
            x *= 10;
            result++;
        }
    
        return result;
    } 
    
    int main() {
        double x = 0.3333331;
    
        int dig = fDig(x);
        printf("%.7f\n", x);
        printf("%.*f\n", dig, x);
        printf("%.20f\n", x);
    
        return 0;
    }
    

    以上代码在我的gcc(MinGW GCC 4.8.1)中的-std=c99的输出如下:

    0.3333331
    0.33333309999999999
    0.33333309999999999329
    

    我无法重现文字 1.3333331 的错误。

    简而言之,只需仔细检查可疑的浮点值即可。

    【讨论】:

    • 所以我的 fDig 工作不正常,它应该返回浮点类型变量的小数位数,但显然不是!我该如何解决?
    • @Ben FM 无法使用双精度类型来完成。如果原始数据可访问,则字符串类型(char [],尽管首选 std::string)是更好的选择。此外,可以根据需要使用 stdlib 中声明的 atof 将字符串转换为 double。
    猜你喜欢
    • 1970-01-01
    • 2018-11-06
    • 2021-10-01
    • 1970-01-01
    • 2021-09-17
    • 2013-08-09
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多