归并排序算法

源码

#define _CRT_SECURE_NO_WARNINGS //处理scanf报错问题
#include <stdio.h>
#include <windows.h>

#define DEBUG_SWITCH 1
#if DEBUG_SWITCH
#define DEBUG_INFO(format, ...) printf("LINE: %d: "format"\n", __LINE__, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...) 
#endif

#define TRUE  1
#define FALSE 0

typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned long int uint32_t;
typedef unsigned long long int uint64_t;

#define ARR_SIZE(arr,type) (sizeof(arr)/sizeof(type))

typedef struct
{
	uint8_t a;
	uint64_t b;
}test_def;

typedef struct merge_sort_def
{
	uint64_t len;
	uint8_t monotonicity;
	uint64_t *raw_data_point;
	uint64_t *temp_data_point;
	uint8_t (*merge_compare_callback)(struct merge_sort_def *data, uint64_t a, uint64_t b);
	uint8_t (*merge_sort_output)(struct merge_sort_def *data, uint64_t *output_buffer);
}merge_sort_def;

static uint8_t merge_compare(merge_sort_def *data, uint64_t a, uint64_t b)
{
#define SORT_DATA_TYPE test_def
#define SORT_CMP_DATA_NAME b
	
	return ((((SORT_DATA_TYPE *)data->raw_data_point[a])->SORT_CMP_DATA_NAME >= ((SORT_DATA_TYPE *)data->raw_data_point[b])->SORT_CMP_DATA_NAME) ? \
		data->monotonicity : !data->monotonicity);
}

uint8_t merge_sort_output(merge_sort_def *data, uint64_t *output_buffer)
{
#define SORT_DATA_TYPE test_def
#define SORT_CMP_DATA_NAME b

	uint8_t ret = FALSE;

	for (uint64_t i = 0; i < data->len; i++)
	{
#if DEBUG_SWITCH
		printf("%ld ", ((SORT_DATA_TYPE *)data->raw_data_point[i])->SORT_CMP_DATA_NAME);
#endif
		((SORT_DATA_TYPE *)output_buffer)[i].SORT_CMP_DATA_NAME = ((SORT_DATA_TYPE *)data->raw_data_point[i])->SORT_CMP_DATA_NAME;
	}
	printf("\r\n");

	return ret;
}

static void merge(merge_sort_def *data, uint64_t left, uint64_t mid, uint64_t right)
{
	uint64_t i = left;//左序列指针
	uint64_t j = mid + 1;//右序列指针
	uint64_t t = 0;//临时数组指针
	while (i <= mid && j <= right) 
	{
		if (data->merge_compare_callback(data, i,j))
		{
			data->temp_data_point[t++] = data->raw_data_point[i++];
		}
		else
		{
			data->temp_data_point[t++] = data->raw_data_point[j++];
		}
	}
	while (i <= mid) 
	{//将左边剩余元素填充进temp中
		data->temp_data_point[t++] = data->raw_data_point[i++];
	}
	while (j <= right) 
	{//将右序列剩余元素填充进temp中
		data->temp_data_point[t++] = data->raw_data_point[j++];
	}
	t = 0;
	//将temp中的元素全部拷贝到原数组中
	while (left <= right) 
	{
		data->raw_data_point[left++] = data->temp_data_point[t++];
	}
}

static void merge_sort(merge_sort_def *data, uint64_t left, uint64_t right)
{
	if (left < right) 
	{
		uint64_t mid = (left + right) / 2;
		merge_sort(data, left, mid);//左边归并排序,使得左子序列有序
		merge_sort(data, mid + 1, right);//右边归并排序,使得右子序列有序
		merge(data, left, mid, right);//将两个有序子数组合并操作
	}
}

uint8_t merge_sort_init(merge_sort_def *data, uint64_t len, uint8_t monotonicity, \
	uint64_t *raw_data_buf, uint64_t *temp_data_buf, \
	uint8_t(*merge_compare_callback)(struct merge_sort_def *data, uint64_t a, uint64_t b), uint8_t(*merge_sort_output)(struct merge_sort_def *data, uint64_t *output_buffer))
{
	uint8_t ret = FALSE;
	if ((data != NULL) && (raw_data_buf != NULL) && (temp_data_buf != NULL) && (merge_compare != NULL) && (len >= (uint64_t)2))
	{
		data->len = len;
		data->monotonicity = monotonicity & (uint8_t)0x01;
		data->raw_data_point = raw_data_buf;
		data->temp_data_point = temp_data_buf;
		data->merge_compare_callback = merge_compare;
		data->merge_sort_output = merge_sort_output;
		ret = TRUE;
	}
	else
	{
		/* No thing */
	}
	return ret;
}

