C语言 用递归实现快速排序

执行结果截图:

 

 执行过程展示:

 

 

 

 

 

 代码:

/* 快速排序算法的基本思想是:
* 通过一趟排序将待排序数据分割成独立的两部分,
* 其中一部分的所有元素均比另一部分的元素小,
* 然后分别对这两部分继续进行排序,重复上述步骤直到排序完成。
*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"

// 如去掉对define DEBUG的注释符,则显示调试信息
#define DEBUG
// 如激活undef DEBUG,且注释掉define DEBUG,则禁止显示调试信息
// #undef DEBUG
// ##这个连接符号充当的作用就是当__VA_ARGS__为空的时候,消除前面的那个逗号,
// 这样当只输入一个参数的时候也能执行,编译依然不会报错
# define PRINT(format, ...) printf(# format, ##__VA_ARGS__)
// # define PRINTF(templt, ...) fprintf(stderr, templt, ##__VA_ARGS__)

static int DebugPrintf(const char * format, ...);

static int DebugPrintf(const char * format, ...)
{
// 如果定义了插桩调试宏DEBUG,则
#ifdef DEBUG
// fprintf(stderr, "%s %s [%d]: ", __FILE__, __FUNCTION__, __LINE__);
va_list argPtr;
int count;
// 获取可变参数列表
va_start(argPtr, format);
// 强制刷新输出缓冲区
fflush(stdout);
// 将信息输出到标准出错流设备
count = vfprintf(stderr, format, argPtr);
// 可变参数列表结束
va_end(argPtr);
#else
// 如果未定义插桩调试宏,则运行空函数体
do {

} while(0);
#endif
}

/* debugTab的值代表不同标签:
* 0代表quick_sort(array, left, right, debugTab)被调用,
* 1代表quick_sort(array, left, j, debugTab)的递归调用,
* 2代表quick_sort(array, i, right, debugTab)的递归调用,
*/
// 定义递归函数quick_sort,用于对整型数组所有元素进行左小右大的排序
// 注意:左边界left和右边界right和递归函数标记debugTab会随着再次递归调用的输入参数变化而变化
void quick_sort(int array[], int left, int right, int debugTab)
{
// quick_sort(int array[], int left, int right, int debugTab)的调用次数统计
static int debugFirstCount = 0;
// quick_sort(array, left, j, debugTab)的递归调用次数计数
static int debugLeftCount = 0;
// quick_sort(array, i, right, debugTab)的递归调用次数计数
static int debugRightCount = 0;
// quick_sort(int array[], int left, int right, int debugTab)的第几层调用结束
static int debugFirstEndCount = 0;
// quick_sort(array, left, j, debugTab)的第几层递归结束
static int debugLeftEndCount = 0;
// quick_sort(array, i, right, debugTab)的第几层递归结束
static int debugRightEndCount = 0;

// 定义数组边界变量i和j并初始化为数组左边界和右边界
int i = left, j = right;
int temp;
int pivot;

if (1 == debugTab)
{
DebugPrintf("<<<<<Recursion of Left<<<<<The %d times loading quick_sort(array, last left=%d, last j=%d, debugTab=%d)...\n", ++debugLeftCount, left, right, debugTab);
}
else if (2 == debugTab)
{
DebugPrintf(">>>>>Recursion of Right>>>>>The %d times loading quick_sort(array, last i=%d, last right=%d, debugTab=%d)...\n", ++debugRightCount, left, right, debugTab);
}
else if (0 == debugTab)
{
DebugPrintf("The %d time loading quick_sort(int array, left=%d, right=%d, int debugTab=%d)....\n", ++debugFirstCount, left, right, debugTab);
}
DebugPrintf("Assigned i = left = %d j = right = %d\n", left, right);

DebugPrintf("\nNow the very array elements for sorting:");
for (int k = 0; k < (right - left) + 1; k++)
{
DebugPrintf("%3d ", array[k + left]);
}
DebugPrintf("\n\n");

// 将排在数组中间位置的元素的值赋值给pivot,(left +right) / 2)会被array自动取整
pivot = array[(left + right) / 2];
// 监控(left + right) / 2 的值非整数的情况
DebugPrintf("(left + right) / 2 is:%f\npivot -> array[%d]:%d\n", (float) (left + right) / 2, (int) (left + right) / 2, pivot);

// 只要数组第i个元素当前位置不是排在第j个元素的右边,就继续执行下去,否则排序结束
while ( i <= j)
{
DebugPrintf("--------------------- Because i=%d <= j=%d, starting sort... ---------------------\n", i, j);
// 从左到右找到第一个大于等于基准点的元素
while (array[i] < pivot)
{
DebugPrintf("Because array[%d]=%d < pivot=%d, ", i, array[i], pivot);
i++;
DebugPrintf("operated i++ for checking next array[%d], now i:%d\n", i, i);
}
DebugPrintf("Founded array[%d]=%d >= (pivot=%d)\n", i, array[i], pivot);
// 从右到左找到第一个小于等于基准点的元素
while (array[j] > pivot)
{
DebugPrintf("Because array[%d]=%d > pivot=%d, ", j, array[j], pivot);
j--;
DebugPrintf("operated j-- for checking next array[%d], now j:%d\n", j, j);
}
DebugPrintf("Founded array[%d]=%d <= (pivot=%d)\n", j, array[j], pivot);
// 只要数组的第i个元素不是排在第j个元素的右边,就将这两个数组元素互换一下位置, 如果第i个元素就是第j个元素,那也要迭代一次以满足结束迭代的条件
if (i <= j)
{
DebugPrintf("Because (i=%d) <= (j=%d), so exchanging array[%d]and array[%d]...\n", i, j, i, j);
// DebugPrintf("Before exchange, array[%d]:%d\n", i, array[i]);
// DebugPrintf("Before exchange, array[%d]:%d\n", j, array[j]);
temp = array[i];
array[i] = array[j];
array[j] = temp;
DebugPrintf("\nAfter exchange, array[%d]:%d array[%d]:%d\n\n", i, array[i], j, array[j]);

DebugPrintf("Now the very array elements for sorting changed to:");
for (int k = 0; k < (right - left) + 1; k++) {
DebugPrintf("%3d ", array[k + left]);
}
DebugPrintf("\n\n");

i++;
DebugPrintf("Operated i++ for checking next array[%d], now i:%d\n", i, i);
j--;
DebugPrintf("Operated j-- for checking next array[%d], now j:%d\n", j, j);
}
}

/* 设置左边界递归和结束条件:
* 只要数组左边界的位置排在数组元素j的左边,就执行左边界递归
* 否则结束左边界递归
*/
if(left < j)
{
// 执行左边界递归,这时array[j]以右的元素不会在左边界递归时被再次排序
// 随着递归的嵌套,left与j的差越来越小,要解决的排序问题的范围也就越来越收敛直到消失
DebugPrintf("Because left=%d < j=%d, loading quick_sort(array, left, j, debugTab=1)...\n", left, j);
quick_sort(array, left, j, 1);
DebugPrintf("finished checking if need further recursion of quick_sort(array, left, j, debugTab=1)\n");
}
if (1 == debugTab)
{
DebugPrintf("Now still in quick_sort(array, left, j, debugTab).\n");
}
else if(2 == debugTab)
{
DebugPrintf("Now still in quick_sort(array, i, right, debugTab).\n");
}

/* 设置右边界递归和结束条件:
* 只要数组元素i的位置排在数组右边界的左边,就执行右边界递归
* 否则结束右边界递归
*/
if(i < right)
{
// 执行右边界递归,这时array[i]以左的元素不会在左边界递归时被再次排序
// 随着递归的嵌套,i与right的差越来越小,要解决的排序问题的范围也就越来越收敛直到消失
DebugPrintf("Because i=%d < right=%d, loading quick_sort(array, i, right, debugTab=2)\n", i, right);
quick_sort(array, i, right, 2);
DebugPrintf("finished checking if need further recursion of quick_sort(array, i, right, debugTab=2)\n");
}
if (1 == debugTab)
{
DebugPrintf("Now still in quick_sort(array, left, j, debugTab).\n");
}
else if(2 == debugTab)
{
DebugPrintf("Now still in quick_sort(array, i, right, debugTab).\n");
}

DebugPrintf("Finished checking if any further recursion required\n");

switch(debugTab)
{
default :
DebugPrintf("Error!!!-> wrong debugTab value:%d", debugTab);
exit(1);
break;
case 2 :
DebugPrintf("Because i=%d > j=%d, the %d times ended recursion of quick_sort(array, i, right, debugTab=%d) \n", i, j, ++debugRightEndCount, debugTab);
break;
case 1 :
DebugPrintf("Because i=%d > j=%d, the %d times ended recursion of quick_sort(array, left, j, debugTab=%d)\n", i, j, ++debugLeftEndCount, debugTab);
break;
case 0 :
DebugPrintf("Because i=%d > j=%d, the %d times ended invoking of quick_sort(int array[], int left, int right, int debugTab=%d)\n", i, j, ++debugFirstEndCount, debugTab);
break;
}
}

