目录

qsort()函数的功能:

首先回忆一下冒泡排序是如何实现的

需要改动的地方:

compare():

swap():

qosrt()函数实现

快速排序实现qsort()已经成功


今天我要分享的是qsort的自主实现。

冒泡版qsort()(标准是用的快速排序,好吧,我还没想到怎么准确实现)

qsort()函数的功能:

qsort()函数能将一个数组的元素进行排序。

作用:

Remarks

The qsort function implements a quick-sort algorithm to sort an array of num elements, each of width bytes. The argument base is a pointer to the base of the array to be sorted.qsort overwrites this array with the sorted elements. The argument compare is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. qsort calls the compare routine one or more times during the sort, passing pointers to two array elements on each call:

翻译:

评论

qsort函数实现了一种快速排序算法,可以对num元素数组进行排序,每个元素的宽度为字节。参数base是指向要排序的数组的基的指针。qsort用已排序的元素覆盖此数组。参数compare是指向用户提供的例程的指针,该例程比较两个数组元素,并返回一个指定其关系的值。qsort在排序过程中调用比较例程一次或多次,每次调用时将指针传递到两个数组元素:

简单来说就是排序,但是你要自己写一个比较大小的函数。

注意:这个函数的函数指针的类型为 int (*)(const void *, const void * );

如果不知道函数指针就别管这个了(以后我会出一篇详解指针文章)。

先看一下qsort函数的类型(带参数名字)

可复制:

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

由于qsort只是让待排序数组排序,所以不必设置返回值,返回类型为空。base是传入的首元素地址,void*说明它可以接收任意类型的地址;num是待排数组的元素个数,size_t是unsigned int类型的重定义类型,其实就是unsigned int(上一篇文章提到了),元素个数不可能是负数,所以用的是无符号类型;width是数组每一个元素的所占空间的大小;int (__cdecl *compare )(const void *elem1, const void *elem2 ) 是一个函数指针(不知道函数指针也没事,看案例就可明白)。

先看一下标准qsort函数的应用:

#include<stdio.h>
#include<stdlib.h>
int compare1(const void* e1, const void* e2)
{return (int)(*(int*)e1 - *(int*)e2);
}int main(void)
{int arr[5] = { 2,4,3,1,0 };int i = 0;int j = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}int len = sizeof(arr) / sizeof(arr[0]);printf("\n======================\n");qsort(arr, len, sizeof(int), compare1);for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}

运行结果:

自主实现(利用冒泡排序):

首先回忆一下冒泡排序是如何实现的

 for (i = 0; i < len - 1; i++){for (j = 0; j < len - 1 - i; j++){if (arr[j] > arr[j + 1]){int t = arr[j];arr[j] = arr[j + 1];arr[j + 1] = t;}}}

我们就以这个为基础来实现,

需要改动的地方:

一:if的判断条件。

二:if里面需要设立一个函数实现数组元素的交换。

这里用两个函数,if的判断条件用compare()函数的返回值来加以修饰来作为判断条件,而swap()函数作为交换两个元素的函数。

于是我们可以改写为:

以每个元素为int类型的数组为例:compare()函数是是自己设置的,目的是比较两个元素的大小。我们先实现这个函数的实现。

compare():

因为我们需要对待排数组排序,所以我们应该知道待排数组的每个元素的类型是什么,以int类型为例:

(int*)e1是把e1前置类型转换为int*类型,而*(int*)e1是对强制类型转换后的e1解引用,就是取出元素的值,那么*(int*)e1 - *(int*)e2就是两个元素相减,有人可能会问了,这个结果不就是int类型吗,为什么还要对最终结果强制类型转换为int?因为我想以后编写其他类型的元素的数组方便。一会换其他类型的实例就很容易明白(升序是e1在前,降序是e1在后,主要是返回的结果与0比较)。

判断条件:

compare(前一个元素, 后一个元素) > 0

因为我们是用冒泡排序的思想,传入的是相邻前后的元素,这个函数的返回值如果大于0那么就交换。

swap():

swap()需要交换的元素类型是未知的,所以用void*类型来接收,但是如果写成void*我们怎么对元素进行交换呢?我们学过的最小类型是char一个字节,数据的是以字节为单位在计算机里存储的,那么我们有一个思路,我们可以先把void*强制类型转换为char*类型,一个字节一个字节的进行交换。但是我们还要知道每个元素占用多少字节,即交换几个字节,要做到恰好两个元素每个字节都交换,所以我们要传入一个元素所占用字节数,我们可以用传入qsort()的形参width作为swap()的一个实参,代表一个元素的所占字节数。

那么swap()函数就可以这样实现:

void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}

char* c1, char* c2表示我们直接把传进来元素的地址以char*类型进行操作。

现在我们的代码大概可以写出