#define ARR_MAX 10
int main()
{
	static test_def data[ARR_MAX] = { 0 };
	static test_def output_data[ARR_MAX] = { 0 };
	static uint64_t merge_sort_raw_data[ARR_MAX] = { 0 };
	static uint64_t merge_sort_temp_data[ARR_MAX] = { 0 };

	static merge_sort_def merge_sort_data = { 0 };
		 
	for (uint64_t i = 0; i < ARR_SIZE(data, test_def); i++)
	{
		data[i].a = rand();
		data[i].b = rand();
		merge_sort_raw_data[i] = (uint64_t)&data[i];
#if DEBUG_SWITCH
		printf("%ld ", data[i].b);
#endif
	}
	printf("\r\n");

	uint64_t start, end;
	start = GetTickCount();
	merge_sort_init(&merge_sort_data, ARR_SIZE(data, test_def), TRUE, \
		merge_sort_raw_data, merge_sort_temp_data, \
		&merge_compare, &merge_sort_output);
	merge_sort(&merge_sort_data, 0, merge_sort_data .len - 1);
	merge_sort_data.merge_sort_output(&merge_sort_data, (uint64_t *)output_data);
	end = GetTickCount();
	printf("start: %lld ms  end: %lld ms  time: %lld ms\n", start, end, end - start);


	start = GetTickCount();
	merge_sort_init(&merge_sort_data, ARR_SIZE(data, test_def), FALSE, \
		merge_sort_raw_data, merge_sort_temp_data, \
		&merge_compare, &merge_sort_output);
	merge_sort(&merge_sort_data, 0, merge_sort_data.len - 1);
	merge_sort_data.merge_sort_output(&merge_sort_data, (uint64_t *)output_data);
	end = GetTickCount();
	printf("start: %lld ms  end: %lld ms  time: %lld ms\n", start, end, end - start);
}

验证

排序验证

  • 产生10个随机数进行排序
    在这里插入图片描述

耗时测试

  • 产生0XFFFFFF个数据进行排序

在这里插入图片描述

使用方法

定义比较回调函数

  • 只需要修改相应的宏即可
  • SORT_DATA_TYPE 结构体数组类型
  • SORT_CMP_DATA_NAME 需要对比的数据类型
  • 如果存在多层嵌套,需要自己修改成对应的大小比较函数即可
static uint8_t merge_compare(merge_sort_def *data, uint64_t a, uint64_t b)
{
#define SORT_DATA_TYPE test_def
#define SORT_CMP_DATA_NAME b
	
	return ((((SORT_DATA_TYPE *)data->raw_data_point[a])->SORT_CMP_DATA_NAME >= ((SORT_DATA_TYPE *)data->raw_data_point[b])->SORT_CMP_DATA_NAME) ? \
		data->monotonicity : !data->monotonicity);
}

定义结果获取函数

  • 若输入与输出数据类型相同,只需要修改相应的宏即可
  • 若不同,则可自行修改获取排序结果
uint8_t merge_sort_output(merge_sort_def *data, uint64_t *output_buffer)
{
#define SORT_DATA_TYPE test_def
#define SORT_CMP_DATA_NAME b

	uint8_t ret = FALSE;

	for (uint64_t i = 0; i < data->len; i++)
	{
#if DEBUG_SWITCH
		printf("%ld ", ((SORT_DATA_TYPE *)data->raw_data_point[i])->SORT_CMP_DATA_NAME);
#endif
		((SORT_DATA_TYPE *)output_buffer)[i].SORT_CMP_DATA_NAME = ((SORT_DATA_TYPE *)data->raw_data_point[i])->SORT_CMP_DATA_NAME;
	}
	printf("\r\n");

	return ret;
}

定义缓存

  • 数据输入缓存
  • 数据输出缓存(不能和输入共用,用于接收排序后的结果)
  • 排序输入缓存(存储输入数据的地址)
  • 排序临时缓存
  • 归并排序句柄
static test_def input_data[ARR_MAX] = { 0 };
static test_def output_data[ARR_MAX] = { 0 };
static uint64_t merge_sort_raw_data[ARR_MAX] = { 0 };
static uint64_t merge_sort_temp_data[ARR_MAX] = { 0 };

static merge_sort_def merge_sort_data = { 0 };

初始化排序输入缓存

  • 获取输入数据数组的地址
for (uint64_t i = 0; i < ARR_SIZE(input_data, test_def); i++)
{
	merge_sort_raw_data[i] = (uint64_t)&input_data[i];
}

定义并初始化排序句柄

static merge_sort_def merge_sort_data = { 0 };
merge_sort_init(&merge_sort_data, ARR_SIZE(input_data, test_def), TRUE, \
	merge_sort_raw_data, merge_sort_temp_data, \
	&merge_compare, &merge_sort_output);

运行排序

merge_sort_run(&merge_sort_data);

获取结果

merge_sort_data.merge_sort_output(&merge_sort_data, (uint64_t *)output_data);

参考

图解排序算法(四)之归并排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值