int main(void)
{
int * ptr_array = NULL;
// const int array[] = {73, 108, 111, 118, 101, 70, 105, 115, 104, 67, 46, 99, 111, 109};
const int array[] = {100,55,33,11,22,66};
// const int array[] = {88,66,22};
// const int array[] = {200,100};
// const int array[] = {9};
int i, arrayLength;

do {
arrayLength = sizeof(array) / sizeof(array[0]);
DebugPrintf("arrayLength: %d\n", arrayLength);

ptr_array = (int *)malloc(arrayLength);
if (NULL == ptr_array)
{
DebugPrintf("Error:动态内存分配失败\n");
exit(1);
}
DebugPrintf("ptr_array -> %p\n", ptr_array);

PRINT(\n打印原始数组并将其拷贝到动态内存空间:\n);
for (i = 0; i < arrayLength; i++)
{
PRINT(%6d, array[i]);
}
PRINT(\n);

memcpy(ptr_array, array, arrayLength*sizeof(int));

PRINT(在动态内存空间对以下数组元素进行由左至右由小到大的排序:\n);
for (i = 0; i < arrayLength; i++)
{
PRINT(%6d, * (ptr_array + i));
}
PRINT(\n);

quick_sort(ptr_array, 0, arrayLength - 1, 0);

PRINT(排序后的结果是:\n);
for (i = 0; i < arrayLength; i++)
{
PRINT(%6d, * (ptr_array + i));
}
PRINT(\n);
} while(0);

free(ptr_array);

DebugPrintf("动态内存空间已释放,动态内存空间的当前数据如下:\n");
for (i = 0; i < arrayLength; i++)
{
DebugPrintf("%20d", * (ptr_array + i));
}
DebugPrintf("\n");
PRINT(\n);

ptr_array = NULL;
if(NULL == ptr_array)
{
DebugPrintf("free(ptr_array)后,要将动态内存指针设为NULL,现在ptr_array: NULL\n");
}
else
{
DebugPrintf("Warning!!! pointer ptr_array is not NULL\n");
}

return 0;
}
posted @   JohnnyH  阅读(651)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示