排序算法之冒泡排序

本文介绍了冒泡排序的原理,通过实例展示了冒泡排序的过程,并针对冒泡排序进行了改进,减少了不必要的比较。此外,还介绍了如何使用C语言实现冒泡排序,并通过回调函数实现了通用性。同时,提出了测试模块的概念,用于统一测试不同排序算法的效率和正确性,以确保排序结果的升序排列。
摘要由CSDN通过智能技术生成

一.冒泡排序原理

      冒泡排序(Bubble Sort)应该是我们学习的第一个排序算法,因排序过程类似泡泡上浮或则下沉的形式所以叫冒泡排序。先看一个简单的实例整形数组排序:

int bubble_sort1(int* array, int nSize)
{
	int nIndex1 = 0;
	int nIndex2 = 0;

	RET_VAL_IF_FAIL(array != NULL && nSize > 1, -1)
	
	for(nIndex1 = 0; nIndex1 < nSize - 1; nIndex1++)
	{
		for(nIndex2 = 1; nIndex2 < nSize - nIndex1; nIndex2++)
		{
			if(array[nIndex2] < array[nIndex2 - 1])
			{
				int nTemp = array[nIndex2];
				array[nIndex2] = array[nIndex2 - 1];
				array[nIndex2 - 1] = nTemp;
			}
		}
	}
	return (0);
}
      外层nIndex < nSize - 1,因为最后一次冒泡只有一个元素,故可以取消此次冒泡。关于函数里面的RET_VAL_IF_FAIL宏后面会提到。

二.冒泡排序改进

     假设输入序列为:3,2,1,4,5,6.。可以得到第一次交换输出:2,3,1,4,5,6。第二次输出:2,1,3,4,5,6。此时nIndex2等于2,观察序列从3开始已经是有序了,第二次冒泡的时候只需要比较从0到nIndex2-1的位置即可。另外,当第二次冒泡的时候交换2和1的位置序列此时已经是升序,所以不需要再进行第三次冒泡。得到以下代码:

int bubble_sort2(int* array, int nSize)
{
	int nIndex = 0;
	int flag = nSize;
	int key = 0;

	RET_VAL_IF_FAIL(array != NULL && nSize > 1, -1)

	while(flag > 1)
	{
		for(nIndex = 1; nIndex < flag; nIndex++)
		{
			if(array[nIndex1] < array[nIndex - 1])
			{
				int nTemp = array[nIndex];
				array[nIndex] = array[nIndex - 1];
				array[nIndex - 1] = nTemp;
				key = nIndex;
			}
		}
		flag = key < flag-1 ? key : flag - 1;
	}
	
	return (0);
}

三.封装函数

      上面的代码基于输入序列为整形,通用算法不应该局限在具体的数据类型,对于具体操作的类型我们应该交给调用者来决定。C语言常用回调函数来隔离这类变化。我们得到以下代码:

int bubble_sort3(void** ppvArray, size_t nCount, SortCompaerFunc CompareFunc)
{
	int nKey = 0;
	int nIndex = 0;
	int nFlag = nCount;

	RET_VAL_IF_FAIL((ppvArray != NULL)  && (CompareFunc != NULL), SORT_ERR_INVALID_PARAM);

	if(nCount < 2)
	{
		return (SORT_ERR_OK);
	}

	while(nFlag > 1)
	{
		for(nIndex = 1; nIndex < nFlag; nIndex++)
		{
			if(CompareFunc(ppvArray[nIndex], ppvArray[nIndex - 1]) < 0)
			{
				void* pvTemp = ppvArray[nIndex];
				ppvArray[nIndex] = ppvArray[nIndex - 1];
				ppvArray[nIndex - 1] = pvTemp;
				nKey = nIndex;
			}
		}
		nFlag = nKey < nFlag-1 ? nKey : nFlag - 1;
	}
	
	return (SORT_ERR_OK);
}

四.代码测试

      排序算法有好几种,我们不可能为每个排序算法都各自写一个测试程序,当然也不是不可以,这里代码量并不多。更加提倡的做法是写一个小小的测试模块每种排序算法都通用。

定义错误码、比较回调函数原型、排序函数原型:

typedef int (*SortCompaerFunc)(void* pvParam1, void* pvParam2);

typedef int (*Sort_Func)(void** pvData, size_t nCount, SortCompaerFunc CompareFunc);

typedef enum tagSORT_ERR_E
{
    SORT_ERR_OK,
    SORT_ERR_OOM,
    SORT_ERR_FAIL,
    SORT_ERR_INVALID_PARAM
}SORT_ERR_E;

     这里比较函数只需要两个参数就可以了,由于不知道具体参数类型就设置为void*类型。排序函数原型也设定为固定形式:输入序列、序列长度和比较回调函数,返回值表示排序是否成功。

测试模块函数:

static void** dump_creat_sort_array(size_t nCount)
{
	int* pnNewArray = malloc(sizeof(int) * nCount);
	int nIndex = 0;

	for(nIndex = 0; nIndex < nCount; nIndex++)
	{
		pnNewArray[nIndex] = rand();
	}
	printf("\n");
	return ((void**)pnNewArray);
}


static void dump_sort_test(size_t nCount, Sort_Func Sortfunc, SortCompaerFunc CompareFunc)
{
	int nIndex = 0;
	void **ppvArray = dump_creat_sort_array(nCount);
	
	Sortfunc(ppvArray, nCount, CompareFunc);
	printf("%d\n", nCount);
	for(nIndex = 1; nIndex < nCount; nIndex++)
	{
		assert(ppvArray[nIndex - 1] <= ppvArray[nIndex]);
	}
	printf("test ok\n");
	free(ppvArray);
	ppvArray = NULL;
}


void dump_sort(int nTimes, Sort_Func Sortfunc, SortCompaerFunc CompareFunc)
{
	int nIndex = 0;

	for(nIndex = 0; nIndex <= nTimes; nIndex++)
	{
		dump_sort_test(nIndex, Sortfunc, CompareFunc);
	}
}

      测试模块动态调用随机函数创建测试序列,这样可以保证测试样例足够均匀。如果我们想测试某个排序函数只需要把该函数传入测试模块,并提供比较回调函数和需要测试的数据长度即可。对于排序结果调用assert来判断前一个元素一定小于等于后一个元素(排序结果为升序)。

  测试冒泡排序:

int sort_compare_int(void* pvParam1, void* pvParam2)
{
	return ((int)pvParam1 > (int)pvParam2 ? 1 : -1);
}


int main(int argc, char** argv)
{
	dump_sort(20, bubble_sort, sort_compare_int);
	return (0);
}
      测试长度范围从0-20的随机序列。可以根据自己需要自由设定。

测试结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值