c使用qsort函数_使用C库的qsort函数

c使用qsort函数

There are many sorting algorithms, often with several variations, but the C library’s built-in qsort (Quicksort) function is the best option for sorting arrays in most situations.

排序算法很多,通常会有几种变化,但是C库的内置qsort (Quicksort)函数是在大多数情况下对数组进行排序的最佳选择。

However, there is more to using qsort than just throwing an array at a function: you need to provide your own comparator function, the implementation of which can be slightly fiddly if you are sorting anything other than primitive data types. In this article I’ll start off with a simple int-sorting example, and then go on to sort an array of structs, firstly by an int and then by a string.

但是,使用qsort不仅仅是向函数抛出数组:您还需要提供自己的比较器函数,如果您对除原始数据类型以外的任何其他东西进行排序,则其实现可能会有些麻烦。 在本文中,我将从一个简单的int排序示例开始,然后继续对一个结构数组进行排序,首先是一个int,然后是一个字符串。

If you are interested in how Quicksort works take a look at the Wikipedia article Quicksort here, but for the purposes of this project we’ll just treat the qsort function as a “black box”.

如果您对Quicksort的工作方式感兴趣,请在此处查看Wikipedia文章Quicksort ,但是出于本项目的目的,我们仅将qsort函数视为“黑匣子”。

编码 (Coding)

This is a short and simple project so I’ll just keep all the code in one source file. Create a file called qsort.c somewhere convenient, and then type or paste the following. You can clone/download the Github repository if you prefer.

这是一个简短的项目,因此我将所有代码保存在一个源文件中。 在方便的位置创建一个名为qsort.c的文件,然后键入或粘贴以下内容。 如果愿意,可以克隆/下载Github存储库

This is the first part of the source code.

这是源代码的第一部分。

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


// --------------------------------------------------------
// STRUCT author
// --------------------------------------------------------
typedef struct author
{
    int id;
    char name[64];
} author;


//--------------------------------------------------------
// FUNCTION PROTOTYPES
//--------------------------------------------------------
int compare_ints(const void* a, const void* b);
int compare_author_id(const void* a, const void* b);
int compare_author_name(const void* a, const void* b);


void output_ints(int* data, int size);
void output_authors(author* authors, int size);


void sort_integers();
void sort_authors();


//--------------------------------------------------------
// FUNCTION main
//--------------------------------------------------------
void main(void)
{
    puts("-----------------");
    puts("| codedrome.com |");
    puts("| qsort         |");
    puts("-----------------\n");


    sort_integers();


    //sort_authors();
}

One of the #includes is stdlib.h, needed for the qsort function. We’ll use the author struct in an array which we’ll sort by both id and name. The first three functions prototyped here are the comparator functions needed by the qsort function. The next two functions simply output arrays of ints and authors. The last two functions are called by main, and will create, sort and output arrays of ints and authors respectively.

#includesqsort函数所需的stdlib.h 。 我们将在数组中使用author struct ,并按idname排序。 此处原型化的前三个函数是qsort函数所需的比较器函数。 接下来的两个函数只是输出ints和作者数组。 最后两个函数由main调用,并将分别创建,排序和输出intsauthors数组。

排序整数 (Sorting Integers)

As you can see sort_authors is commented out in main, as to start with we will just implement sort_integers and its associated functions. Enter/paste the code for the three functions needed to sort integers into qsort.c.

如您所见,在main sort_authors注释掉,首先,我们将实现sort_integers及其相关功能。 输入/粘贴将整数排序到qsort.c所需的三个函数的代码。

//--------------------------------------------------------
// FUNCTION sort_integers
//--------------------------------------------------------
void sort_integers()
{
    int data[16];
    srand(time(NULL));


    for(int i = 0; i < 16; i++)
    {
        data[i] = (rand() % 128);
    }


    puts("Unsorted");
    output_ints(data, 16);


    qsort(data, 16, sizeof(int), compare_ints);


    puts("Sorted");
    output_ints(data, 16);
}


//--------------------------------------------------------
// FUNCTION output_ints
//--------------------------------------------------------
void output_ints(int* data, int size)
{
    for(int i = 0; i < size; i++)
    {
        printf("%d\n", data[i]);
    }
}


