C language library function qsort - usage and simulation implementation

Table of contents

1. How to use:

(1) Instructions for use:

(2) Function declaration:

(3) Instructions on the use of parameters:

(4) Simple usage examples:

 2. C language simulation to implement qsort:

(1), Step 1

(2) Step 2

(3) Step 3

(4) Simulation implementation source code


1. How to use:

(1) Instructions for use:

①: This function sorts the data in the array.

②: Different from other sorting algorithms (such as bubble sort, quick sort...), these sorting algorithms can only sort one type of data, but this library function can sort all types . (Such as structure, integer, floating point, etc.) This is also its advantage.

③: The principle of this library function is: quick sort algorithm.

④: This library function uses the "callback function" mechanism.

⑤: The specific usage can be found on the official website of the library function: https://legacy.cplusplus.com/ .

(2) Function declaration:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*));

explain:

1: This function has no return type.

2: There are four parameters in total:

           ①: The first parameter base is used to receive the first address of the array to be sorted, because all types of arrays can be sorted, and all parameter types are "void*" (type void*, which can receive different types of addresses. The specific usage can be Find out for yourself.).

          ②: The second parameter num is the number of elements in the array to be sorted (pointed to by the pointer). The parameter type is an unsigned integer.

          ③: The third parameter size is the size of each element in the array to be sorted (pointed to by this pointer). The parameter type is an unsigned integer.

          ④: The fourth parameter is a function pointer (those who have not learned it but are interested can learn it by themselves. If you are not interested, just use this library function as follows). We usually call it a "comparison function", which points to The function return type is int and has two "const void*" parameters. The function pointed to by this pointer needs to be defined by us (the user). The commonly used definition method is as follows:

        

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

explain:

            ①: The two pointers of the formal parameters are used to receive the addresses of the two elements compared in the array. We don’t need to worry about it. This library function will automatically pass the value according to the first three formal parameters of our qsort. Just remember here. , using void* to receive is to facilitate the reception of different types of data, and because it is defined by our users, we force the type to be converted according to the actual situation. For example, the above is sorting and shaping, so it is forced to "int*". The role of const is to prevent the two addresses from being changed.

           ②: Regarding the return type, we need to remember that the return value is the value of pointer p1 minus the value of p2, which is ascending order;

                                                                 Return the value of pointer p2 minus the value of p1, which is descending order.

As in the above use case, it is sorted in ascending order.

(3) Instructions on the use of parameters:

①: Why use "void*" for base type?

Answer: The starting address is convenient for receiving different types of data.

②: Why do we need the number of elements of the array num?

 Answer: Because the array needs to be sorted.

③: Why do you need the size of array elements?

Answer: Because when sorting, the program does not know what type of data is being sorted and how far it will go in one step, so it needs the size of each element in order to complete the sorting.

(4) Simple usage examples:

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

//升序排序整形的比较函数
int comp1(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
//降序排序整形的比较函数
int comp2(const void* p1, const void* p2)
{
	return (*(int*)p2 - *(int*)p1);
}
//打印数组
void my_print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
}

//排序整形用例
void test1()
{
	int arr[10] = { 2,3,1,6,5,8,4,0,7,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);
	printf("原arr:");
	my_print(arr, sz);
	//升序
	qsort(arr, sz, size, comp1);
	printf("升序:");
	my_print(arr, sz);
	//降序
	qsort(arr, sz, size, comp2);
	printf("降序:");
	my_print(arr, sz);
}

//排序结构体用例
typedef struct Stu
{
	int age;
	char name[10];
}S;
//排序结构体成员age的比较函数
int comp3(void* p1,void* p2)
{
	return (((S*)p1)->age - ((S*)p2)->age);
}
//排序结构体成员name的比较函数
int comp4(void* p1, void* p2)
{
	return strcmp(((S*)p1)->name, ((S*)p2)->name);
}

void test2()
{
	S s[3] = { {20,"zhangsan"}, {10,"lisi"},{40,"wangwu"} };
	//按升序年龄排序
	qsort(s, 3, sizeof(s[0]), comp3);
	int i = 0;
	printf("\n按升序年龄排序:\n");
	for (i = 0; i < 3; i++)
	{
		printf("%s %d\n", s[i].name, s[i].age);
	}
	//按姓名升序排序
	qsort(s, 3, sizeof(s[0]), comp4);
	printf("按姓名升序排序:\n");
	for (i = 0; i < 3; i++)
	{
		printf("%s %d\n", s[i].name, s[i].age);
	}
}

