qsort函数用法及实现

qsort函数介绍

我们可以先看看官网:qsort函数
头文件为:stdlib.h
实现接口:void qsort (void* base, size_t num, size_t size, int (compar)(const void,const void*));

用法:对数组元素排序

排序NUM通过指向的数组base,数组元素数量 num,元素大小,使用COMPAR函数来确定的顺序。
此函数使用的排序算法(官方底层是基于快排实现的,这个如果自己实现各种排序都是可以的,后边我用最简单的冒泡排序来自己实现一个qsort函数)通过调用指定的比较函数并以指向它们的指针作为参数来比较元素对。
该函数不返回任何值,而是通过对数组的元素进行基本排序(如compar所定义)来修改指向的数组的内容。
等效元素的顺序未定义。

参量

base:Pointer to the first object of the array to be sorted, converted to a void*.
num:Number of elements in the array pointed to by base. size_t is an unsigned integral type.
size:Size in bytes of each element in the array. size_t is an unsigned integral type.
compar:Pointer to a function that compares two elements. This function is called repeatedly by qsort to compare two elements. It shall follow the following prototype:int compar (const void* p1, const void* p2);

这里==void*==的用法可参见我之前的博客:void和void*的区别

comper示例:

int compareMyType (const void * a, const void * b)
{
  if ( *(MyType*)a <  *(MyType*)b ) return -1;
  if ( *(MyType*)a == *(MyType*)b ) return 0;
  if ( *(MyType*)a >  *(MyType*)b ) return 1;
}

qsort使用演示

/* qsort example */
#include <stdio.h>      /* printf */
#include <stdlib.h>     /* qsort */

int values[] = { 40, 10, 100, 90, 20, 25 };

int compare (const void * a, const void * b)
{
  return ( *(int*)a - *(int*)b );
}

int main ()
{
  int n;
  qsort (values, 6, sizeof(int), compare);
  for (n=0; n<6; n++)
     printf ("%d ",values[n]);
  return 0;
}

输出结果:

10 20 25 40 90 100

用冒泡排序实现一个my_qsort函数

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>

// 比较函数
int CompInt(const void* xp,const void* yp) {
	int x = *(const int*)xp;//xp是void*类型,我们要用于int类型数组排序所以先强转为int*,然后在解引用为x的值进行比较
	int y = *(const int*)yp;
	if (x > y) {
		return 1;
	}
	else if (x == y) {
		return 0;
	}
	else {
		return -1;
	}

}
//交换函数
void swap(char *p, char *q, size_t num) {
	while (num--) {
		char temp = *p;
		*p = *q;
		*q = temp;
		p++;
		q++;
	}
}
// my_sort函数
void my_qsort(void *base,size_t num,size_t size,int (*comp)(const void*,const void*)) {
	assert(base);
	assert(comp);
	char *p = (char*)base;
	for (size_t i = 0; i < num - 1; i++) {
		int flag = 0;
		for (size_t j = 0; j < num - 1 - i; j++) {
			if (comp(p + j*size, p + (j + 1)*size)>0) {
				swap(p+j*size,p+(j+1)*size,size);
				flag = 1;
			}
		}
		if (flag == 0) {
			break;
		}
	}
}

int main() {
	int arr[] = { 1, 23, 4, 5, 65, 32, 124, 675 };
	
	int num = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, num, sizeof(int), CompInt);
	
	system("pause");
	return 0;
}

冒泡排序解析可见我之前博客:冒泡排序以及优化

运行结果(在这里简单介绍如何调试代码):
第一步在my_sort前后打上断点
第二步启动调试
第三步打开监视窗口查看arr内容
(在这里就不具体介绍了,后边会写一篇博客介绍相关内容)
排序前:
qsort函数用法及实现

排序后:

qsort函数用法及实现

在这里我们发现排序结果是升序的。那么问题来了如何让结果为降序呢???
在这里我用qsort来说明这个问题

// 比较函数
int CompInt(const void* xp,const void* yp) {
	int x = *(const int*)xp;//xp是void*类型,我们要用于int类型数组排序所以先强转为int*,然后在解引用为x的值进行比较
	int y = *(const int*)yp;
	if (x > y) {
		return 1;
	}
	else if (x == y) {
		return 0;
	}
	else {
		return -1;
	}

}

qsort函数用法及实现

排序的顺序主要取决于compint的返回值。大于返回1,小于返回-1那么他就是升序。
如果修改大于返回-1,小于返回1,那么他就是降序了。

// 比较函数
int CompInt(const void* xp,const void* yp) {
	int x = *(const int*)xp;//xp是void*类型,我们要用于int类型数组排序所以先强转为int*,然后在解引用为x的值进行比较
	int y = *(const int*)yp;
	if (x > y) {
		return -1;
	}
	else if (x == y) {
		return 0;
	}
	else {
		return 1;
	}

}

qsort函数用法及实现

qsort中几种常见的比较函数comp

对int型数组排序

int comp_int(const void* _a , const void* _b)  //参数格式固定
{
    int* a = (int*)_a;    //强制类型转换
    int* b = (int*)_b;
    return *a - *b;  
}

这里不返回-1,1也是可以的。用大于0小于0的数,效果是一样的。

对char型数组排序(同int类型)

int comp_char(const void* _a , const void* _b)  //参数格式固定
{
    char* a = (char*)_a;    //强制类型转换
    char* b = (char*)_b;
    return *a - *b;  
}

对double型数组排序

int comp_double(const void* _a , const void* _b)  //参数格式固定
{
    double* a = (double*)_a;    //强制类型转换
    double* b = (double*)_b;
    return *a > *b ? 1 : -1;   //特别注意
}

在对浮点或者double型的一定要用三目运算符,因为要是使用像整型那样相减的话,如果是两个很接近的数则可能返回一个很小的小数(大于-1,小于1),而cmp的返回值是int型,因此会将这个小数返回0,系统认为是相等,失去了本来存在的大小关系

对字符串进行排序

int comp_string(const void* _a , const void* _b)  //参数格式固定
{
    char* a = (char*)_a;  //强制类型转换
    char* b = (char*)_b;
    return strcmp(a,b);
}

参考博客:C语言qsort函数用法

上一篇:C语言常用库函数:快速排序qsort与查找bsearch


下一篇:语言库中常用的排序算法底层结构qsort()