for (i = 0; i < num - 1; i++)
    {
        for (j = 0; j < num - 1 - i; j++)
        {
            if (前一个元素, 后一个元素) > 0)
            {
                swap(前一个元素, 后一个元素, width);
            }
        }
    }

现在我们有了一种思想,char*类型可以解决我们遇到的问题。

所以copare()和swap()传入数组元素的地址怎么传入合理呢?

答案是先转换为char*类型在利用j和width寻找代操作元素。

用compare()举例:

compare((char*)base + j * width, (char*)base + (j + 1) * width)

(char*)base + j * width 的含义是先以char*找到base地址,然后移动j*width个char类型距离,这里就相当于base[j],但是不能用base[j]直接访问,因为传入base是未知的类型,不可直接访问base的某个元素

那么(char*)base + (j + 1) * width就相当于base[j + 1]。

所以我们可以写出swap()函数的传参

swap((char*)base + j * width, (char*)base + (j + 1) * width, width)

qosrt()函数实现

void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}void my_qsort(void* base, size_t num, size_t width,int(__cdecl* compare)(const void* e1, const void* e2))
{assert(base);int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}

看一下成果:

示例一(int):

#include<stdio.h>
#include<assert.h>
int compare1(const void* e1, const void* e2)
{return (int)(*(int*)e1 - *(int*)e2);
}void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}
void my_qsort(void* base, size_t num, size_t width,int(__cdecl* compare)(const void* e1, const void* e2))
{assert(base);//防止传入空指针,保证代码的健壮性int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}int main(void)
{int arr[5] = { 2,4,3,1,0 };int i = 0;int j = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}printf("\n======================\n");int len1 = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, len1, sizeof(int), compare1);for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}

运行结果:

示例二(char):

#include<stdio.h>
#include<assert.h>
#include<string.h>
int compare2(const void* e1, const void* e2)
{return (int)(*(char*)e1 - *(char*)e2);
}void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}void my_qsort(void* base, size_t num, size_t width,int(__cdecl* compare)(const void* e1, const void* e2))
{assert(base);//防止传入空指针,保证代码的健壮性int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}int main(void)
{char ch[5] = "adxb";int i = 0;int j = 0;printf("%s", ch);printf("\n======================\n");int len2 = strlen(ch);my_qsort(ch, len2, sizeof(char), compare2);printf("%s", ch);return 0;
}

运行结果:

示例三(double):

#include<stdio.h>
#include<assert.h>
int compare3(const void* e1, const void* e2)
{return (int)(*(double*)e1 - *(double*)e2);
}void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}void my_qsort(void* base, size_t num, size_t width,int(__cdecl* compare)(const void* e1, const void* e2))
{assert(base);//防止传入空指针,保证代码的健壮性int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}int main(void)
{double dd[5] = { 0.2, 0.3, 5.0, 0.1, -10.2 };int i = 0;int j = 0;for (i = 0; i < 5; i++){printf("%lf ", dd[i]);}printf("\n======================\n");int len3 = sizeof(dd) / sizeof(dd[0]);my_qsort(dd, len3, sizeof(double), compare3);for (i = 0; i < 5; i++){printf("%lf ", dd[i]);}return 0;
}

运行结果:

实例四(结构体):

#include<stdio.h>
#include<assert.h>typedef struct Student
{char name[10];double scores;
} Student;int compare4(const void* e1, const void* e2)
{return (int)(((Student*)e1)->scores - ((Student*)e2)->scores);
}void swap(char* c1, char* c2, int len)
{int i = 0;for (i = 0; i < len; i++){char t = *(c1 + i);*(c1 + i) = *(c2 + i);*(c2 + i) = t;}
}void my_qsort(void* base, size_t num, size_t width,int(__cdecl* compare)(const void* e1, const void* e2))
{assert(base);//防止传入空指针,保证代码的健壮性int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}int main(void)
{Student s[5] = { {"张三", 10}, {"李四", 0}, {"王五", 100}, {"乌龟", 0.5}, {"兔子", -20} };int i = 0;int j = 0;for (i = 0; i < 5; i++){printf("%-6s%lf\n", s[i].name, s[i].scores);}printf("\n======================\n");int len4 = sizeof(s) / sizeof(s[0]);my_qsort(s, len4, sizeof(s[0]), compare4);for (i = 0; i < 5; i++){printf("%-6s%lf\n", s[i].name, s[i].scores);}return 0;
}

运行结果:

这篇文章本来还想这再用快速排序来实现,但是没实现~~~,我会努力让它实现的!

要多记录一下写的代码了,伙伴们的支持是我最大的动力。

快速排序实现qsort()已经成功

qosrt()快速排序自主实现_逆风路上伴有谁的博客-CSDN博客

qsort的自主实现相关推荐

  1. C语言qsort快速排序函数详解

    直接进入主题,在c语言中qsort函数是用来快速排序的,qsort有4个参数,分别是数组地址,数组元素个数,数组元素字节大小和一个比较数组元素的函数指针.让我来看一下官方给出的使用标准,上图: 让我们 ...

  2. 2022-2028年中国自主可控行业深度调研及投资前景预测报告(全卷)

    [报告类型]产业研究 [报告价格]¥4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国自主可控行业市场行业相关概述.中国自主 ...

  3. 自主数据类型:在TVM中启用自定义数据类型探索

    自主数据类型:在TVM中启用自定义数据类型探索 介绍 在设计加速器时,一个重要的决定是如何在硬件中近似地表示实数.这个问题有一个长期的行业标准解决方案:IEEE 754浮点标准.1.然而,当试图通过构 ...

  4. 初具雏形的UL标准侧重于自主车辆的安全性

    初具雏形的UL标准侧重于自主车辆的安全性 Nascent UL standard focuses on autonomous vehicle safety 就任何自主汽车(AV)的安全性进行可信的争论 ...

  5. 跟踪自主车辆软件平台

    跟踪自主车辆软件平台 Tracking autonomous vehicle software platforms 全世界--包括影音产业和媒体--都承认,通往4级和5级自动驾驶汽车的道路仍然漫长而曲 ...

  6. 中国人工智能AI框架自主研发

    中国人工智能AI框架自主研发 中国AI界争相构建AI开源框架的背后,技术和业务层面的考量因素当然重要,但也不应忽视国家层面的政策支持.对于AI基础设施的建设,中国政府在<新一代人工智能发展规划& ...

  7. Waymo的自主进化

    Waymo的自主进化 3月初,Waymo在推特上宣布,共获得了22.5亿美元(约合人民币156亿元)融资,由Silver Lake(银湖资本).Canada Pension Plan Investme ...

  8. Udacity机器人软件工程师课程笔记(五)-样本搜索和找回-基于漫游者号模拟器-自主驾驶

    9.自主驾驶 在接下来的环节中,我们要实现漫游者号的自动驾驶功能. 完成这个功能我们需要四个程序,第一个为感知程序,其对摄像头输入的图片进行变换处理和坐标变换使用.第二个程序为决策程序,功能是帮助漫游 ...

  9. 对应到对象 数据库驼峰_【GI的自主空间数据库】一种竞争力,叫技术引领;一种竞争力,叫时间沉淀...

    引子:GI的自主空间数据库及GIS框架来自于求学时MAPGIS的引导,工作时ARCGIS的追随,读博时IBM和Microsoft2篇文献....即使在大数据技术发展的今天,自主空间数据库存储仍然有其技 ...

最新文章

  1. SAP SD基础知识之交货单不完全日志
  2. 英特尔宣布全新自动驾驶平台整合处理器和视觉芯片
  3. Workout Wednesday Redux (2017 Week 3)
  4. 搭建Angular2环境
  5. html导航栏代码跳转,微信小程序自定义底部导航栏tabBar(含跳转页面wx.navigateTo)...
  6. 怎样修改iis 服务器日期,怎么在IIS里设置服务器端缓存时间?
  7. JS Number对象常用函数(数字类型常用函数)
  8. Centos 7编译安装 LAMP 环境
  9. 小米(MIUI)系统组招聘职位
  10. 2018年11月26日 练习3
  11. 8位数控分频器的设计_数控分频器的设计实验报告
  12. Child returned status 1问题解决
  13. 《西部世界》会成真吗? 人类如何避免被机器人干掉的未来?
  14. 线性代数中自由变量为什么取0和1?
  15. lizzieyzy使用智星云GPU算力
  16. 台式计算机电源线 规格,台式电脑电源线怎么接
  17. iphonex中全屏h5的适配
  18. ubuntu20安装gcc_Ubuntu:软件常用安装方法(附WPS安装)
  19. chmod +x 与chmod 777的区别
  20. 在线教育项目02_前端知识(es6、vue)

热门文章

  1. Java二代身份证正则表达式分析
  2. 【黑苹果显卡驱动】通过Device/properties 给Framebuffer打补丁一点经验
  3. 奥林匹克计算机怎么学,信息学竞赛金牌教练带你C++入门!
  4. 开源SPL消灭数以万计的数据库中间表
  5. String a =new String(“abc”);和String b=”abc”;的区别
  6. Proteus:单片机锁存器控制数码管亮灭
  7. Unity 按键控制相机(移动、旋转、相机角度控制)
  8. 【一步步一起学DApp开发】(四)web3.js 基本使用 | 连接geth | 创建web客户端
  9. 因果分析,PC算法(PC Algorithm)
  10. 防火墙策略规则 查看防火墙开通端口以及操作命令