简体   繁体   中英

Quick sort in C — pointers and memory

I am a computer science freshman and I still have some difficulties when it comes to pointers. I am trying to implement a quick sort program in CI currently have 2 errors but I am not able to figure out how to fix it.

  1. On the main function, when I am calling partition, I got an Incompatible pointer types

  2. On the swap function: Thread 1: EXC_BAD_ACCESS (code=1, address=0x200000007)

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


void partition(int* array[], int size){
    int pivot = size;
    int i = - 1;
    for(int j = 0 ; j < size - 1 ; j++){
        if(array[j] < array[pivot]){
            i++;
            swap(array[i],array[j]);
        }
    }
}

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

For starters if an array has N elements then the valid range of indices is [0, N-1]

Thus there is an attempt to access memory beyond the array

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

Your function swap does not make sense.

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

After the first expression statement

    *i = *j;

the both objects pointed to by the pointers i and j will have the same value.

The function can be defined the following way.

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

and called like

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

The function partition is also invalid. Apart from the incorrect used algorithm at least its first parameter is declared also incorrectly.

Instead of

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

the function should be declared like

void partition( int *array, int size );

or more correctly like

void partition( int *array, size_t size );

and the function should be called like

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

On the other hand, the function partition should return the position that divides the array into two parts. So the final function declaration will look like

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

Below there is a demonstrative program that shows how a recursive function quick sort can be written using functions swap and partition .

#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;
}

The program output is

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

There are a few problems in here:

  1. The pointer notation has the weird effect that the star comes after the thing it points to, so the int* array[] in partition is an array of pointers to integers, while what you call it with in main is a pointer to an array of integers.
  2. An array[] is actually a pointer by itself (though with some slightl technical differences, but in general something that accepts a pointer will also accept an array). You are mainly using the array in partition as an array of integers (the array[j] < array[pivot] should be a comparison of content, but with an int* array[] it is a comparison of address), so you should change it to just being an int array[] . Note that this will also help with resolving point 1, as you just need to remove the superflous referencing when you call partition.
  3. When you index an array it counts as a dereferencing, so when you call swap(array[i],array[j]) (assuming you have made the corrections suggested above) you are passing int s and not int* s, you need to change it to swap(&array[i],&array[j]) .
  4. In swap you are setting both of their values to j's. This happens because the information of what is in i is destroyed when you write over it. There are several ways to handle this, the 2 main ones are saving the information in a temporary variable, and the second is through bit-hacking. Here are 2 examples:
void swap(int *i, int* j){
    int temp = *j;
    *j = *i;
    *i = temp;
}

An a version using exlusive or:

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

pointers

I wasn't sure if the question was asking about a pointer based quicksort, so here is an example, using Lomuto partition scheme. In the partition loop, it recurses on the smaller part, and loops back for the larger part, limiting stack space to O(log(n)), but worst case time complexity remains at 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;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM