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

C 快速排序:打印内存地址而不是数组元素:,c,algorithm,sorting,segmentation-fault,quicksort,C,Algorithm,Sorting,Segmentation Fault,Quicksort,我已经编写了用于快速排序整数数组的代码,但在打印时,它会在终端上显示某种内存地址。我一直在想办法,但没有成功 我试着在在线gdb编译器上编译它,它给出了一个错误:分段错误(内核转储),否则,我试着修改代码好几次 #包括 无效交换(int*a,int*b){ int t=*a; *a=*b; *b=t; } int part(int arr[],int l,int r){//用于对数组进行分区 int i=l,j=0; 而(j第一次调用part()“i”永远不会递增,因为没有值小于arr[8]。

我已经编写了用于快速排序整数数组的代码,但在打印时,它会在终端上显示某种内存地址。我一直在想办法,但没有成功

我试着在在线gdb编译器上编译它,它给出了一个错误:分段错误(内核转储),否则,我试着修改代码好几次

#包括
无效交换(int*a,int*b){
int t=*a;
*a=*b;
*b=t;
}
int part(int arr[],int l,int r){//用于对数组进行分区
int i=l,j=0;

而(j第一次调用part()“i”永远不会递增,因为没有值小于arr[8]。该函数将返回“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;
}
int-part(int-arr[],int-l,int-r){//用于对数组进行分区
int i=l,j=0;

而(j部分,当
l
大于0时,在
part
中从0开始的
j
包括处理中
l
左侧的数组部分,可能导致
i
(初始化为
l
)增加太多次,超过
r

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


通过修改
qsort
part
可以发现此问题,以便在每次调用它们时打印它们的参数,并在它们返回时打印,或者按照当前递归深度缩进以前的打印(为了调试目的,可以使用静态计数器跟踪)。这会立即显示对
qsort
的调用,将
r
设置为9,超出数组,然后检查它是如何形成的。

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

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

    while(j<r){ // line 10
...
。。。
int part(int arr[],int l,int r){//用于对数组进行分区
int i=l,j=l;

而(j您的分区被破坏了。它似乎松散地基于两种算法,但两种算法都没有正确实现

int part(int arr[], int l, int r){    //for partitioning the array
这告诉我们我们有一些数组,我们想要在
l
r
之间划分范围。不清楚这个目标是否包含这些索引,但这并不重要,因为后续代码无论如何都会被破坏

int i=l, j=0; // HERE. Why is j 0 ??
稍后,您将多次访问
arr[j]
,包括读和写。如果正在分区的范围在[l..r]中,则无法保证从零开始的
j
在该范围内。从
l
开始的
j
是合适的

但是有更好的办法

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

int part(int arr[], int len)
很公平。现在我们可以实现一个简单的分区,它选择一个轴,基于该轴进行分区,并返回轴结束位置的索引。我将不讨论选择“好”的相关主题pivot。有几种方法,我鼓励您调查自己。为了简单起见,我们将在本例中使用最右边的元素pivot:

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;
}
就是这样。注意,第二个递归调用使用指针算法将目标序列的基址定位在超过枢轴位置的位置。相应地调整长度

完整程序如下所示,包括生成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;
}
这里的好处有两个。第一,不需要初始调用方提供序列的两端。第二,函数实际上更简单


希望有帮助。

qsort
是一个标准库函数的名称,而C标准没有定义自己定义它的行为。请重命名它,然后重试。当我在我的计算机上运行此操作时,它会输出
10 17 6 5 3 0 4 5 1
。排序不太好,但它仍然是数组的原始值。@Eric Posypicschil没有里德,仍然不工作。@是的,我也有几次得到了原始值。@BusyBee:C 2018 7.1.3说标准库的标识符是保留的,7.1.4说定义它们而不是明确允许的行为没有被标准定义:“如果程序在保留标识符的上下文中声明或定义标识符(7.1.4允许的除外),或将保留标识符定义为宏名称,则行为未定义。”您是否更改了代码?看起来您刚刚发布了op的错误代码。
qsort
的主体被包装在
If中(尽管这不是严格意义上的快速排序,是吗?它不符合常规(OP的代码带有
j
as
l
)惯例。(这是一个合法的问题,不是修辞性的)它是快速排序。划分机制通常是两种形式中的一种。这是一种,在教授分治和快速排序的总体技术时经常使用,因为它很容易理解。
#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