快速排序:打印内存地址而不是数组元素:

时间:2019-09-06 19:03:43

标签: c algorithm sorting segmentation-fault quicksort

我已经编写了用于对整数数组进行快速排序的代码,但是在打印时,它在终端上显示了某种内存地址。我一直想弄清楚很长时间,但没有成功。

我试图在在线gdb编译器上编译它,但出现错误:Segmentation Fault(核心已转储),否则,我试图将代码修改数千次

#include<stdio.h>
void swap(int* a, int* b){
    int t = *a;
    *a = *b;
    *b = t;
}
int part(int arr[], int l, int r){    //for partioning the array
    int i=l, j=0;

    while(j<r){
            if(arr[j]<arr[r]){
                swap(&arr[j], &arr[i]);
                i++;
            }
        j++;
    }
    swap(&arr[i], &arr[r]);
return i;
}
void qsort(int arr[], int l, int r){    //recursive function for quicksort
    if(l<r){
        int p = part(arr, l, r);
        qsort(arr, l, p-1);
        qsort(arr, p+1, r);
    }
}
int main(void){
    int arr[] = {4, 10, 17, 5, 5, 6, 1 , 3, 0};

    qsort(arr, 0, 8);                 //function called

    for(int i=0; i<9; i++){            
        printf("%d ", arr[i]);       //for printing the array
    }
return 0;
}

实际结果:
11016472 1974520423 11016472 6356864 6 6356800 4214784 11015616 1974521024

我期望对数组进行排序。

4 个答案:

答案 0 :(得分:1)

部分地,当l大于0时,j中的part从0开始在处理中包含l的“左”数组的一部分,并且可能会导致i(已初始化为l)增加了太多次,超过了r

int i=l, j=0;更改为int i=l, j=l;会导致程序为问题案例打印所需的输出。

通过修改qsortpart以在每次调用它们时打印其参数,并在它们返回时进行打印或以当前递归深度缩进先前的打印,可以发现此问题。 (可以使用静态计数器对其进行跟踪(出于调试目的))。这会立即显示在数组之外将qsort设置为9的对r的调用,然后导致检查这种情况。

答案 1 :(得分:1)

在输入j时,您需要将l设置为0,而不是part

...
int part(int arr[], int l, int r){    //for partioning the array
    int i=l, j=l;

    while(j<r){ // line 10
...

如果不这样做,那么当r大于8时,您将超出数组的边界(可能会写)。

答案 2 :(得分:1)

您的分区已损坏。它似乎是基于两种算法的,它们都没有正确实现。

int part(int arr[], int l, int r){    //for partitioning the array

这告诉我们我们有一些数组,我们想在lr之间划分范围。尚不清楚该目标是否是这些索引中的 ,但这并不重要,因为无论如何后续代码都会被破坏。

int i=l, j=0; // HERE. Why is j 0 ??

此后,您多次访问arr[j],并且都进行了读取和写入。如果您要分区的范围在[l..r]中,则不能保证j(从零开始)在该范围内。从j开始l

但是有更好的方法。

首先,这是C。在part中,标识arr不是数组;这是一个指针。让我们假设我们有一个序列,其中l总是从零开始,而r只是长度。在这种情况下,l参数将毫无意义,而我们的part函数可以像这样开始:

int part(int arr[], int len)

足够公平。现在,我们可以实现一个简单的分区,该分区选择一个枢轴,并基于该枢轴进行分区,并返回枢轴结束位置的索引。我不会涉及选择“良好”枢轴的相关主题。有几种方法,我鼓励您进行调查。为了简单起见,在此示例中,我们将使用最右边的元素:

int part(int arr[], int len)
{
    if (len <= 1)
        return 0;

    int pvt = 0;
    for (int i=0; i<len; ++i)
    {
        if (arr[i] < arr[len-1]) 
            swap(arr+i, arr + pvt++);
    }
    swap(arr+pvt, arr+len-1);

    return pvt;
}

足够简单。现在,这如何帮助实际的快速排序?在对序列进行分区时,通过使用偏移地址作为前导参数可以提供帮助。这也有帮助,因为现在我们可以像执行q_sort一样进行part的操作,即摆脱参数之一,而只使用基地址和长度:

void q_sort(int arr[], int len)
{
    if (len <= 1)
        return;

    int p = part(arr, len);
    q_sort(arr, p);
    q_sort(arr+p+1, len-p-1);
}

就是这样。请注意,第二个递归调用使用指针算法将目标序列的基地址定位在枢轴位置的前一位置。长度会相应调整。

完整的程序出现在下面,包括一个测试工具,该工具生成30个元素的序列,然后对结果进行排序并显示:

代码

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

void swap(int* a, int* b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

int part(int arr[], int len)
{
    if (len <= 1)
        return 0;

    int pvt = 0;
    for (int i=0; i<len; ++i)
    {
        if (arr[i] < arr[len-1])
            swap(arr+i, arr + pvt++);
    }
    swap(arr+pvt, arr+len-1);

    return pvt;
}

void q_sort(int arr[], int len)
{
    if (len <= 1)
        return;

    int p = part(arr, len);
    q_sort(arr, p);
    q_sort(arr+p+1, len-p-1);
}

#define N_ELEMS     30

int main(void)
{
    int arr[N_ELEMS];

    srand((unsigned int)time(NULL));
    for (int i=0; i<N_ELEMS; ++i)
    {
        arr[i] = 1 + (rand() % 99);
        printf("%d ", arr[i]);
    }
    fputc('\n', stdout);


    q_sort(arr, N_ELEMS);

    for (int i=0; i<N_ELEMS; ++i)
    {
        printf("%d ", arr[i]);
    }
    fputc('\n', stdout);

    return 0;
}

输出(很明显是可变的)

21 95 18 10 57 60 60 6 37 72 44 99 91 25 14 5 50 58 16 18 81 5 52 42 15 40 58 16 76 61 
5 5 6 10 14 15 16 16 18 18 21 25 37 40 42 44 50 52 57 58 58 60 60 61 72 76 81 91 95 99 

这里的好处有两个。首先,不要求初始调用者提供序列的两端。其次,这些功能实际上更简单

希望有帮助。

答案 3 :(得分:-3)

因为没有值小于arr [8],所以第一次调用part()'i'将永远不会递增。该函数将返回“ i”,它为0。然后,您调用qsort(arr,l,p-1(-1))。此时,您将与arr [-1]交换。由于不正确的索引,大多数arr数组的值将与堆栈中的随机数据交换。这就是为什么您得到奇怪的值。

int part(int arr[], int l, int r){    //for partioning the array
int i=l, j=0;

while(j<r){
        if(arr[j]<arr[r]){
            swap(&arr[j], &arr[i]);
            i++;
        }
    j++;
}
swap(&arr[i], &arr[r]);
return i;
}