//--------------------------------------------------------
// FUNCTION compare_ints
//--------------------------------------------------------
int compare_ints(const void* a, const void* b)
{
    if(*(int*)a < *(int*)b)
        return -1;
    else if(*(int*)a > *(int*)b)
        return 1;
    else
        return 0;
}

The sort_integers function creates an array of ints, populates it with random data, and outputs the data. (There is of course the possibility that the random numbers will already be in order. Sometimes writing software can be scary!)

sort_integers函数创建一个int数组,用随机数据填充它,然后输出数据。 (当然,随机数可能已经整理好了。有时候编写软件可能会很吓人!)

Then we get down to business by calling qsort. This function takes four arguments:

然后,我们通过致电qsort开始业务。 该函数有四个参数:

  • The array to be sorted

    要排序的数组
  • The number of items in the array

    数组中的项目数
  • The size of each item

    每个项目的大小
  • A pointer to a comparator function taking two void pointer arguments, and returning an int

    指向比较器函数的指针,该函数接受两个void指针参数,并返回一个int

After calling qsort we simply output the data again in its sorted form.

调用qsort我们只需再次以排序形式输出数据即可。

I won’t insult your intelligence by explaining how output_ints works, so let’s move straight on to disentangling compare_ints. As I mentioned above it takes two void pointers, one to each of the values which need comparing. This makes qsort general-purpose in that it can sort anything by delegating the actual comparisons to custom functions. It does mean, however, that we have to do something with the pointers to get to the actual values we want to compare, exactly what we need to do with those pointers depends of course on what they are pointing to. The function then returns < 0 if the first argument is “less than” the second (using whatever logic is appropriate for your purposes), > 0 if the first is “more than” the second, and 0 if they are the same. The convention is to return -1, 1 or 0. (If for some reason you need to sort your data in descending order, just swap the return values.)

我不会通过解释output_ints工作方式来侮辱您的智慧,因此让我们继续output_ints compare_ints 。 如上所述,它需要两个void指针,每个需要比较的值都指向一个。 这使qsort具有通用性,因为它可以通过将实际比较委托给自定义函数来对任何东西进行排序。 但是,这的确意味着我们必须对指针进行一些操作才能获得要比较的实际值,确切地说,我们对这些指针需要执行的操作当然取决于它们所指向的对象。 然后,如果第一个参数“小于”第二个参数(使用适合您的目的的任何逻辑),则函数返回<0;如果第一个参数“大于”第二个参数,则返回0;如果它们相同,则返回0。 约定是返回-1、1或0。(如果由于某种原因需要按降序对数据进行排序,只需交换返回值即可。)

The core bits of the entire function are in the form

整个功能的核心位采用以下形式

*(int*)a

*(int*)a

which when you look at separately don’t look so bad. In this particular case the pointer points to an int, so firstly we cast the void* to int*, and then dereference that pointer to give the actual value. These are then compared, and the appropriate value returned.

当您单独查看时,它看起来并不差。 在这种特殊情况下,指针指向一个int ,因此我们首先将void*强制转换为int* ,然后取消对该指针的引用以给出实际值。 然后将它们进行比较,并返回适当的值。

Compile the program with the following command in Terminal:

在终端中使用以下命令编译程序:

gcc qsort.c -std=c11 -o qsort

gcc qsort.c -std=c11 -o qsort

and then run it with

然后用

./qsort

./qsort

You should see something like this.

您应该会看到类似这样的内容。

Image for post

That’s about as simple as qsort gets, but now we will go on to sort something slightly more complicated, an array of structs. The principle is exactly the same, the big difference is that extracting the values we want to actually compare from the pointers is more involved.

这与qsort一样简单,但是现在我们将继续对一些稍微复杂的东西进行排序,即结构数组。 原理是完全一样的,最大的不同是从指针中提取我们要实际比较的值的过程更多。

排序结构 (Sorting Structs)

Enter or paste the following into qsort.c, comment out sort_integers in main, and uncomment sort_authors.

输入或粘贴以下为qsort.c,出评论sort_integersmain取消注释,并sort_authors

