[Lenguaje C] Fácil simulación para realizar la función qsort

inserte la descripción de la imagen aquí

Página de inicio personal de Junxi_

Sé diligente y anima los años a no esperar a nadie.

Desarrollo de juegos C/C++


Hola Mina-san, soy Jun Xi_, hoy continuaremos con el contenido de la última actualización y hablaremos sobre cómo podemos simular e implementar nuestra propia función qsort, sin más preámbulos, comencemos el contenido de hoy .

Cómo usar y detalles de la función qsort

  • El contenido de este aspecto se ha presentado en detalle en el blog anterior, y no lo repetiré aquí. Si estás interesado, puedes saltar al siguiente enlace del blog: Llévate a jugar con la función de biblioteca
    qsort

Simular la implementación de la función qsort

Bueno, conocemos la función qsort, entonces, ¿cómo deberíamos simularla?

  • Como dijimos antes, la función qsort es muy similar a la clasificación de burbujas. La diferencia entre las dos es que la función qsort también puede clasificar otros tipos de datos además de clasificar datos plásticos. Con base en esta idea, primero podemos escribir el siguiente código:
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);
            }
        }
    }
}
  • El código anterior es similar a la clasificación de burbujas, creo que esta parte es sobre la que todos tienen dudas
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
    
    
                swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
  • Entonces, ¿qué significa exactamente esta pieza? Vamos a analizarlo paso a paso.
  • 1. En primer lugar, es necesario explicar que,Esta función de intercambio la definimos nosotros mismos y su propósito es intercambiar dos datos byte a byte.

función de intercambio

  • 1.1
    Los tres parámetros que la función necesita pasar son ciertos datos en la matriz, los siguientes datos y el tamaño de los bytes ocupados por este tipo de datos. Por ejemplo, si se pasan datos de tipo int, cuando j=0, los datos que se pasan son el primer elemento, el segundo elemento y el tamaño en bytes ocupado por los datos de tipo int 4
  • 1.2
    El tipo que pasamos desde la base es un dato vacío, es decir, un tipo vacío, por lo que si desea usarlo, debe convertirlo al tipo que desee. El char aquí también puede ser int, double, etc.
  • 1.3
    La razón principal de char* aquí es que el tamaño de un dato char es de un byte, que es el más común. El propósito de nuestra función qsort es ordenar varios datos. Por ejemplo, si hay una estructura que ocupa 20 bytes, pero usas double aquí, y un dato ocupa 8 bytes, entonces, ¿cómo apuntas al siguiente elemento omitiendo bytes? Entonces char es el más adecuado.
  • 1.4
    Queremos resolver el problema de clasificación recorriendo cada elemento de la matriz y comparando el tamaño, pero el tamaño en bytes que ocupa cada tipo de datos es diferente, ¿cómo deberíamos hacerlo?
    En este momento, pensamos, dado que char es el más pequeño y solo ocupa un byte, cuando queremos simular algún tipo de dato +1, solo debemos omitir los datos de tipo char por el tamaño de bytes de los datos simulados correspondientes, ¿no? Y podemos atravesar cada dato a través del ciclo de j, por lo que existe el siguiente código
(char*)base + j * size
(char*)base + (j+1) * size//跳过对于size个字节的数据指向所需排序类型的下一个元素
  • Con la explicación anterior, creo que todos deberían comprender el propósito del intercambio y las razones para establecer varios parámetros. Implementémoslo a continuación:
//交换函数
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++;
    }
}
  • Intercambiar byte a byte Cuando se complete el intercambio, salte al siguiente byte y continúe el intercambio hasta que se intercambien todos los bytes ocupados por este tipo de datos.

  • 2. Después de hablar sobre la función de intercambio anterior, hablemos de las condiciones de juicio anteriores
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

A través de la explicación de los parámetros pasados ​​en el intercambio, este código es muy fácil de entender, esto en realidad es para comparar el tamaño de los datos anteriores y los datos siguientes, que es donde realizamos la clasificación en orden ascendente y descendente, lo hablamos en la función qsort anterior.

void qsort(void* base, //指向了需要排序的数组的第一个元素
          size_t num, //排序的元素个数
          size_t size,//一个元素的大小,单位是字节
           int (*cmp)(const void*, const void*)//函数指针类型 - 这个函数指针指向的函数,能够比较base指向数组中的两个元素
          );
  • Para el desarrollo, solo necesitamos diseñar un programa que pueda ordenar varios tipos de datos. No sabemos qué tipo de datos necesita ordenar el usuario. Por lo tanto, para la función qsort, el último puntero de función pasado debe ser escrito por el propio usuario para decirnos qué tipo de datos necesita ordenar.
  • Y nuestra función cmp aquí es el puntero de función en la definición anterior, y su tipo de retorno es int. ¿Por qué es un int? Vamos a hablar de ello con ejemplos específicos.
  • 到这里,我们的模拟qsort实现基本就完成了,下面来通过例子告诉大家具体使用方法

