qsort排序

1.重温冒泡排序

#include <stdio.h>
bubble_sort(int arr[], int sz)
{
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		
		//一趟排序过程
		int j = 0;                     //两两相邻的元素进行比较,如果不满足顺序就交换
		for (j = 0; j <sz-1-i ; j++)
		{                           
			if (arr[j]>arr[j+1])
				{
					int tmp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=tmp;
				}
		}
	}
}
void Print_arr(int arr[],int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0};
	//排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr,sz);
	//打印
	Print_arr(arr, sz);
	return 0;
}

我们发现函数参数部分整型数组接收,所以这个函数只能排序整型数据。而qsort是用来排序的库函数,可以排序任意类型的数据,它可以对指定数组(包括字符串,二维数组,结构体等)进行排序,底层使用的是快速排序的方式。

2.qsort函数的参数

从cplusplus官网上我们可以看到qsort()函数是有四个参数的,如图: 

参数说明:

  • 第一个参数是一个指针,指向的是待排序数组的第一个元素,而void*的意思是它是一个无具体类型指针,原因是我们希望它是一个可以排序很多种数据的排序函数,如果这里的指针类型固定,我们就只能对函数传入固定类型的参数进行排序了。
  • 第二个参数代表待排数组的元素个数。因为元素个数恒为非负数,因此该参数的数据类型是size_t(即无符号整形)。
  • 第三个参数为待排数组中每个元素的大小。因为元素大小恒为非负数,因此该参数的数据类型是size_t(无符号整形)。
  • 第四个参数是一个函数指针,该指针指向的函数需要两个无具体类型的指针作为参数,该函数的返回值是一个int类型的整型

compar()函数的作用是将传进来的两个参数进行比较,如果参数p1<p2,函数返回一个小于0的数;如果参数p1=p2,返回0;如果参数p1>p2,返回一个大于0的数。

在qsort函数调用完compar函数后,会接收到compar返回的一个有符号的整型数字,当接收到compar函数返回值大于0时,qsort函数就会将这两个元素进行交换; 返回值小于等于0时,qsort函数不对其交换


在使用冒泡排序的情况下,我们想要改造这个函数,让它能够排序任意类型的数据,我们发现两个整型元素的比较可以直接使用 '>',但是两个字符串,两个结构体的比较不能直接使用 '>'。我们可以把两个元素比较的方法封装成函数,然后把函数的地址传递给排序函数。 

3.使用qsort函数排序一维整型数组数据

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* p1, const void* p2)
{
    return *(int*)p1 - *(int*)p2;
                           //void*不能直接进行解引用,需要强制类型转换成待排序的数据类型
}
void Print_arr(int arr[],int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
void test1()
{
    int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), cmp_int);
    Print_arr(arr, sz);
}
int main()
{
    test1();
    return 0;
}

运行结果:

注意:qsort排序默认会是升序。如果你希望qsort函数排出一个降序数组时,那么就需要调换一下*p1和*p2,直接返回*p2-*p1的值即可。


4.使用qsort函数排序结构体

4.1按姓名排序:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
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);
    //将p1的类型强制转换成结构体指针,再用结构体间接访问操作符找到名字,
    //借助strcmp函数来比较两个字符串的大小,并将比较的结果返回给qsort函数。
}   
void test2()
{
    struct Stu arr[3] = { {"zhangsan",20},{"lisi",35},{"wangermazi",18 } };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%s %d\n", arr[i].name, arr[i].age);
    }
}
int main()
{
    test2();
    return 0;
}

运行结果:

4.2按年龄排序:

#include<stdio.h>
#include<stdlib.h>
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[3] = { {"zhangsan",20},{"lisi",35},{"wangermazi",18 } };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%s %d\n", arr[i].name, arr[i].age);
    }
}
int main()
{
    test2();
    return 0;
}

运行结果:


5.qsort函数的模拟实现

套用冒泡排序算法,模拟实现bubble_sort函数

 bubble_sort函数的参数:

void bubble_sort(void* base, size_t sz, size_t width,int (*compar)(const void*, const void*));

6使用bubble_sort函数排序一维整形数组数据

#include <stdio.h>
int cmp(const void* p1, const void* p2)
{
    return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1, char* buf2, size_t width)
{
	int i = 0;
	for (size_t i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
void bubble_sort(void*base,size_t sz,size_t width,int(*cmp)(const void*p1,const void*p2) )
{
	//趟数
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		
		//一趟排序过程
		size_t j = 0;
		for ( j = 0; j <sz-1-i ; j++)
		{         //无法确定base指针类型,强转成char*一个字节一个字节地访问,不会出错                  
			if (cmp((char*)base + j * width, (char*)base + (j+1) * width)>0)
				{
				    /*int tmp=arr[j];
					arr[j]=arr[j+1];    //交换两个元素
					arr[j+1]=tmp;*/
				    Swap((char*)base + j * width, (char*)base + (j + 1) * width ,width);
				}
		}
	}
}
void Print_arr(int arr[],int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp);
	Print_arr(arr, sz);
	return 0;
}

Swap函数

因为我们要交换的数据可能不是整型数据,可能是其他类型的数据, 所以我们封装一个函数,把需要比较的两个数据的地址传进去,由于不知道一个元素的大小,所以把width也得传进去,数据类型强转成char*,将width大小字节的内容一个字节一个字节交换,这就保证了函数能交换任意类型的数据

运行结果:


7使用bubble_sort函数排序结构体

7.1按年龄排序:

#include <stdio.h>
void Swap(char* buf1, char* buf2, size_t width)
{
	int i = 0;
	for (size_t i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
void bubble_sort(void*base,size_t sz,size_t width,int(*cmp)(const void*p1,const void*p2) )
{
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for ( j = 0; j <sz-1-i ; j++)
		{                           
			if (cmp((char*)base + j * width, (char*)base + (j+1) * width)>0)
			{
				   Swap((char*)base + j * width, (char*)base + (j + 1) * width ,width);
			}
		}
	}
}
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;
}
int main()
{
	struct Stu arr[3] = { {"zhangsan",20},{"lisi",35},{"wangermazi",18 } };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
   	for (int i = 0; i < sz; i++)
    {
	   printf("%s %d\n", arr[i].name, arr[i].age);
	}
	return 0;
}

运行结果:

7.2按姓名排序:

#include <stdio.h>
#include<string.h>
void Swap(char* buf1, char* buf2, size_t width)
{
	int i = 0;
	for (size_t i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
void bubble_sort(void* base, size_t sz, size_t width, int(*cmp)(const void* p1, const void* p2))
{
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
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);
}
int main()
{
	struct Stu arr[3] = { {"zhangsan",20},{"lisi",35},{"wangermazi",18 } };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
	for (int i = 0; i < sz; i++)
	{
		printf("%s %d\n", arr[i].name, arr[i].age);
	}
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值