【问题标题】:swapping last element problem in sorting C array交换排序C数组中的最后一个元素问题
【发布时间】:2021-03-26 09:55:58
【问题描述】:

我正在尝试使用查找数组中最小元素地址的函数编写排序算法:

#include <stdio.h>


int * findMin(int * start,int * end) ///function to return the adress of the smallest array element
{
    int *min = start;
    int x;
    int size = (end - start);
    
    for(x=0; x<size; x++)
    {
    
        if (*(start+x)<*min)
            min = (start+x);
        
    }
    
    return min;
}

但是在我的排序算法中,由于最后一个元素没有什么可比较的,因此错误地保持原样

void sort(int * start, int  * end)  ///funtion to sort the array in ascending order
{
    int x,temp;
    int size = (end - start);
    
    for (x = 0; x <size; x++) 
    { 
        if ( *(start+x) > *findMin(start,end))
        {
            temp = *findMin(start+x,end);
            *findMin(start+x,end) = *(start+x);
            *(start+x) = temp;
        }
    }
}


int main()
{

    int arr[10]={5,11,3,12,17,25,1,9,14,2};
    
    sort(arr,&arr[9]);
    
    for(int i=0;i<10;i++)
        printf("%d ",arr[i]);
    printf("\n");
    
    
}

我该如何纠正这个问题?

【问题讨论】:

  • 在 C 中,无论您使用索引 (i &lt; n) 还是指针 (p &lt; end),通常都使用包含下限和互斥上限来描述范围。在这两种情况下,上限和下限之间的差异都会为您提供范围的大小。你的函数是这样工作的,但你在main 中的调用没有。通过&amp;arr[10]arr + 10 作为上限。
  • 这种排序算法的运行时复杂度真的很糟糕。这只是你为了好玩而尝试的东西吗?请注意,对于 10 个元素的数组,您的 findMin 函数被调用 27 次,findMin 内的循环迭代 171 次。有几个现有的排序例程会执行得非常好,尤其是对于较大的数组。
  • 这是一个学校作业,排序算法是讲师决定的,所以我们不能真正使用另一个。在任何情况下,该程序都不应该为任何其他数组输入运行多次,但感谢您提供的信息。

标签: arrays c sorting pointers selection-sort


【解决方案1】:

此声明中的表达式

int size = (end - start);

没有给出数组的确切大小。至少你应该写

int size = end - start + 1;

但是,传递指向数组最后一个元素的指针而不是指向数组最后一个元素之后的内存的指针并不是一个好主意。在这种情况下,您可以指定一个空范围,因为 start 等于 end。

此外,如果函数接受两个指针,则无需在循环中引入用作索引的中间变量。

还有这段代码sn-p

        temp = *findMin(start+x,end);
        *findMin(start+x,end) = *(start+x);
        *(start+x) = temp;

效率很低。

这是一个演示程序,展示了如何实现这些功能。

#include <stdio.h>

int * findMin( const int * start, const int * end ) ///function to return the adress of the smallest array element
{
    const int *min = start;

    if ( start != end )
    {
        while ( ++start != end )
        {
            if ( *start < *min ) min = start;
        }
    }
    
    return ( int * )min;
}

void selection_sort( int *start, int  *end )  ///funtion to sort the array in ascending order
{
    for ( ; start != end; ++start )
    {
        int *min = findMin( start, end );

        if ( min != start )
        {
            int tmp = *start;
            *start = *min;
            *min = tmp;
        }
    }
}

int main(void) 
{
    int arr[] = { 5, 11, 3, 12, 17, 25, 1, 9, 14, 2 };
    const size_t N = sizeof( arr ) / sizeof( *arr );
    
    for ( const int *p = arr; p != arr + N; ++p )
    {
        printf( "%d ", *p );
    }

    putchar( '\n' );
    
    selection_sort( arr, arr + N );
    
    for ( const int *p = arr; p != arr + N; ++p )
    {
        printf( "%d ", *p );
    }

    putchar( '\n' );

    return 0;
}

程序输出是

5 11 3 12 17 25 1 9 14 2 
1 2 3 5 9 11 12 14 17 25 

【讨论】:

    【解决方案2】:

    但是在我的排序算法中,由于最后一个元素没有什么可比较的,因此错误地保持原样

    不,这充其量只是一种误导性的描述。您的findMin() 没有专门将数组元素与其直接后继进行比较,因此*end 没有后继这一事实无关紧要。问题(部分)只是你有一个错误,导致永远不会将*end*min 进行比较。如果您更直接地依赖指针算术和比较,则该错误将更难犯且更容易识别:

    int *findMin(int *start, int *end) {
        int *min = start;
    
        // The original code is equivalent to this variant:
        // for (int *x = start; x < end; x++) {
        
        // but this is what you need for an inclusive upper bound:
        // for (int *x = start; x <= end; x++) {
    
        // or, since initially min == start, this would be even better:
        for (int *x = start + 1; x <= end; x++) {
            if (*x < *min) {
                min = x;
            }
        }
        
        return min;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2020-10-13
      • 1970-01-01
      • 2020-12-03
      • 2023-03-16
      • 2011-04-07
      相关资源
      最近更新 更多