C语言实现程序分层(使用回调函数(冒泡排序算法举例))

了解更多知识请点我:学习C语言之路(汇总篇)


手把手教你使用回调函数(冒泡排序算法举例)

总体思路

  • 字节交换
  • 比较函数
  • 冒泡算法

冒泡函数基本要素

1.字节交换函数

 void byte_swap(void *pData1, void *pData2, size_t stSize) 
{ 
    unsigned char *pcData1 = pData1; 
    unsigned char *pcData2 = pData2; 
    unsigned char ucTemp; 
    
        while (stSize--){ 
            ucTemp = *pcData1; *pcData1 = *pcData2; *pcData2 = ucTemp; 
            pcData1++; pcData2++; 
        } 
} 

2.3种比较函数

int compare_int(const void * e1, const void * e2)   //大 
{ 
    return *(int *)e1 - *(int *)e2; 
} 
int compare_int_r(const void * e1, const void * e2) //小 
{ 
    return *(int *)e2 - *(int *)e1 ; 
} 

int compare_str(const void * e1, const void *e2) //比较字符串大小 
{ 
    return strcmp(*(char **)e1, *(char **)e2); 
} 
  • 说明:由于我们这边定义的类型是void * 所有我们首先将(int )e1.ps:e1先强制转化为指向int 类型的指指针。然后在使用取该地址的值 retrun 输入两个参数的比较值,如果值为正数,说明e1 大于e2 ,反之则小于。
    还有一个疑问为什么要加const呢???
    忘了说了 哈哈哈 这边加const 相当于修饰一个常量的指针,修饰的内容在函数中无法进行修改。
    那什么是常量呢???
    举例
    int a[2] = {0x31,0x32};
    const int *c =a ; // 这是合法的,
    非法的是对c的使用
    *c =2 ; // 非法,但可以这样修改c指向的对象的值:a[0] = 2; !!! 错误 常量无法修改

  • 还有字符串的比较,(char **) 这边为什么会有两个 **,额…忘了说了
    我这边后面定义的是一个char * arrayStr[] = { “Sunday”,“Monday”,“Tuesday”,“Wednesday”,“Thursday”,“Friday”,“Saturday” };
    因为arrayStr[0]的类型是的指向char * 的地址,不是“Sunday”,那我这边怎么取“Sunday”地址呢,&arrayStr[0] 就是再取一次地址 这次的数据类型就相当于char ** arryStr取两次地址。

3.冒泡算法函数

