qsort的自主实现

目录

qsort()函数的功能:

首先回忆一下冒泡排序是如何实现的

需要改动的地方:

compare():

swap():

qosrt()函数实现

快速排序实现qsort()已经成功


今天我要分享的是qsort的自主实现。

冒泡版qsort()(标准是用的快速排序,好吧,我还没想到怎么准确实现)

qsort()函数的功能:

qsort()函数能将一个数组的元素进行排序。

作用:
 

Remarks

The qsort function implements a quick-sort algorithm to sort an array of num elements, each of width bytes. The argument base is a pointer to the base of the array to be sorted.qsort overwrites this array with the sorted elements. The argument compare is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. qsort calls the compare routine one or more times during the sort, passing pointers to two array elements on each call:

翻译:

评论

qsort函数实现了一种快速排序算法,可以对num元素数组进行排序,每个元素的宽度为字节。参数base是指向要排序的数组的基的指针。qsort用已排序的元素覆盖此数组。参数compare是指向用户提供的例程的指针,该例程比较两个数组元素,并返回一个指定其关系的值。qsort在排序过程中调用比较例程一次或多次,每次调用时将指针传递到两个数组元素:

简单来说就是排序,但是你要自己写一个比较大小的函数。

注意:这个函数的函数指针的类型为 int (*)(const void *, const void * );

如果不知道函数指针就别管这个了(以后我会出一篇详解指针文章)。

先看一下qsort函数的类型(带参数名字)

qsort的自主实现_第1张图片

可复制:

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

由于qsort只是让待排序数组排序,所以不必设置返回值,返回类型为空。base是传入的首元素地址,void*说明它可以接收任意类型的地址;num是待排数组的元素个数,size_t是unsigned int类型的重定义类型,其实就是unsigned int(上一篇文章提到了),元素个数不可能是负数,所以用的是无符号类型;width是数组每一个元素的所占空间的大小;int (__cdecl *compare )(const void *elem1, const void *elem2 ) 是一个函数指针(不知道函数指针也没事,看案例就可明白)。

先看一下标准qsort函数的应用:

#include
#include
int compare1(const void* e1, const void* e2)
{
	return (int)(*(int*)e1 - *(int*)e2);
}

int main(void)
{
	int arr[5] = { 2,4,3,1,0 };

	int i = 0;
	int j = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	int len = sizeof(arr) / sizeof(arr[0]);
	printf("\n======================\n");
	qsort(arr, len, sizeof(int), compare1);

	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果:

qsort的自主实现_第2张图片

 自主实现(利用冒泡排序):

首先回忆一下冒泡排序是如何实现的

	for (i = 0; i < len - 1; i++)
	{
		for (j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
			}
		}
	}

我们就以这个为基础来实现,

需要改动的地方:

一:if的判断条件。

二:if里面需要设立一个函数实现数组元素的交换。

这里用两个函数,if的判断条件用compare()函数的返回值来加以修饰来作为判断条件,而swap()函数作为交换两个元素的函数。

于是我们可以改写为:

以每个元素为int类型的数组为例:compare()函数是是自己设置的,目的是比较两个元素的大小。我们先实现这个函数的实现。

compare():

因为我们需要对待排数组排序,所以我们应该知道待排数组的每个元素的类型是什么,以int类型为例:

qsort的自主实现_第3张图片

 (int*)e1是把e1前置类型转换为int*类型,而*(int*)e1是对强制类型转换后的e1解引用,就是取出元素的值,那么*(int*)e1 - *(int*)e2就是两个元素相减,有人可能会问了,这个结果不就是int类型吗,为什么还要对最终结果强制类型转换为int?因为我想以后编写其他类型的元素的数组方便。一会换其他类型的实例就很容易明白(升序是e1在前,降序是e1在后,主要是返回的结果与0比较)。

判断条件:

compare(前一个元素, 后一个元素) > 0

因为我们是用冒泡排序的思想,传入的是相邻前后的元素,这个函数的返回值如果大于0那么就交换。

swap():

swap()需要交换的元素类型是未知的,所以用void*类型来接收,但是如果写成void*我们怎么对元素进行交换呢?我们学过的最小类型是char一个字节,数据的是以字节为单位在计算机里存储的,那么我们有一个思路,我们可以先把void*强制类型转换为char*类型,一个字节一个字节的进行交换。但是我们还要知道每个元素占用多少字节,即交换几个字节,要做到恰好两个元素每个字节都交换,所以我们要传入一个元素所占用字节数,我们可以用传入qsort()的形参width作为swap()的一个实参,代表一个元素的所占字节数。

那么swap()函数就可以这样实现:

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}

char* c1, char* c2表示我们直接把传进来元素的地址以char*类型进行操作。

现在我们的代码大概可以写出

    for (i = 0; i < num - 1; i++)
    {
        for (j = 0; j < num - 1 - i; j++)
        {
            if (前一个元素, 后一个元素) > 0)
            {
                swap(前一个元素, 后一个元素, width);
            }
        }
    }

