[C language] Easy simulation to realize qsort function

insert image description here

Junxi_'s personal homepage

Be diligent and encourage the years to wait for no one

C/C++ game development


Hello, Mina-san, this is Jun Xi_, today we will continue with the content of the last update, and talk about how we can simulate and implement our own qsort function. Without further ado, let's start today's content.

How to use and details of qsort function

Simulate the implementation of qsort function

Well, we know the qsort function, so how should we simulate it?

  • As we said before, the qsort function is very similar to the bubble sort. The difference between the two is that the qsort function can also sort other types of data in addition to sorting plastic data. Based on this idea, we can first write the following code:
void bubble_sort(void* base, int num, int size, int (*cmp)(const void*, const void*))
{
    
    
    int i = 0;
    for (i = 0;i < num - 1; i++)
    {
    
    
        int j = 0;
        for (j = 0; j < num - 1 - i; j++)
        {
    
    
            if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
    
    
                swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }
}
  • The above code is similar to bubble sorting, I think this part is what everyone has doubts about
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
    
    
                swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
  • So what exactly does this piece mean? Let's analyze it step by step.
  • 1. First of all, it needs to be explained that,This swap function is defined by ourselves, and its purpose is to exchange two data byte by byte.

swap function

  • 1.1
    The three parameters that the function needs to pass in are a certain data in the array, the next data, and the size of bytes occupied by this type of data. For example, if an int type data is passed in, when j=0, the data passed in are the first element, the second element, and the byte size occupied by the int type data 4
  • 1.2
    The type we pass in from the base is a void data, that is, an empty type, so if you want to use it, you have to cast it to the type you want. The char here can also be int, double, etc.
  • 1.3
    The main reason for char* here is that the size of a char data is one byte, which is the most common. The purpose of our qsort function is to sort various data. For example, if there is a structure that occupies 20 bytes, but you use double here, and one data occupies 8 bytes, then how do you point to the next element by skipping bytes? So char is the most suitable
  • 1.4
    We want to realize the sorting problem by traversing each element in the array and comparing the size, but the byte size occupied by each data type is different, how should we do it?
    At this time, we thought, since char is the smallest and only occupies one byte, when we want to simulate some kind of data +1, we only need to skip the char type data by the size bytes of the corresponding simulated data, right? And we can traverse each data through the cycle of j, so there is the following code
(char*)base + j * size
(char*)base + (j+1) * size//跳过对于size个字节的数据指向所需排序类型的下一个元素
  • With the above explanation, I think everyone should understand the purpose of swap and the reasons for setting various parameters. Let’s implement it below:
//交换函数
void swap(char* p1, char* p2, int size)
{
    
    
    int i = 0;
    char* tmp = 0;
    for (i = 0; i < size; i++)
    {
    
    
        tmp = *p1;//由于不是交换地址而是交换存放的内容因此需要解引用
        *p1 = *p2;
        *p2 = tmp;
        p1++;
        p2++;
    }
}
  • Exchange byte by byte. When the exchange is completed, skip to the next byte and continue the exchange until all the bytes occupied by this type of data are exchanged.

  • 2. After talking about the above swap function, let's talk about the above judgment conditions
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

Through the explanation of the incoming parameters in swap, this code is very easy to understand. In fact, this is to compare the size of the previous data and the next data, which is where we realize the sorting in ascending and descending order. We talked about it in the previous qsort function

void qsort(void* base, //指向了需要排序的数组的第一个元素
          size_t num, //排序的元素个数
          size_t size,//一个元素的大小,单位是字节
           int (*cmp)(const void*, const void*)//函数指针类型 - 这个函数指针指向的函数,能够比较base指向数组中的两个元素
          );
  • For development, we only need to design a program that can sort various types of data. We don’t know what kind of data the user needs to sort. Therefore, for the qsort function, the last function pointer passed in needs to be written by the user himself to tell us what kind of data it needs to sort.
  • And our cmp function here is the function pointer in the above definition, and its return type is int. Why is it an int? Let's talk about it with specific examples.
  • 到这里,我们的模拟qsort实现基本就完成了,下面来通过例子告诉大家具体使用方法

Simulation of qsort function actual combat

  • Logically, our qsort function works, let's try it with a practical example

1. Integer data is sorted using simulated qsort

int cmp_int(const void* p1, const void* p2)
{
    
    
    return *(int*)p1 - *(int*)p2;
}
void test1()
{
    
    
    int arr[] = {
    
     10,2,4,5,6,8,9,1,0,7 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    bubble_sort(arr, sz, sizeof(int), cmp_int);
    for (i = 0; i < sz; i++)
    {
    
    
        printf("%d ", arr[i]);
    }
}
int main()
{
    
    
    test1();
    return 0;
}
  • result
    insert image description here

  • It fulfilled our requirement very well

  • Let's now talk specifically about function pointers

iint cmp_int(const void* p1, const void* p2)
{
    
    
    return *(int*)p1 - *(int*)p2;
}
  • 上面qsort定义中是一个函数指针,我们现在这里直接定义一个函数并把该函数的地址传入即可,如上代码
  • It casts the incoming two void pointers to int type, subtracts the data pointed to by the two pointers by dereferencing and returns the result, then the results at this time are nothing more than three situations
  • p1>p2, return a number greater than 0
  • p1=p2, return 0
  • p1<p2, return a number less than 0
  • This function judges whether it needs to be exchanged by the sign of the return value.
  • Return a number greater than 0, indicating that the previous element is greater than the latter element, and exchange the positions of the two
  • Returns a number less than or equal to 0, unchanged
    注意:这里的p1指向前一个数,而p2指向后一个数,这样通过不断比较交换就可以实现我们的升序排序了
  • At the same time, here also explains why our function pointer returns an int type

  • So if we want to achieve descending order, do we just need to change p1-p2 to p2-p1?

  • Return a number greater than 0, indicating that the latter element is greater than the previous element, and exchange the positions of the two

  • Returns a number less than or equal to 0, unchanged

int cmp_int(const void* p1, const void* p2)
{
    
    
    return *(int*)p2 - *(int*)p1;
}

insert image description here

  • no problem

2. The custom structure is sorted using qsort

  • Other data types are exactly the same as integers. Now let’s talk about how to sort structure data through qsort

  • Note that if there are multiple types of data in the structure, since we simulate qsort to sort the data in the array, the data passed in must be of the same type when using
    .

  • code show as below:

  • The first introduction is to sort by the age in the structure

//测试qsort排序结构体数据
struct Stu
{
    
    
    char name[20];
    int age;
};

int cmp_stu_by_age(const void* p1, const void* p2)
{
    
    
    return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}

void test2()
{
    
    
    struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
    for (i = 0; i < sz; i++)
    {
    
    
        printf("%s %d ", arr[i].name, arr[i].age);
    }
}
int main()
{
    
    
    test2();
    return 0;
}
  • We first define a structure with two elements in it: name and age
  • Then we defined a structure array and initialized three elements into it
struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
  • After that, we still calculate the size of the array, and calculate the bytes occupied by each element in the array by calculating the size of the first element
  • Finally, we can see that it is sorting by the second element in the structure, that is, the age
int cmp_stu_by_age(const void* p1, const void* p2)
{
    
    
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}

Here we compare the size by converting p1 and p2 into the structure pointer type and pointing to the age element in the structure through the "->" operator
insert image description here

  • sort by size
  • Others are the same as above, this time we compare the size and sort by name
  • code show as below:
/测试qsort排序结构体数据
struct Stu
{
    
    
    char name[20];
    int age;
};


int cmp_stu_by_name(const void* p1, const void* p2)
{
    
    
    return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}

void test3()
{
    
    
    struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
    for (i = 0; i < sz; i++)
    {
    
    
        printf("%s %d ", arr[i].name, arr[i].age);
    }
}
int main()
{
    
    
    test3();
    return 0;
}

  • The result is as follows

insert image description here

  • Here we briefly introduce the rules for comparing the size of strings

String Comparison Size Rules

  • For comparing the size of two character strings, it is actually comparing the size of the ASCLL code value of the character at the corresponding position. If the ASCLL value at the same position is the same, compare the next position until there is a difference.
  • 比如上面这段代码的比较,在首元素上分别是'l','w','z',其中‘l’ASCLL码值最小,排在首位,'w'ASCLL码值居中,'z'ASCLL码值最大,排在最后,这就是出现上面结果的原因。

Summarize

  • This is the end of today's content. In it, we introduced the implementation of the simulated qsort function. You might as well use it yourself. Only by doing it yourself can you truly understand and learn it!

  • Well, if you have any questions, please ask me in the comment area or private message, see you next time!

It is not easy for a new blogger to create. If you feel that the content of the article is helpful to you, you may wish to click on this new blogger before leaving. Your support is my motivation to update! ! !

**(Ke Li asks you to support the blogger three times in a row!!! Click the comment below to like and collect to help Ke Li)**

insert image description here

Guess you like

Origin blog.csdn.net/syf666250/article/details/131718473