void bubbleSort(void * base, size_t nmemb, size_t size, COMPARE compare) 
{ 
    int hasSwap=1; 
    int i;
    int j;
    for ( i = 0; hasSwap&&i < nmemb - 1; i++)          // 大循环
		{ 
       		 hasSwap = 0; //判断条件是否成立
       		 for ( j = 0; j < nmemb - 1-i; j++)        //小循环
			{ 
		        void *pThis = ((unsigned char *)base) + size*j; 
           	 	void *pNext = ((unsigned char *)base) + size*(j+1); 
           	 	
            	if (compare(pThis, pNext) > 0) 
				{ 
	                hasSwap = 1;   // 
	                byte_swap(pThis, pNext, size); 
            	} 
    	} 
}

来来来 ,相比大家上面看有点晕,哈哈,那就再来点猛料!!!(不是一家人,不进一家门)

参数介绍

  • 参数一:void * base,这边这边是要接受所有类型的数据,所以这边第一个参数要为 void *类型 ,允许支持不同类型的数据比较排序。

  • 参数二:很关键,就是比较的数据的总个数,举例int arrayInt[] = { 39, 33, 18, 64, 73, 30, 49, 51, 81 };那这个时候,我们可以使用sizeof(arrayInt)/ sizeof(arrayInt[0])
    (ps :sizeof实际上是获取了数据在内存中所占用的存储空间,以字节为单位来计数。)
    举例
    int a=10; int arr=[1,2,3]; sizeof(a) = 4; sizeof(arr) = 12 ;

  • 参数三:每元素的数据类型 可以使用sizeof(arr[0]);

  • 参数四:回调函数,也是该函数最重要的设计点,它的数据类型为COMPARE (int (*)(const void * e1, const void * e2))。

逻辑介绍

先看第一个for循环,定义了一个hasSwap标志位作为判断有什么用意呢? 后面我们再讲。进入第二个for,这个for循环总共巡行(nmenb-1-i)次(原因在于n个数据对比,只要对比n-1次就好了 ,吧不信你自己试),这段代码最核心的函数为compare函数,它决定了排序的走势,假如它是升序,那在这次循环后,最大的一位将排序最后,
举例定义一个数组

  • 小循环执行一次后 ,执行次数为8次,将最大的数据81排到了最后一位
  • int arrayInt[] = { 39, 33, 18, 64, 73, 30, 49, 51, 81 };
  • hasSwap = 1; 再执行大循环 ,i =1
  • 小循环第二次,执行次数为7次,将73数据排到倒数第二位
  • int arrayInt[] = { 39, 33, 18, 64,30, 49, 51, 73,81 };
  • 如此循环

全部代码

#include<stdio.h>
#include<string.h> 
#include<stddef.h>

typedef int(*COMPARE)(const void * e1, const void *e2); 

void byte_swap(void *pData1, void *pData2, size_t stSize) 
{ 
    unsigned char *pcData1 = pData1; 
    unsigned char *pcData2 = pData2; 
    unsigned char ucTemp; 
    
        while (stSize--){ 
            ucTemp = *pcData1; *pcData1 = *pcData2; *pcData2 = ucTemp; 
            pcData1++; pcData2++; 
        } 
} 

//   bubbleSort(arrayInt, numArray, sizeof(arrayInt[0]), compare_int); 

void bubbleSort(void * base, size_t nmemb, size_t size, COMPARE compare) 
{ 
    int hasSwap=1; 
    int i;
    int j;
    for ( i = 0; hasSwap&&i < nmemb - 1; i++)   //带入循环9次 
		{ 
       		 hasSwap = 0; //判断条件是否成立
       		 
       		 for ( j = 0; j < nmemb - 1-i; j++) 
			{ 
		        void *pThis = ((unsigned char *)base) + size*j; 
           	 	void *pNext = ((unsigned char *)base) + size*(j+1); 
           	 	
            	if (compare(pThis, pNext) > 0) 
				{ 
	                hasSwap = 1;   // 
	                byte_swap(pThis, pNext, size); 
            	} 
			}
        	
    	} 
}

int compare_int(const void * e1, const void * e2)   //大 
{ 
    return *(int *)e1 - *(int *)e2; 
} 
int compare_int_r(const void * e1, const void * e2) //小 
{ 
    return *(int *)e2 - *(int *)e1 ; 
} 

int compare_str(const void * e1, const void *e2) //比较字符串大小 
{ 
    return strcmp(*(char **)e1, *(char **)e2); 
} 

void main() 
{ 
    int arrayInt[] = { 39, 33, 18, 64, 73, 30, 49, 51, 81 }; 
    
    int numArray = sizeof(arrayInt) / sizeof(arrayInt[0]); 
    int i;
    ////// 从小到大 
    bubbleSort(arrayInt, numArray, sizeof(arrayInt[0]), compare_int); 
    for ( i = 0; i <numArray; i++) { 
        printf("%d ", arrayInt[i]); 
    } 
    printf("\n"); 
    ////// 从大到小 
    bubbleSort(arrayInt, numArray, sizeof(arrayInt[0]), compare_int_r); 
    for ( i = 0; i <numArray; i++) { 
        printf("%d ", arrayInt[i]); 
    } 
    printf("\n");
    char * arrayStr[] = { "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" }; 
    numArray = sizeof(arrayStr) / sizeof(arrayStr[0]); 
    bubbleSort(arrayStr, numArray, sizeof(arrayStr[0]), compare_str); 
    
    for ( i = 0; i < numArray; i++) 
	{ 
        printf("%s\n", arrayStr[i]); 
    } 
}

调试结果

在这里插入图片描述

重点来了–回调函数—介绍

在这里插入图片描述

  • 上层模块为mian() 和compara_int

    扫描二维码关注公众号,回复: 11411785 查看本文章
  • 下层模块为bubbleSort () 。

  • 链路说明如下:上层mian()将(arrayStr, numArray, sizeof(arrayStr[0]), compare_str)等参数给bubbleSor() 。bubbleSor()回调compara_int ()函数,达到上层A调用下层B,B执行的过程中又将信息返回给上层模块。而对于上层模块,上层模块compara_int 不仅监视下层bubbleSor() ,还干预了bubbleSor()的运行,本职上是上层模块调用下层模块实现是分层的思想

设计分层思想总结

  • 分层设计:就是将软件按照某种上级级的关系进行分层,每隔层之间通过API接口进行调用。
    硬件驱动层:顾名思义,就是和硬件打交道最密切的部分,举例:显示器、蜂鸣器等
    虚拟层:它是根据需求进行划分
    应用层:直接用于功能实现。人机交互。
    基于分层架构有一下优点:1降低系统复杂度,2隔离变化,3有利于测试,4可移植性。

介绍一个原则:好莱坞原则(Hollywood),下层不能调用上层的函数,层和层之间不能循环调用。不要调用我,让我调用你

猜你喜欢

转载自blog.csdn.net/qq_38179373/article/details/107464386
今日推荐