首页 > 编程语言 >三种基本排序算法:桶排序,冒泡排序,快速排序

三种基本排序算法:桶排序,冒泡排序,快速排序

时间:2023-10-20 14:22:25浏览次数:23  
标签:数字 int 复杂度 冒泡排序 算法 排序 1000

第一节 桶排序 (最快最简单的排序)

1、概括

就实现申请大小为的数组为例,int a[11]。首先将所有变量初始化为0,表示还没有出现过任何数字。


下面开始处理得到的数字:

若存入的第一个数字是5,就将相对应的a[5]的值在原来的基础上增加1.即将a[5]的值从0改为1,表示5出现过一次。
若第二个数字是3,将相对应的a[3]的值在原来的基础上增加1,即a[3] = 1。
注意!如果下一个数字也是5,将a[5]的值在原来的基础上+1,即a[5]++;

以此类推,处理第四个数字 “2” 和第五个数字 “8” ,最终得到下面的图.

或者可以用插旗子更加直观一些

2、代码实现

// 排序1000以内的数字,降序输出结果
#include <stdio.h>
int main()
{
    int book[1001], i, j, t, n;

    for (i = 0; i <= 1000; i++)
    {
        book[i] = 0; // 将所有的元素初始化为0
    }

    printf("请输入元素个数:");
    scanf("%d", &n); // 输入一个数字n,表示接下来有n个数

    if (n < 0 || n > 1000)
    {
        printf("输入的 'n' 无效。应该在 0 到 1000 之间。\n");
        return 1; // 以错误代码退出程序。
    }

    printf("请输入 %d 个元素:\n", n);

    for (i = 1; i <= n; i++) // 循环读入n个数字,并且进行桶排序
    {
        scanf("%d", &t); // 将每个数读到变量t中

        if (t < 0 || t > 1000) // 错误检测
        {
            printf("输入的 't' 无效。应该在 0 到 1000 之间。\n");
            return 1; // 以错误代码退出程序。
        }

        book[t]++; // 进行计数,对编号为t的桶放一个“旗子”
    }

    // 降序排序
    for (i = 1000; i >= 0; i--) // 依次判断编号1000~1的桶
    {
        for (j = 1; j <= book[i]; j++) // 出现了几次小旗子就将桶的编号打印几次
        {
            printf("%d ", i);
        }
    }
    getchar();
    getchar(); // 暂停程序
    return 0;
}

如果要实现升序排序,只需要将

改为此即可

3、总结:

1、第一个for循环,循环了m次(桶的个数)。第二个for循环,循环了n次。第三个for循环,循环了m+n次。共循环了m+n+m+n次,即时间复杂度为O(2*(m+n)) -> O(M+N)。
2、浪费空间。必须根据数组的大小进行排序,如果我要排序10000和1,那就需要定义a[10001],数组太大,需要遍历到10000。上文只是简单介绍桶排序,真正的桶排序很复杂,解决了这个问题
3、局限性太大。现有3个人的名字和分数,张三:86分,李四:98,王五:68,请按照分数进行升序排序,打印结果 “王五,张三,李四”,但是桶排序只能排序出成绩,无法输出名字,我们无法知道排序后的分数原本对应的哪一个人。这该怎么办呢?请看下节,冒泡排序

第二节 冒泡排序

1、概括

冒泡排序的基本思想是:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。
冒泡排序是我大一接触的第一个算法,比较简单,直接给出例子吧。

2、代码展示:

#include <stdio.h>
int main()
{
    int a[100], i, j, n, t;
    scanf("%d", &n); // 输入需要排序的数字个数
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
    }
// 核心部分
    for (j = 1; j <= n - 1; j++) // 相邻对比
    {
        for (i = 1; i < n; i++)
        {
            if (a[i] < a[i + 1]) // 比较大小并转换
            {
                t = a[i]; 
                a[i] = a[i + 1];
                a[i + 1] = t;
            }
        }
    }

    for (i = 1; i <= n; i++) // 输出结果
    {
        printf("%d ", a[i]);
    }
    getchar();
    return 0;
}

运行结果如下:

将上面的代码稍加修改,就可以解决第一节遗留的问题了

#include <stdio.h>
struct student
{
    char name[21];
    int score;
}; // 创建结构体存储姓名和分数
int main()
{
    struct student a[100], t;
    int i, j, n;
    scanf("%d", &n); // 输入需要排序的数字个数
    for (i = 1; i <= n; i++)
    {
        scanf("%s %d", a[i].name,&a[i].score);
    }
    // 核心部分
    for (j = 1; j <= n - 1; j++) // 相邻对比
    {
        for (i = 1; i < n; i++)
        {
            if (a[i].score < a[i + 1].score) // 比较大小并转换
            {
                t = a[i];
                a[i] = a[i + 1];
                a[i + 1] = t;
            }
        }
    }

    for (i = 1; i <= n; i++) // 输出结果
    {
        printf("%s\n ", a[i].name);
    }
    getchar();
    return 0;
}

运行结果如下

3、总结:

1、冒泡排序的核心是双重循环嵌套。实践复杂度是O(N^2)。时间复杂度太高,不值得推荐。

第三节 快速排序(最常用的排序)

1、概括

快速排序是跳跃式的排序,通过设置基准点,将大于基准点的放在右侧,小于的放在左侧。
下图直观化表示:

2、代码展示

#include <stdio.h>

#define MAX_SIZE 101 // 定义数组最大大小

int arr[MAX_SIZE], num; // 定义全局数组和变量