Simulación del combate real de la función qsort

  • Lógicamente nuestra función qsort funciona, probemos con un ejemplo práctico

1. Los datos enteros se ordenan usando qsort simulado

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;
}
  • resultado
    inserte la descripción de la imagen aquí

  • Cumplió muy bien con nuestro requerimiento.

  • Ahora hablemos específicamente sobre los punteros de función.

iint cmp_int(const void* p1, const void* p2)
{
    
    
    return *(int*)p1 - *(int*)p2;
}
  • 上面qsort定义中是一个函数指针,我们现在这里直接定义一个函数并把该函数的地址传入即可,如上代码
  • Convierte los dos punteros vacíos entrantes al tipo int, resta los datos a los que apuntan los dos punteros al desreferenciarlos y devuelve el resultado., entonces los resultados en este momento no son más que tres situaciones
  • p1>p2, devuelve un número mayor que 0
  • p1=p2, devuelve 0
  • p1<p2, devuelve un número menor que 0
  • Esta función juzga si necesita ser intercambiado por el signo del valor de retorno.
  • Retorna un número mayor que 0, indicando que el elemento anterior es mayor que el último elemento, e intercambia las posiciones de los dos
  • Devuelve un número menor o igual a 0, sin cambios
    注意:这里的p1指向前一个数,而p2指向后一个数,这样通过不断比较交换就可以实现我们的升序排序了
  • Al mismo tiempo, aquí también se explica por qué nuestro puntero de función devuelve un tipo int

  • Entonces, si queremos lograr un orden descendente, ¿solo necesitamos cambiar p1-p2 a p2-p1?

  • Devolver un número mayor que 0, indicando que el último elemento es mayor que el elemento anterior, e intercambiar las posiciones de los dos

  • Devuelve un número menor o igual a 0, sin cambios

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

inserte la descripción de la imagen aquí

  • ningún problema

2. La estructura personalizada se ordena usando qsort

  • Otros tipos de datos son exactamente iguales a los números enteros. Ahora hablemos sobre cómo ordenar datos de estructura a través de qsort

  • Tenga en cuenta que si hay varios tipos de datos en la estructura, dado que simulamos qsort para ordenar los datos en la matriz, los datos que se pasan deben ser del mismo tipo cuando se usa
    .

  • el código se muestra a continuación:

  • La primera introducción es ordenar por edad en la estructura.

//测试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;
}
  • Primero definimos una estructura con dos elementos en ella: nombre y edad
  • Luego definimos una matriz de estructura e inicializamos tres elementos en ella.
struct Stu arr[] = {
    
     {
    
    "zhangsan", 20}, {
    
    "lisi", 50},{
    
    "wangwu", 15} };
  • Después de eso, aún calculamos el tamaño de la matriz y calculamos los bytes ocupados por cada elemento de la matriz calculando el tamaño del primer elemento.
  • Finalmente, podemos ver que está ordenando por el segundo elemento de la estructura, es decir, la edad.
int cmp_stu_by_age(const void* p1, const void* p2)
{
    
    
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}

Aquí comparamos el tamaño convirtiendo p1 y p2 en el tipo de puntero de estructura y apuntando al elemento de edad en la estructura a través del operador "->".
inserte la descripción de la imagen aquí

  • ordenado por tamaño
  • Otros son iguales a los anteriores, esta vez comparamos el tamaño y ordenamos por nombre
  • el código se muestra a continuación:
/测试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;
}

  • El resultado es el siguiente

inserte la descripción de la imagen aquí

  • Aquí presentamos brevemente las reglas para comparar el tamaño de las cadenas.

Reglas de tamaño de comparación de cadenas

  • Para comparar el tamaño de dos cadenas de caracteres, en realidad se compara el tamaño del valor del código ASCLL del carácter en la posición correspondiente. Si el valor ASCLL en la misma posición es el mismo, compare la siguiente posición hasta que haya una diferencia.
  • 比如上面这段代码的比较,在首元素上分别是'l','w','z',其中‘l’ASCLL码值最小,排在首位,'w'ASCLL码值居中,'z'ASCLL码值最大,排在最后,这就是出现上面结果的原因。

Resumir

  • Este es el final del contenido de hoy. En él, presentamos la implementación de la función qsort simulada. También puede usarla usted mismo. ¡Solo al hacerlo usted mismo puede realmente comprenderla y aprenderla!

  • Bueno, si tiene alguna pregunta, por favor pregúnteme en el área de comentarios o mensaje privado, ¡hasta la próxima!

No es fácil crear un nuevo blogger. Si cree que el contenido del artículo es útil para usted, puede hacer clic en este nuevo blogger antes de irse. ¡Tu apoyo es mi motivación para actualizar! ! !

**(¡Ke Li te pide que apoyes al bloguero tres veces seguidas! Haz clic en el comentario a continuación para darle me gusta y recolectar para ayudar a Ke Li)**

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/syf666250/article/details/131718473
Recomendado
Clasificación