C语言编写无类型的快速排序和归并排序

本文介绍了一种适用于任何数据类型的快速排序和归并排序算法实现。使用void*指针和回调函数来实现对不同类型数据的排序,并提供了具体代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚看了李先静老师的《系统程序员成长计划》,里面有一部分是讲解排序的,就按着他的讲解顺序自己尝试着写了适用于任何类型的快速排序和归并排序的代码。写一个无类型的排序要注意两个方面:

1) 用指针,并且是void*作为传入参数,这样可以接纳任何的类型。

2)利用回调函数,通过调用不同的比较函数(DataCompareFunc)实现对多种数据类型的可行性

3)排序不可避免的要用到数据的交换,即swap函数,由于我们传入的数据类型不同,因此相应的swap函数也是不同。这里也可以用回调函数来实现,不过有一种更简单的方法实现。就是将void*转换为char*,如果已知数据类型的字节大小,那么可以通过逐个字节的交换,实现数据的交换。库函数中的qsort函数就是用的这种方法。具体的代码可以参考下面的代码。

#ifndef SORT_H_
#define SORT_H_
#include <sys/types.h>

typedef int (*CompareFunc)(void *ctx, void *data);
typedef int (*SortFunc)(void **array, size_t size, CompareFunc cmp);

int bubble_sort(void *array, size_t size, size_t width, CompareFunc cmp);
int quick_sort_recursion(void *array, size_t size, size_t width, CompareFunc cmp);
int merge_sort_recursion(void *array, size_t size, size_t width, CompareFunc cmp);

int cmp_int(void *ctx, void *data);
int cmp_char(void *ctx, void *data);
int cmp_str(void *ctx, void *data);


#endif


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include "mysort.h"

#define return_if_fail(p) if(!(p))\
	{printf("%s : %d Warning: "#p" failed!\n",__func__,__LINE__);return 0;}

static void swap(char *thiz, char *data, size_t width) //转换函数
{
	char temp;
	if(thiz != data)
	{
		while(width --)
		{
			temp = *thiz;
			*(thiz++) = *data;
			*(data++) = temp;	
		}
	}
}

static void assign(char *thiz, char *data, size_t width) //赋值函数,用于归并排序
{
	if(thiz != data)
	{
		while(width --)
		{
			*data = *thiz;
			data ++;
			thiz ++;
		}
	}
}

static void bubble_sort_re(char *start, char *end, size_t width, CompareFunc cmp) //冒泡排序
{
	char *p, *q;
	size_t flag = 1;
	for(p = end; p > start; p -= width)
	{
		flag = 1;
		for(q = start; q < p; q += width)
		{			
			if(cmp(q, q + width) > 0)
			{
				flag = 0;
				swap(q, q+width, width);
			}
		}
		if(flag == 1)
		return;
	}


}

static void quick_sort_recursion_re(char *start, char *end,  size_t width, CompareFunc cmp) // 递归快速排序
{
	char *p = start + width;
	char *q = end;
	char *pivot = start;
	while(p < q)
	{
		while(cmp(q, pivot) > 0  && q > p)
		{
			q -= width;
		}
		while(cmp(p, pivot) < 0  && q > p)
		{
			p += width;
		}

		if(q > p)
		{
			swap(p , q , width);
		}
	}
	if(cmp(pivot , q) > 0)
	{
		swap(pivot, q, width);
	}
	if( start < q - width)
	{
		quick_sort_recursion_re(start, q - width, width, cmp);
	}
	if(q  < end)
	{
		quick_sort_recursion_re(q , end , width, cmp);
	}
	return;
}


int bubble_sort(void *array, size_t size, size_t width, CompareFunc cmp) //冒泡排序
{
	return_if_fail(array != NULL && size > 0 && cmp != NULL);
	if(size < 2)
	return 0;
	
	char *start  = (char *)array;
	char *end = (char*)array + (size-1)*width;
	bubble_sort_re(start, end, width, cmp);
	return 0;	
}

int quick_sort_recursion(void *array, size_t size, size_t width, CompareFunc cmp) //快速排序
{
	return_if_fail(array != NULL && size > 0 && cmp != NULL);
	if(size < 2)
	return 0;

	char *start = (char *)array;
	char *end = (char*)array + (size -1)*width;
	quick_sort_recursion_re(start, end, width, cmp);
	return 0;
}

static int merge(char *start, char *middle_pointer, char *end, size_t size, size_t width, CompareFunc cmp) //归并排序
{
	char *p = start;
	char *q = middle_pointer + width;
	char *data = (char *)malloc(size*width);
	char *temp = data;
	while(p <= middle_pointer && q <= end)
	{
		while(cmp(p, q) <= 0 && p <= middle_pointer)
		{
			assign(p, temp, width);
			temp += width;
			p += width;
		}
		while(cmp(p,q) > 0 && q <= end)
		{
			assign(q, temp, width);
			temp += width;
			q += width;
		}
	}
	while(p <= middle_pointer)
	{
		assign(p, temp, width);
		temp += width;
		p += width;
	}
	while(q <= end)
	{
		assign(q, temp, width);
		temp += width;
		q += width;
	}
	p = start;
	q = end;
	temp = data;
	while(p <= q)
	{
		assign(temp, p, width);
		temp += width;
		p += width;
	}
	free(data);
	data = NULL;
}

static int merge_sort_recursion_re(char *start, char *end,  size_t size, size_t width, CompareFunc cmp)//归并排序
{
	if(start == end)
		return 0;
	if(end > start)
	{
		size_t front_size = size>>1;
		size_t back_size = size - front_size;
		char * middle_pointer = start + (front_size-1)*width;
		//printf("%d, 0%s\n", __LINE__, __func__);
		merge_sort_recursion_re(start, middle_pointer, front_size, width, cmp);
		//printf("%d, 1%s\n", __LINE__, __func__);
		merge_sort_recursion_re(middle_pointer + width, end, back_size, width, cmp);
		//printf("%d, 2%s\n", __LINE__, __func__);
		merge(start , middle_pointer, end, size, width, cmp);
		//printf("%d, 3%s\n", __LINE__, __func__);
	}
	return 0;	
}

int merge_sort_recursion(void *array, size_t size, size_t width, CompareFunc cmp) //归并排序
{
	return_if_fail(array != NULL && size > 0 && cmp != NULL);
	if(size < 2)
		return 0;
	char *start = (char *)array;
	char *end  = (char *)array + (size - 1)*width;
	merge_sort_recursion_re(start, end, size, width, cmp);
	return 0;
}
int cmp_int(void *ctx, void *data)
{
	return (*(int*)ctx - *(int*)data);
}

int cmp_char(void *ctx, void *data)
{
	return (*(char*)ctx - *(char*)data);
}

int cmp_str(void *ctx, void *data)
{
	return strcmp((char*)ctx, (char*)data);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值