void quicksort(int left, int right) {
    if (left > right) {
        return; // 处理边界条件,确保不会越界
    }

    int i = left, j = right, temp, pivot = arr[left]; // 选择第一个元素作为基准数

    while (i != j) {
        while (arr[j] >= pivot && i < j) j--; // 从右向左找比基准数小的元素
        while (arr[i] <= pivot && i < j) i++; // 从左向右找比基准数大的元素

        if (i < j) {
            temp = arr[i]; // 交换元素位置
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }

    arr[left] = arr[i]; // 将基准数归位
    arr[i] = pivot;

    quicksort(left, i - 1); // 递归调用,对左半部分排序
    quicksort(i + 1, right); // 递归调用,对右半部分排序
}

int main() {
    printf("请输入要排序的元素个数:");
    scanf("%d", &num); // 输入元素个数

    if (num < 0 || num > MAX_SIZE) {
        printf("输入的元素个数无效。请确保在 0 到 %d 之间。\n", MAX_SIZE);
        return 1; // 以错误代码退出程序
    }

    printf("请输入 %d 个元素:\n", num);

    for (int i = 1; i <= num; i++) {
        scanf("%d", &arr[i]); // 输入元素
    }

    quicksort(1, num); // 调用快速排序函数

    printf("快速排序的结果为:");
    for (int i = 1; i <= num; i++) {
        printf("%d ", arr[i]); // 输出排序结果
    }

    printf("\n");
    return 0;
}

运行结果展示

3、总结

1、快速排序的时间复杂度是不确定的,最差的结果是O(N^2),他的平均时间复杂度是O(NlogN)。
2、冒泡排序解决了桶排序浪费空间的问题,但是算法的执行效率牺牲了很多。而快速排序既不浪费空间,也可以快一点排序。

标签:数字,int,复杂度,冒泡排序,算法,排序,1000
From: https://www.cnblogs.com/yzx-sir/p/17776729.html

相关文章

  • 排序算法总结
    lowB三人组冒泡排序思想:列表相邻元素两两对比,每趟结束都会产生一个最大/最小元素代码实现defbubble_sort(li):foriinrange(0,len(li)-1):#趟数exchange=0#设置一个标识符,当有一趟无变化时,列表已有序,停止排序forjinrange(0,len(......
  • 数据结构之美:如何优化搜索和排序算法
    文章目录搜索算法的优化1.二分搜索2.哈希表排序算法的优化1.快速排序2.归并排序总结......
  • 文心一言 VS 讯飞星火 VS chatgpt (106)-- 算法导论10.1 4题
    四、用go语言,重写ENQUEUE和DEQUEUE的代码,使之能处理队列的下溢和上溢。文心一言:在Go语言中,我们可以使用切片来实现队列。下面是如何实现ENQUEUE和DEQUEUE操作,同时处理队列的下溢和上溢的情况:packagemainimport"fmt"typeQueuestruct{elements[]i......
  • 文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题
    三、用go语言,仿照图10-2,画图表示依次执行操作ENQUEUE(Q,4)、ENQUEUE(Q,1)、ENQUEUE(Q,3)、DEQUEUE(Q)、ENQUEUE(Q,8)和DEQUEUE(Q)每一步的结果,队列初始为空,存储于数组Q[1…6]中。文心一言:在这个问题中,我们尝试使用Go语言来模拟队列的操作,并且展示每一步的结果。首先,我们需要定义......
  • 文心一言 VS 讯飞星火 VS chatgpt (107)-- 算法导论10.1 5题
    五、用go语言,栈插入和删除元素只能在同一端进行,队列的插入操作和删除操作分别在两端进行,与它们不同的,有一种双端队列(deque),其插入和删除操作都可以在两端进行。写出4个时间均为O(1)的过程,分别实现在双端队列的两端插入和删除元素的操作,该队列是用一个数组实现的。文心一言:在Go......
  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    二、用go语言,说明如何在一个数组A[1…n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。要求PUSH和POP操作的运行时间为O(1)。文心一言:在这个问题中,我们要在一个数组A[1…n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。这......
  • 文心一言 VS 讯飞星火 VS chatgpt (103)-- 算法导论10.1 1题
    一、用go语言,仿照图10-1,画图表示依次执行操作PUSH(S,4)、PUSH(S,1)、PUSH(S,3)、POP(S)、PUSH(S,8)和POP(S)每一步的结果,栈S初始为空,存储于数组S[1…6]中。文心一言:图10-1展示了在执行一系列栈操作后栈的状态。我会用文字描述来模仿这个图,因为目前我无法直接绘制图片。栈S初始......
  • 10.20算法
    位1的个数编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为'1'的个数(也被称为汉明重量)。 提示:请注意,在某些语言(如Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号......
  • 智能优化算法第一次实验
    智能优化算法第一次实验一、实验目的(1)掌握梯度下降法的基础知识及其应用过程;(2)利用梯度下降法求解简单优化问题。二、实验原理梯度下降法是一种最优化算法,由于函数在该点梯度的模代表着函数值在该点最大的变化率,我们可以让函数沿着梯度方向迭代移动逼近函数最值,这就是梯......
  • [刷题笔记] [算法学习笔记]树上差分 -- Luogu P3128
    DescriptionProblem:https://www.luogu.com.cn/problem/P3128FJ给他的牛棚的\(N\)个隔间之间安装了\(N-1\)根管道,隔间编号从\(1\)到\(N\)。所有隔间都被管道连通了。FJ有\(K\)条运输牛奶的路线,第\(i\)条路线从隔间\(s_i\)运输到隔间\(t_i\)。一条运输路线会给......