指针(五)后半

发布于:2025-09-14 ⋅ 阅读:(24) ⋅ 点赞:(0)

1、 qsort 函数

1.1、qsort 函数排列结构体

在这里,我们创建结构体类型的数组,用于 qsort 函数的传参。

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

struct Stu//创建结构体变量
{
	char name[30];
	int age;
};

struct Stu arr[] = { { "zhangsan", 18 }, { "lisi", 20 }, { "wangwu", 38 } };

void Print(struct Stu* p, int sz)//打印函数
{
	for (int i = 0; i < sz; i++)
	{
		printf("%s: %d\n", p->name, p->age);
		p++;
	}
}

cmp_str_by_age(const void* p1, const void* p2)//排年龄函数
{
	return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);
}

test1()//按年龄大小
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_str_by_age);
	Print(arr, sz);
}

cmp_str_by_name(const void* p1, const void* p2)//排姓名函数
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}

test2()//按姓名
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_str_by_name);
	Print(arr, sz);
}

int main()
{
	test1();
	printf("-------------------------\n");
	test2();

	return 0;
}

这里讲两点:

1、结构成员访问操作符: ->

使用方法为:结构体指针 -> 成员变量。上面代码中, ((struct Stu*)p1)->age 也可以换为 *(struct Stu*)p1.age 。

2、 strcmp 函数

使用方法为,向函数中传入两个字符串类型的数据,比较对应位置字符的 ASCII 码值的大小。以顺序为例,若前一个字符串对应位置字符的 ASCII 码值应大于后一个,返回大于0的值;相等返回0,小于返回小于0的值。

1.2、 qsort 函数的模拟实现

既然要实现 qsort 函数,那么向其中传入的参数,也应该是:首元素地址、元素个数、元素大小、比较函数。

#include<stdio.h>

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

void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
    
}

void test1()
{
    int arr[] = { 4,5,2,7,9,12,34,101 };
    int count = sizeof(arr) / sizeof(arr[0]);
    Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
}

int main()
{
    test1();//实现整型值的排序

    return 0;
}

将这个函数的名字取为 Bubble_qsort ,是因为我们将用冒泡排列的方式来模拟实现 qsort 函数。

所以,我们要交代趟数,也要交代每趟交换数据的次数。

而交换操作中,我们可以将每两个数(的地址)传入 int_cmp 函数中,观察返回的值。若返回正数值,则再创建一个交换函数。

但是, void* 类型的指针不能进行任何操作。也许会用强制类型转换,转换成什么? int* ?但这可是在模拟 qsort 函数,这个函数原来是可以排列任意类型的数据的。

所以,我们不妨将 void* 类型,强制转换成 char* 类型

#include<stdio.h>

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

void Swap(char* buf1, char* buf2)
{
    
}

void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = 0; j < count - i - 1; j++)
        {
            if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
                Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }
}

void test1()
{
    int arr[] = { 4,5,2,7,9,12,34,101 };
    int count = sizeof(arr) / sizeof(arr[0]);
    Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
}

int main()
{
    test1();//实现整型值的排序

    return 0;
}

而在交换函数中,既然地址已被强制转换成 char* ,那么我们就不能一次性交换干净,而是一点一点交换。交换的次数,自然是元素的大小。

#include<stdio.h>

void Print(int arr[], int count)//打印函数
{
    for (int i = 0; i < count; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int int_cmp(const void* p1, const void* p2)//比较函数
{
    return *(int*)p1 - *(int*)p2;
}

void Swap(char* buf1, char* buf2, int size)//交换函数
{
    for (int i = 0; i < size; i++)
    {
        char tmp = *(buf1 + i);
        *(buf1 + i) = *(buf2 + i);
        *(buf2 + i) = tmp;
    }
}

void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{                                                   //模拟 qsort 的函数
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = 0; j < count - i - 1; j++)
        {
            if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
                Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }
}

void test1()
{
    int arr[] = { 4,5,2,7,9,12,34,101 };
    int count = sizeof(arr) / sizeof(arr[0]);
    Print(arr, count);
    Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
    Print(arr, count);
}

int main()
{
    test1();//实现整型值的排序

    return 0;
}

这样一来,这个函数连结构体都能排列。但是要加一点比较函数代码:

#include<stdio.h>

struct Stu//创建结构体
{
	char name[30];
	int age;
};

void Print(int arr[], int count)//打印函数
{
    for (int i = 0; i < count; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void Print1(struct Stu* p, int sz)//打印结构体
{
	for (int i = 0; i < sz; i++)
	{
		printf("%s: %d\n", p->name, p->age);
		p++;
    }
}

int int_cmp(const void* p1, const void* p2)//比较函数
{
    return *(int*)p1 - *(int*)p2;
}

int cmp_str_by_name(const void* p1, const void* p2)//比较字符串
{
	if (strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name) > 0)
		return 1;
	else if (strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name) < 0)
		return -1;
	else
		return 0;
}

void Swap(char* buf1, char* buf2, int size)//交换函数
{
    for (int i = 0; i < size; i++)
    {
        char tmp = *(buf1 + i);
        *(buf1 + i) = *(buf2 + i);
        *(buf2 + i) = tmp;
    }
}

void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{                                                   //模拟 qsort 的函数
    for (int i = 0; i < count - 1; i++)
    {
        for (int j = 0; j < count - i - 1; j++)
        {
            if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
            {
                Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
            }
        }
    }
}

void test1()
{
    int arr[] = { 4,5,2,7,9,12,34,101 };
    int count = sizeof(arr) / sizeof(arr[0]);
    Print(arr, count);
    Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
    Print(arr, count);
}

void test2()
{
    struct Stu arr[] = { { "zhangsan", 18 }, { "lisi", 20 }, { "wangwu", 38 } };
	int count = sizeof(arr) / sizeof(arr[0]);
	Print1(arr, count);
    printf("-------------------------\n");
    Bubble_qsort(arr, count, sizeof(arr[0]), cmp_str_by_name);
	Print1(arr, count);
}

int main()
{
    //test1();//实现整型值的排序
    test2();//实现结构体的排列

    return 0;
}