int main()
{
	test1();//排序整形
	test2();//排序结构体
	return 0;
}

       It is worth noting that in the comparison function, integer, floating point and other types can be directly compared using the greater than symbol, but for a string (such as the comparison function comp4 that compares name in the use case), this is not possible. In this case, the String comparison function strcmp (you can learn the relevant usage by yourself, or search for it at https://legacy.cplusplus.com/ ).  

operation result:

 2. C language simulation to implement qsort:

(1), Step 1

1. As mentioned above, the principle of the qsort function is "quick sort", but for this simulation implementation, the editor uses bubble sort .

2. Since it is a simulation implementation, the return type, parameter type and number should be consistent.

3. The basic idea of ​​bubble sorting is nothing more than that one layer of for loop determines the number of passes, and one layer of for loop determines the number of exchanges required for each pass. Here you need to use the second parameter num to determine the number of passes , num Yuan takes num-1 trips.

void my_bubb_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	//趟数
	for (i = 0; i < num; i++)
	{
		int j = 0;
		//每趟的交换次数
		for (j = 0; j < num - 1 - i; j++)
		{
			
		}
	}
}

(2) Step 2

4. At this point, we are ready to determine whether to perform the exchange. The fourth parameter function pointer is used here to call the function pointed to by the actual parameter address passed by the user (this is a classic example of a "callback function"). Specifically How to judge the following picture:

void my_bubb_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	//趟数
	for (i = 0; i < num; i++)
	{
		int j = 0;
		//每趟的交换次数
		for (j = 0; j < num - 1 - i; j++)
		{
			//以升序为例,用户自定义的函数comp1和comp2返回值大于0,则交换
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)
			{
				
			}
		}
	}
}

Specifically, in the judgment condition of if, the function pointed to by the function pointer cmp is called, and the addresses of the two elements to be compared are passed in as actual parameters. The third formal parameter size is used here . Why is it written like this? The explanation is as follows :

The value of local variable j happens to meet the addressing conditions, so the multiple of size is j times.

Then we see that the return value of the function pointed to by the function pointer cmp is judged to be greater than 0. If it is greater than 0, the two data corresponding to the actual parameter address are exchanged. This corresponds to the return method in the user-defined comparison function:

When it is *p1-*p2 (*p1 is the previous number, *p2 is the next number): Because the rule is to return a number greater than 0 before exchanging, so only when *p1>*p2, the return value is positive number, so that the values ​​​​of *p1 and *p2 will be exchanged, so the larger number will be sorted to the back, so it is sorted in ascending order at this time.

 When it is *p2-*p1 (*p1 is the previous number, *p2 is the next number): According to the rules, only when *p2>*p1, the return value will be a positive number, so that *p1 and *p1 will be exchanged *p2 value, so larger values ​​will be sorted first, so it is sorted in descending order.

(3) Step 3

5. After judging whether to sort, the sorting condition is established, and after entering the if, it is time to perform the swap operation. A function Swap is defined here for this operation.

The function is defined as follows:

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

}
void my_bubb_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	//趟数
	for (i = 0; i < num; i++)
	{
		int j = 0;
		//每趟的交换次数
		for (j = 0; j < num - 1 - i; j++)
		{
			//以升序为例,用户自定义的函数comp1和comp2返回值大于0,则交换
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)
			{
				//交换
				Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}

As shown in the above code, we can see that we need to pass the addresses of the two numbers that meet the conditions as actual parameters to Swap, and also pass the element size size in, so the formal parameters are two char* pointers buf1 and buf2, and size used to receive the size of the element.

The purpose of passing the addresses of two numbers is to exchange the two numbers. Then why is the size of the element passed?

The reason is as follows:

According to the above principle, buf1 and buf2 are both char* pointers. They can only exchange one byte of content at a time. After the exchange, add 1 to the pointers buf1 and buf2, so that they jump to the next byte of content, so you want To complete the exchange, it is necessary to exchange size times. Because the element size is size bytes, one byte is exchanged at a time, so the purpose can be achieved by exchanging size times , so the for loop judgment condition is i<size.

The above is all the content of the simulation implementation. The following are usage examples:

(4) Simulation implementation source code

//冒泡排序模拟实现qsort

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

}

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

}

void my_bubb_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	int i = 0;
	//趟数
	for (i = 0; i < num; i++)
	{
		int j = 0;
		//每趟的交换次数
		for (j = 0; j < num - 1 - i; j++)
		{
			//以升序为例,用户自定义的函数comp1和comp2返回值大于0,则交换
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)
			{
				//交换
				Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}

int main()
{
	int i = 0;
	int arr[10] = { 6,5,8,7,3,4,2,1,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("原arr:");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	my_bubb_sort(arr, sz, sizeof(arr[0]), comp1);
	printf("\n升序排序:");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

operation result:

This is the end of this knowledge, I hope it is helpful to you! ! !

Guess you like

Origin blog.csdn.net/hffh123/article/details/132261992