//--------------------------------------------------------
// FUNCTION sort_authors
//--------------------------------------------------------
void sort_authors()
{
    author authors[6];


    authors[0] = (author){.id = 7, .name = "Dickens, Charles"};
    authors[1] = (author){.id = 3, .name = "Stevenson, Robert Louis"};
    authors[2] = (author){.id = 9, .name = "Bronte, Emily"};
    authors[3] = (author){.id = 4, .name = "Gaskell, Elizabeth"};
    authors[4] = (author){.id = 1, .name = "Collins, Wilkie"};
    authors[5] = (author){.id = 8, .name = "Shelley, Mary"};


    puts("Unsorted");
    output_authors(authors, 6);


    qsort(authors, 6, sizeof(author), compare_author_id);
    puts("Sorted by id");
    output_authors(authors, 6);


    qsort(authors, 6, sizeof(author), compare_author_name);
    puts("Sorted by name");
    output_authors(authors, 6);
}


//--------------------------------------------------------
// FUNCTION output_authors
//--------------------------------------------------------
void output_authors(author* authors, int size)
{
    for(int i = 0; i < size; i++)
    {
        printf("id: %d name: %s\n", authors[i].id, authors[i].name);
    }
}


//--------------------------------------------------------
// FUNCTION compare_author_id
//--------------------------------------------------------
int compare_author_id(const void* a, const void* b)
{
    if(((author*)a)->id < ((author*)b)->id)
        return -1;
    else if(((author*)a)->id > ((author*)b)->id)
        return 1;
    else
        return 0;
}


//--------------------------------------------------------
// FUNCTION compare_author_name
//--------------------------------------------------------
int compare_author_name(const void* a, const void* b)
{
    return strcmp(((author*)a)->name, ((author*)b)->name);
}

I’ll gloss over the sort_authors and output_authors functions as they are essentially the same as the integer equivalents, except that we create, sort and output an array of authors rather than integers. Note though that we sort the array twice, firstly by id and secondly by name. The important functions here are compare_author_id and compare_author_name.

我将介绍sort_authorsoutput_authors函数,因为它们与等效的整数基本相同,除了我们创建,排序和输出一个authors数组而不是整数。 请注意,尽管我们对数组进行了两次排序,首先按id排序,其次按name排序。 这里的重要功能是compare_author_idcompare_author_name

Let’s look at compare_author_id first, and specifically getting at the ids from the pointers. The bits of code that do this are in the form:

首先让我们看一下compare_author_id ,特别是从指针中获取ID。 执行此操作的代码位的形式为:

((author*)a)->id

((author*)a)->id

Note that we need to cast the void pointer to an author pointer, the whole wrapped in brackets. If we did:

请注意,我们需要将void指针转换为author指针,整个指针都放在方括号中。 如果我们这样做:

(author*)a->id

(author*)a->id

we would be attempting to obtain the id property of a and then casting that to an author pointer, which of course is completely wrong and indeed meaningless. If we tried it the compiler would humiliate us with a suitable error message.

我们将试图获得id的财产a ,然后流延到一个author的指针,这当然是完全错误的,事实上毫无意义。 如果我们尝试这样做,编译器将以适当的错误消息来羞辱我们。

Now let’s move on to compare_author_name which works slightly differently as we are now comparing strings. The C library has a built-in string comparison function strcmp (in string.h) which we will use, but we still need to get at the name properties to pass to strcmp. This is done in the same way as with id:

现在让我们转移到compare_author_name稍微不同的工作,因为我们现在比较字符串。 C库有一个内置的字符串比较函数strcmp (在string.h中 ),我们将使用它,但是我们仍然需要获取name属性以传递给strcmp 。 这与使用id方式相同:

((author*)a)->name

((author*)a)->name

The strcmp function returns the same < 0, 0, > 0 values that qsort expects so we can just return its return value as-is.

strcmp函数返回qsort期望的相同的<0、0,> 0值,因此我们可以按原样返回其返回值。

Build and run the program again and you should get:

再次生成并运行程序,您将获得:

Image for post

Of course you can create an array of anything, building up data structures of any complexity. It is therefore impossible to give examples of all possible comparator functions to be passed to qsort, but I hope this article is a good start.

当然,您可以创建任何东西的数组,建立任何复杂性的数据结构。 因此,不可能给出所有可能的比较器函数传递给qsort示例,但我希望本文是一个好的开始。

翻译自: https://medium.com/programming-in-c/using-the-c-librarys-qsort-function-94380598ff2b

c使用qsort函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值