在C中快速排序-指针和内存

时间:2019-06-23 14:01:34

标签: c algorithm quicksort partitioning swap

我是计算机科学专业的新生,在使用指针时仍然遇到一些困难。我正在尝试用C实现一个快速排序程序。我目前有2个错误,但我不知道如何解决它。

  1. 在主函数上,当我调用分区时,得到了不兼容的指针类型

  2. 在交换功能上:线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x200000007)

v1.2.3

3 个答案:

答案 0 :(得分:1)

对于初学者,如果数组具有N个元素,则索引的有效范围为[0, N-1]

因此,尝试访问阵列之外的内存

int pivot = size;
int i = - 1;
for(int j = 0 ; j < size - 1 ; j++){
    if(array[j] < array[pivot])
                       ^^^^^^^

您的函数交换没有意义。

    void swap(int *i, int* j){
    *i = *j;
    *j = *i;
    *i = *j;
}

在第一个表达式语句之后

    *i = *j;

指针ij所指向的两个对象都将具有相同的值。

可以通过以下方式定义函数。

void swap( int *p, int *q )
{
    int tmp = *p;
    *p = *q;
    *q = tmp;
} 

并称呼为

swap( &array[i], &array[j] );

功能分区也无效。除了错误使用的算法外,至少它的第一个参数也被错误地声明。

代替

void partition( int* array[], int size );

函数应声明为

void partition( int *array, int size );

或更正确地

void partition( int *array, size_t size );

,该函数应类似于

int array[] = {7,2,1,8,6,3,5,4};
size_t size = sizeof(array)/sizeof(array[0]);
partition( array,size );

另一方面,函数partition应该返回将数组分为两部分的位置。所以最终的函数声明看起来像

size_t partition( int array[], size_t size );

下面有一个演示程序,显示了如何使用函数swappartition编写递归函数快速排序。

#include <stdio.h>

void swap( int *p, int *q )
{
    int tmp = *p;
    *p = *q;
    *q = tmp;
}

size_t partition( int a[], size_t n, int pivot )
{
    size_t i = 0;

    while ( i != n )
    {
        while ( i != n && a[i] < pivot ) i++;
        while ( i != n && !( a[--n] < pivot ) );

        if ( i != n ) swap( a + i, a + n );
    }

    return i;
}

void quick_sort( int a[], size_t n )
{
    if ( n != 0 )
    {
        size_t pos = partition( a, n - 1, a[n - 1] );
        swap( a + pos, a + n - 1 );

        quick_sort( a, pos );
        quick_sort( a + pos + 1, n - pos - 1 );
    }
}

int main(void) 
{
    int a[] = { 7, 2, 1, 8, 6, 3, 5, 4 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%d ", a[i] );
    }

    putchar( '\n' );

    quick_sort( a, N );

    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%d ", a[i] );
    }

    putchar( '\n' );

    return 0;
}

程序输出为

7 2 1 8 6 3 5 4 
1 2 3 4 5 6 7 8 

答案 1 :(得分:0)

这里有一些问题:

  1. 指针表示法具有一种奇怪的效果,即恒星位于它指向的事物之后,因此分区中的int* array[]是一个指向整数的指针数组,而您在main中使用的指针是指向整数数组。
  2. array []实际上本身就是一个指针(尽管有一些细微的技术差异,但是通常接受指针的东西也将接受数组)。您主要将分区中的数组用作整数数组(array[j] < array[pivot]应该是内容的比较,而int* array[]是地址的比较),因此您应该将其更改为是int array[]。请注意,这也将有助于解决第1点,因为在调用partition时只需要删除多余的引用即可。
  3. 在对数组建立索引时,它会算作取消引用,因此,在调用swap(array[i],array[j])(假设您已进行上述建议的更正)时,您传递的是int,而不是int* ,则需要将其更改为swap(&array[i],&array[j])
  4. 在交换中,您将两个值都设置为j。发生这种情况的原因是,当您在i上写内容时,该信息已被破坏。有几种处理方法,其中两种主要方法是将信息保存在一个临时变量中,第二种方法是通过位黑客攻击。这里有两个例子:
void swap(int *i, int* j){
    int temp = *j;
    *j = *i;
    *i = temp;
}

使用排他性或的版本

void swap(int *i, int* j){
    *i= *j ^ *i;
    *j= *j ^ *i;
    *i= *j ^ *i;
}

答案 2 :(得分:0)

  

指针

我不确定问题是否在问基于指针的快速排序,所以这是一个使用Lomuto分区方案的示例。在分区循环中,它在较小的部分上递归,然后在较大的部分上循环,将堆栈空间限制为O(log(n)),但最坏的情况下时间复杂度仍为O(n ^ 2)。

void QuickSort(int *lo, int *hi)
{
int *pi;
int *pj;
int pv;
int t;
    while (lo < hi){
        pv = *hi;                       /* pivot */
        pi = lo;                        /* partition */
        for (pj = lo; pj < hi; ++pj){
            if (*pj < pv){
                t = *pi;                /*  swap *pi, *pj */
                *pi = *pj;
                *pj = t;
                ++pi;
            }
        }
        t = *pi;                        /* swap *pi, *hi */
        *pi = *hi;                      /*  to place pivot */
        *hi = t;
        if(pi - lo <= hi - pi){         /* recurse on smaller part */
            QuickSort(lo, pi-1);        /*  loop on larger part */
            lo = pi+1;
        } else {
            QuickSort(pi+1, hi);
            hi = pi-1;
        }
    }
}