了解更多知识请点我:学习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++;
}
}
- 关于字节交换函数请参考该链接:用C写第一个交换函数swap&&升级版
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
-
下层模块为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),下层不能调用上层的函数,层和层之间不能循环调用。不要调用我,让我调用你
快速排序&二分法(使用库)
看完了冒泡排序法,紧接着介绍库函数中两个常用的排序函数
打开库函数stdlib.h,找到函数bsearch()、qsort()
函数功能以及参数介绍
bsearch()函数详解
void *bsearch( const void *key, const void *buf, size_t num, size_t size, int (*compare)
(const void *, const void *) );
- 参数一:const void *key 要查找的关键字。
- 参数二:*buf 要查找的数组。
- 参数三:num 指定数组中元素的数目。
- 参数四:size 每个元素的长(以字符为单位)
- 参数五:指向比较函数的指针
qsort()函数详解
_CRTIMP void __cdecl qsort(void*, size_t, size_t,int (*)(const void*, const void*));
- 参数一: base指向数组的起始地址,通常该位置传入的是一个数组名
- 参数二: num 指定数组中元素的数目。
- 参数三:size 每个元素的长(以字符为单位)
- 参数四:指向比较函数的指针
和冒泡算法相似点
void bubbleSort(void * base, size_t nmemb, size_t size, COMPARE compare)
大家一目了然,真的是一模一样。
函数使用
#include<stdio.h>
#include<string.h>
#include<stddef.h>
#include<stdlib.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 findValue = 39;
int numArray = sizeof(arrayInt) / sizeof(arrayInt[0]);
int i;
int *p;
// 从小到大
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");
//快速排序法
qsort(arrayInt, numArray, sizeof(arrayInt[0]), compare_int);
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]);
}
printf("\n");
qsort(arrayStr, numArray, sizeof(arrayStr[0]), compare_str);
for ( i = 0; i < numArray; i++)
{
printf("%s\n", arrayStr[i]);
}
p = (int *)bsearch(&findValue,arrayInt, numArray, sizeof(arrayInt[0]),compare_int);
if(p == NULL)
printf("没有找到");
else
printf("%x",p);
}