现在我们有了一种思想,char*类型可以解决我们遇到的问题。

所以copare()和swap()传入数组元素的地址怎么传入合理呢?

答案是先转换为char*类型在利用j和width寻找代操作元素。

用compare()举例:

compare((char*)base + j * width, (char*)base + (j + 1) * width)

(char*)base + j * width 的含义是先以char*找到base地址,然后移动j*width个char类型距离,这里就相当于base[j],但是不能用base[j]直接访问,因为传入base是未知的类型,不可直接访问base的某个元素

那么(char*)base + (j + 1) * width就相当于base[j + 1]。

qsort的自主实现_第4张图片

所以我们可以写出swap()函数的传参

swap((char*)base + j * width, (char*)base + (j + 1) * width, width)

qosrt()函数实现

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}

void my_qsort(void* base, size_t num, size_t width,
	int(__cdecl* compare)(const void* e1, const void* e2))
{
	assert(base);
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

看一下成果:

示例一(int):

#include
#include
int compare1(const void* e1, const void* e2)
{
	return (int)(*(int*)e1 - *(int*)e2);
}

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}
void my_qsort(void* base, size_t num, size_t width,
	int(__cdecl* compare)(const void* e1, const void* e2))
{
	assert(base);//防止传入空指针,保证代码的健壮性
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}


int main(void)
{
	int arr[5] = { 2,4,3,1,0 };

	int i = 0;
	int j = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}

	printf("\n======================\n");
	int len1 = sizeof(arr) / sizeof(arr[0]);

	my_qsort(arr, len1, sizeof(int), compare1);

	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果:

qsort的自主实现_第5张图片

 示例二(char):

#include
#include
#include
int compare2(const void* e1, const void* e2)
{
	return (int)(*(char*)e1 - *(char*)e2);
}

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}

void my_qsort(void* base, size_t num, size_t width,
	int(__cdecl* compare)(const void* e1, const void* e2))
{
	assert(base);//防止传入空指针,保证代码的健壮性
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

int main(void)
{
	char ch[5] = "adxb";

	int i = 0;
	int j = 0;
	printf("%s", ch);

	printf("\n======================\n");
	int len2 = strlen(ch);

	my_qsort(ch, len2, sizeof(char), compare2);

	printf("%s", ch);

	return 0;
}

运行结果:

qsort的自主实现_第6张图片

示例三(double):

#include
#include
int compare3(const void* e1, const void* e2)
{
	return (int)(*(double*)e1 - *(double*)e2);
}

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}

void my_qsort(void* base, size_t num, size_t width,
	int(__cdecl* compare)(const void* e1, const void* e2))
{
	assert(base);//防止传入空指针,保证代码的健壮性
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

int main(void)
{
	double dd[5] = { 0.2, 0.3, 5.0, 0.1, -10.2 };

	int i = 0;
	int j = 0;

	for (i = 0; i < 5; i++)
	{
		printf("%lf ", dd[i]);
	}
	printf("\n======================\n");
	int len3 = sizeof(dd) / sizeof(dd[0]);

	my_qsort(dd, len3, sizeof(double), compare3);

	for (i = 0; i < 5; i++)
	{
		printf("%lf ", dd[i]);
	}

	return 0;
}

运行结果:

qsort的自主实现_第7张图片

实例四(结构体):

#include
#include

typedef struct Student
{
	char name[10];
	double scores;
} Student;

int compare4(const void* e1, const void* e2)
{
	return (int)(((Student*)e1)->scores - ((Student*)e2)->scores);
}

void swap(char* c1, char* c2, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		char t = *(c1 + i);
		*(c1 + i) = *(c2 + i);
		*(c2 + i) = t;
	}
}

void my_qsort(void* base, size_t num, size_t width,
	int(__cdecl* compare)(const void* e1, const void* e2))
{
	assert(base);//防止传入空指针,保证代码的健壮性
	int i = 0;
	int j = 0;
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

int main(void)
{
	Student s[5] = { {"张三", 10}, {"李四", 0}, {"王五", 100}, {"乌龟", 0.5}, {"兔子", -20} };

	int i = 0;
	int j = 0;

	for (i = 0; i < 5; i++)
	{
		printf("%-6s%lf\n", s[i].name, s[i].scores);
	}
	printf("\n======================\n");
	int len4 = sizeof(s) / sizeof(s[0]);

	my_qsort(s, len4, sizeof(s[0]), compare4);

		for (i = 0; i < 5; i++)
		{
			printf("%-6s%lf\n", s[i].name, s[i].scores);
		}

	return 0;
}

运行结果:

qsort的自主实现_第8张图片

这篇文章本来还想这再用快速排序来实现,但是没实现~~~,我会努力让它实现的!

要多记录一下写的代码了,伙伴们的支持是我最大的动力。

快速排序实现qsort()已经成功

qosrt()快速排序自主实现_逆风路上伴有谁的博客-CSDN博客

qsort的自主实现_第9张图片

你可能感兴趣的:(c语言)