冒泡排序的快速排序——qsort函数的模拟实现

简介: 冒泡排序的快速排序——qsort函数的模拟实现

上一期我们留下了一个题目:

判断一个字符串是否是另一个字符串左旋后的字符:

其实我们只要将原字符串用memcpy加到原字符串的后面构成一个新的字符串,只要你给出的字符串在这个新的字符串里面(用strstr函数),那么他就是这个字符串左旋后的字符串

例如:BCDA如果在下面的这个字符串中,所以是左旋后的字符串

冒泡排序

首先我们来了解一下在不使用qsort函数下的冒泡排序代码:

这里的第一个循环的目的是要对这个数组进行排序的次数

而第二个循环就是这一趟排序要比较的数字的个数

假如size等于10

按规律来就是第一趟要将第一个元素比较其他的9个元素进行比较

但是第二趟就只需要8个,以此进行减一操作

因为下标是从零开始,所以j的范围是小于size-i-1,而不是小于等于

void Bubble_sort(int arr[], int size)
{
  int j,i,tem;
  for (i = 0; i < size-1;i ++)
  {
    int count = 0;
    for (j = 0; j < size-1 - i; j++)  
    {
      if (arr[j] > arr[j+1])
      {
        tem = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = tem;
        count = 1;
      }
    }
    if (count == 0)
        break;  
  }
}

qsort函数

下面我们来了解一下qsort函数:

推荐大家一个网站,用来了解不懂的函数,可以去里面搜索它的用法

https://cplusplus.com/

为了方便理解,我将其转为中文进行讲解:

可以看到,qsort的函数用法如下:

一共需要四个元素,第一个base就是你要排序的数组

num就是base的元素个数

size是base一个元素的大小,单位是字节

而(compar)(const void,const void*))就是一个函数指针了

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

关于这个函数指针,cplusplus上面也有相对应的解释:

他是用于比较两个元素的一个函数的指针

如果他返回的值小于0,就是p1小于p2

等于0就是p1等于p2,大于0就是p1大于p2

所以,qsort函数就是直接将base里的所有元素进行快速的冒泡排序,也可以是字符型,而我们此前写的冒泡排序只是针对于整形数据的。

qsort函数的模拟实现

下面我们将进行qsort函数的模拟实现

首先,我们要知道,qsort函数就是基于冒泡排序的,所以,我们先构建一个基本的冒泡排序框架:

void bubble_sqort(void* arr, int sz, int size, int(*cmp)(const void*, const void*))
{
  int i = 0;
  int j = 0;
  int* tmp = (int*)arr;
  for (i = 0; i < sz; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
        ...........
    }
  }
}

这个大家都知道吧,就和上面的冒泡排序的一样,就是循环内部的语句不一样,下面我们对for循环里面的执行语句展开分析:

我们知道,要进行排序就是要进行比较然后再进行位置的交换呗,并且qsort函数的cmp函数就是判断元素的大小关系的,所以我们就可以展开构思:

注意,排序是将其进行升序处理

if (cmp(x, y > 0)
      {
             ..............
      }

当cmp的返回值大于0是,就是x大于y,我们就要将x和y在数组中的位置进行调换,这个时候我们就可以写一个交换函数:

这里我们将其要比较的元素强制类型转换成为字符型,因为如果我们要比较的是字符型的话就可以直接比较,而且当要比较整形的时候也不影响,因为我们是一个字节一个字节的比较,所以引入了元素字节的大小size

void swap(char* buf1, char* buf2, int size)
{
  int i = 0;
  for (i = 0; i < size; i++)
  {
    char temp = *buf1;
    *buf1 = *buf2;
    *buf2 = temp;
    buf1++;
    buf2++;
  }
}

我们将其放入:

if (cmp((char*)arr + j * size, (char*)arr + (j + 1) * size) > 0)
//我们将j*size+上arr的地址就是第j个元素的的地址,即下标为j的元素的地址
{
  swap((char*)arr + j * size, (char*)arr + (j + 1) * size, size);
}

然后我们开始写cmp函数

我们回想qsort函数的定义,里面的cmp函数的定义就可以很容易的构造出这个函数:

如果是整形就是如下代码

int cmp_int(const void* x, const void* y)
{
  return *((int*)x) - *((int*)y);
}

同理我们可以利用strcmp函数得出字符型的cmp函数:

我们用网站查一查

写出这个cmp_char

int cmp_char(const void* x, const void* y)
{
  return strcmp((char*)x, (char*)y);
}

整体代码如下:

void swap(char* buf1, char* buf2, int size)
{
  int i = 0;
  for (i = 0; i < size; i++)
  {
    char temp = *buf1;
    *buf1 = *buf2;
    *buf2 = temp;
    buf1++;
    buf2++;
  }
}
int cmp_int(const void* x, const void* y)
{
  return *((int*)x) - *((int*)y);
}
int cmp_char(const void* x, const void* y)
{
  return strcmp((char*)x, (char*)y);
}
void bubble_sqort(void* arr, int sz, int size, int(*cmp)(const void*, const void*))
{
  int i = 0;
  int j = 0;
  int* tmp = (int*)arr;
  for (i = 0; i < sz; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (cmp_int((char*)arr + j * size, (char*)arr + (j + 1) * size) > 0)
      {
        swap((char*)arr + j * size, (char*)arr + (j + 1) * size, size);
      }
    }
  }
}

针对于具体的情况,我写了一个针对于结构体的的具体题目,大家可以试着参考:

struct stu
{
  char name[20];
  int age;
};
void swap(char* buf1, char* buf2, int size)
{
  int i = 0;
  for (i = 0; i < size; i++)
  {
    char temp = *buf1;
    *buf1 = *buf2;
    *buf2 = temp;
    buf1++;
    buf2++;
  }
}
int cmp_int(const void* x, const void* y)
{
  return *((int*)x) - *((int*)y);
}
void bubble_sqort(void* arr, int sz, int size, int(*cmp)(const void*, const void*))
{
  int i = 0;
  int j = 0;
  int* tmp = (int*)arr;
  for (i = 0; i < sz; i++)
  {
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (cmp((char*)arr + j * size, (char*)arr + (j + 1) * size) > 0)
      {
        swap((char*)arr + j * size, (char*)arr + (j + 1) * size, size);
      }
    }
  }
}
int cmp_stu_by_age(const void* x, const void* y)
{
  return (((struct stu*)x)->age - ((struct stu*)y)->age);
}
int cmp_stu_by_name(const void* x, const void* y)
{
  return strcmp(((struct stu*)x)->name, ((struct stu*)y)->name);
}
void test1()
{
  int arr[] = { 2,4,11,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sqort(arr, sz, sizeof(arr[0]), cmp_int);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
}
void test2()
{
  struct stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",50} };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sqort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i].age);
  }
}
void test3()
{
  struct stu arr[3] = { {"zhangsan",20},{"lisi",30},{"wangwu",50} };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sqort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
  for (int i = 0; i < sz; i++)
  {
    printf("%s ", arr[i].name);
  }
}
int main()
{
  //test1();
  test3();
  return 0;
}

好了,今天的分享就到这了,谢谢大家的支持!

相关文章
|
SQL 移动开发 算法
MySQL 8.0.23 Hypergraph Join Optimizer代码详解
MySQL Join MySQL本身没有常规意义上的执行计划,一般情况就是通过JOIN和QEP_TAB这两个结构组成。QEP_TAB 的全称是Query Execution Plan Table,这个“Table“可以是物理表、内存表、常量表、子查询的结果表等等。作为整个单独JOIN执行计划载体之前还承担着整个执行路径的调用和流转,但是从8.0.20后,全面的生成了独立的
2207 0
MySQL 8.0.23 Hypergraph Join Optimizer代码详解
|
Kubernetes Java 调度
无需接入执行器,0 代码改造实现微服务任务调度
本文提出了一种基于云原生的任务调度新方案,不需要依赖SDK,不依赖语言,实现定时调度和分布式跑批。
701 86
|
3月前
|
人工智能 安全 Linux
终端AI编程利器Claude Code:百炼平台本土化完整接入与实战指南
Claude Code是Anthropic官方打造的命令行原生AI编程助手,主打轻量化无界面运行、完整全工程代码理解、自动化重构调试、超大项目解析能力。凭借优秀的长上下文代码理解能力、较低的幻觉输出表现、端到端工程处理能力,在全球开发者群体中获得广泛应用,成为终端场景主流AI编程工具。但原生海外版本会遇到网络访问不稳定、海外调用成本高昂、模型选择单一等现实阻碍,很大程度上制约国内开发者日常高频使用。
442 0
|
3月前
|
人工智能 架构师 安全
【AI时代软件项目管理系列】2. 从工具到数字员工:AI 在项目团队中的角色演进
AI 正从个人助手演进为能够规划、调用工具并完成任务的 Agent,进一步形成多 Agent 协作与软件工厂。角色变化带来的不只是效率提升,更是团队结构、任务分配、进度衡量和质量管理方式的重构。项目经理需要把模型、Agent、知识库和自动化流程纳入统一管理,通过明确任务契约、权限边界、质量门禁与人工验收,确保 AI 执行可控、结果可验证、责任可追溯。
381 0
|
4月前
|
人工智能 算法 数据可视化
告别单轮静态测评!WorldForge 多动态环境基准,量化 Agent 组件协同能力
WorldForge是开源动态Agent评测框架,首创情绪耗竭、意义危机、快速衰减三类可控压力环境,支持多轮交互鲁棒性量化评估。适配ModelScope大模型,提供标准化动作空间、WS综合评分及四大基线Agent,助力算法研究与工业落地。
|
11月前
|
人工智能 搜索推荐 数据可视化
不只是作品集:用 Next.js 打造我的数字作品库
这篇文章介绍了作者使用Next.js和Shadcn UI构建的一个个人作品信息展示模板。该模板设计简洁且结构清晰,适合直接使用或作为学习参考。作者在原有基础上进行了个性化调整,增加了交互细节和动画效果。文章还强调了开发者拥有一个统一技术身份的重要性,并详细列出了项目的技术栈、特性和环境变量配置,最后提供了在线预览链接和GitHub地址。
533 1
|
安全 算法 API
手机号码“二次放号”查询:帮助更清晰地识别号码历史(开启“免打扰模式”)
“二次放号”带来资源优化的同时,也引发用户注册受限、骚扰电话频仍、误标记及“背锅”等问题。通过“二次放号状态核验API”,可精准识别号码性质、生命周期与实时状态,助力企业提升平台安全、降低运营风险,推动智慧城市数字身份建设。
1198 0
|
人工智能 数据可视化 数据挖掘
【产品】G 端产品经理
G端产品经理在政府数字化转型中扮演着关键角色,连接政府需求与技术实现。他们负责挖掘需求、规划方案、推动跨部门协作,并监督项目进展。具体职责包括需求调研、产品规划与设计、原型制作、文档撰写及交互与视觉设计等。面对复杂多变的需求、快速更新的技术和严格的项目验收,G端产品经理需不断提升专业技能,以适应挑战并推动政府治理体系现代化。
635 10
|
人工智能 数据可视化 程序员
精心整理自学python的宝藏网站,不看亏死
精心整理自学python的宝藏网站,不看亏死
2965 4
精心整理自学python的宝藏网站,不看亏死