排序算法之冒泡排序

来源:互联网 发布:java标准404页面设计 编辑:程序博客网 时间:2024/04/29 07:17

一.冒泡排序原理

      冒泡排序(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的随机序列。可以根据自己需要自由设定。

测试结果:



原创粉丝点击