c语言用冒泡排序模拟实现qsort排序

简介: c语言用冒泡排序模拟实现qsort排序

1、简单介绍冒泡排序


冒泡排序就是两两相邻元素进行比较,如果不满足顺序就进行交换。现有一组整数,将其用冒泡排序实现排序为升序。


假设有这样一组整数:9 8 7 6 5

82b85ab90e974a16b7d1540e7ae37e74.png

由此可知,如果一个整型数组有num个元素,则需走num-1趟,若走在第i趟,则在第i趟内需要比较num-1-i次。


#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
  int i = 0;
  //趟数
  for (i = 0; i < sz - 1; i++)
  {
    //一趟比较
    //两两相邻元素比较
    int j = 0;
    for (j = 0; j < sz - 1 - i; j++)
    {
      if (arr[j] > arr[j + 1])
      {
        arr[j] = arr[j + 1];
      }
    }
  }
}
int main()
{
  int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  bubble_sort(arr, sz);
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}



2、介绍qsort函数


void qsort(void* base, //指向了需要排序的数组的第一个元素
                 size_t num, //排序的元素个数
                size_t size,//一个元素的大小,单位是字节
                int (*cmp)(const void*, const void*)//函数指针类型 ,此函数指针指向的函数能够比较base指向数组中的两个元素
                );
int cmp (const void* p1, const void* p2);


该函数通过返回值来定义元素的顺序


返回值 意义
>0 p1指向的元素 在p2指向的元素之前
0 p1指向的元素等效于p2指向的元素
<0 p1指向的元素在p2指向的元素之后



void* 的指针是没有具体类型的指针,这类指针可以接受任意类型的地址,但是这类指针不能直接解引用操作,也不能直接进行指针运算。


qsort函数的特点:


             1、是快速排序的方法

               2、适用于任意类型数据的排序


3、用冒泡排序模拟实现qsort排序


将冒泡排序封装成函数,如上buttle_sort(),则此函数需传递同类型的参数且参数个数相等:void buttle_sort(void* base,rsize_t num,size_t size,int(*cmp)(const void*,const void*)),由于传递的数据类型不确定,则比较的方法和交换数据的方法有所不同,故可以使用函数来封装比较和交换的方法,由于冒泡排序函数buttle_sort传递的是首元素的地址,

a9637b09c15e45989e0f0784ee8fe6e1.png


若想比较并交换两个元素就需要元素的地址,故比较函数和交换函数传递的参数都为元素地址,

8a060436144e4dcea9726f21ce518eb4.png


由于传递参数的类型不确定,那么元素的大小也无法确定,int类型的指针通过首元素地址加其所对应下标即为其地址,而void*类型指针无法直接进行指针运算,需将其类型强制转换,冒泡排序函数buttle_sort传递size为元素的字节个数,char为最小字节的类型,可以用来比较任意类型的数据,故将(void*)base强制转化为(char*)base,故void*类型的指针可通过(char*)base + j * size,(char*)base+(j+1)*size来解引用比较相邻元素的大小,故比较函数为cmp((char*)base + j * size,(char*)base+(j+1)*size),交换函数为swp((char*)base + j * size, (char*)base + (j + 1) * size,size),就有了如下函数的代码


//交换
void swp(char* butt1, char* butt2,int size)
{
  int i = 0;
  for(i; i < size; i++)
  {
    char temp = *butt1;
    *butt1 = *butt2;
    *butt2 = temp;
    butt1++;
    butt2++;
  }
}
//冒泡排序所有类型数据
void buttle_sort(void* base,rsize_t num,size_t size,int(*cmp)(const void*,const void*))
{
  int i = 0;
  //趟数,需要n-1趟
  for (i; i < num - 1; i++)
  {
    int j = 0;
    //每趟比较次数
    for (j; j < num - 1 - i; j++)
    {
      //比较,若按升序排列,cmp返回值需>0
      if (cmp((char*)base + j * size,(char*)base+(j+1)*size)>0)
      {
        //交换
        swp((char*)base + j * size, (char*)base + (j + 1) * size,size);
      }
    }
  }
}


比较函数的具体实现因数据类型不同而不同,故比较函数由操。作方即调用函数的一方来书写实现过程。


测试1


#include<stdio.h>
//整型比较
int cmp_int(const void* p1 ,const void* p2 )
{
    return (*(int*)p1 - *(int*)p2);
}
void test1()//qsort测试整形数据
{
    int a[10] = { 2,1,3,0,5,7,4,9,6,8 };
    int num = sizeof(a) / sizeof(a[0]);
    buttle_sort(a, num, sizeof(a[0]), cmp_int);
    int i = 0;
    for (i; i < num; i++)
    {
        printf("%d \n",a[i]);
    }
}
int main()
{
    test1();
    return 0;
}


测试结果:

bb3e9324573d479dbe1c47f169d4206a.png


测试2


#include<stdio.h>
#include<string.h>
struct Stu
{
    char name[20];
    int age;
};
//结构体通过名字比较
int cmp_struct_by_name(const void* p1, const void* p2)
{
    return strcmp((struct Stu*)p1->name, (struct Stu*)p2)->name;
}
void test2()//qsort测试结构体数据
{
    struct Stu stu[3] = { {"zhangsan",20},{"lisi",50},{"wangwu",15} };
    int num = sizeof(stu) / sizeof(stu[0]);
    buttle_sort(stu, num, sizeof(stu[0]), cmp_struct_by_name);
    int i = 0;
    for (i; i < num; i++)
    {
        printf("%s %d\n", stu[i].name, stu[i]age);
    }
}
int main()
{
    test2();
    return 0;
}


测试结果:

11dad36133b5414db4fde44527506d18.png


测试3


#include<stdio.h>
struct Stu
{
    char name[20];
    int age;
};
//结构体通过年龄比较
int cmp_struct_by_age(const void* p1, const void* p2)
{
    return  ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void test3()//qsort测试结构体数据
{
    struct Stu stu[3] = { {"zhangsan",20},{"lisi",50},{"wangwu",15} };
    int num = sizeof(stu) / sizeof(stu[0]);
    buttle_sort(stu, num, sizeof(stu[0]), cmp_struct_by_age);
    int i = 0;
    for (i; i < num; i++)
    {
        printf("%s %d\n",stu[i].name,stu[i]age);
    }
}
int main()
{
    test3();
    return 0;
}


测试结果:

7d1c3d06abd2496ea32cabbc34caceb9.png


目录
相关文章
|
1月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
79 8
|
1月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
77 7
|
2月前
|
算法 C语言
【C语言】排序查找
【C语言】排序查找
|
2月前
|
算法 搜索推荐 C语言
【C语言】冒泡排序+优化版
【C语言】冒泡排序+优化版
|
2月前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
25 2
|
2月前
|
C语言
【c语言】qsort函数及泛型冒泡排序的模拟实现
本文介绍了C语言中的`qsort`函数及其背后的回调函数概念。`qsort`函数用于对任意类型的数据进行排序,其核心在于通过函数指针调用用户自定义的比较函数。文章还详细讲解了如何实现一个泛型冒泡排序,包括比较函数、交换函数和排序函数的编写,并展示了完整的代码示例。最后,通过实际运行验证了排序的正确性,展示了泛型编程的优势。
23 0
|
2月前
|
NoSQL 算法 Redis
Redis的实现三:c语言实现平衡二叉树,通过平衡二叉树实现排序集
本博客介绍了如何在C语言中实现一个平衡二叉树,并通过这个数据结构来模拟Redis中的排序集功能。
16 0
|
2月前
|
搜索推荐 C语言
深入浅出理解 C 语言中的 qsort 函数
深入浅出理解 C 语言中的 qsort 函数
|
5月前
|
搜索推荐 C语言
C语言冒泡排序(附源码和动态图)
冒泡排序是一种简单的排序算法,其基本思想是通过重复遍历待排序的数列,比较每对相邻元素的值,如果它们的顺序错误(即满足一定的排序条件,如从小到大排序时前一个元素大于后一个元素),就交换它们的位置。这个过程就像水底的气泡一样逐渐向上冒,因此得名“冒泡排序”。
|
搜索推荐 C语言
【C语言】使用回调函数通过冒泡排序模拟实现qsort函数
【C语言】使用回调函数通过冒泡排序模拟实现qsort函数
【C语言】使用回调函数通过冒泡排序模拟实现qsort函数