0
点赞
收藏
分享

微信扫一扫

【数据结构和算法】:排序

写心之所想 2022-02-12 阅读 81

⭐️排序算法⭐️

📚最快最简单的排序算法——桶排序

🔐举个栗子:
期末考试完了老师要将同学们的分数按照从高到低排序。小哼的班上只有5个同学,这5个同学分别考了5分、3分、5分、2分和8分,哎考得真是惨不忍睹(满分是10分)。接下来将分数进行从大到小排序,排序后是85532。你有没有什么好方法编写一段程序,让计算机随机读入5个数然后将这5个数从大到小输出?

💡分析

首先我们需要申请一个大小为11的数组int a[11]。OK,现在你已经有了11个变量,编号从a[0] ~ a[10]。刚开始的时候,我们将a[0] ~ a[10]都初始化为0,表示这些分数还都没有人得过。例如 a[0]等于0就表示目前还没有人得过0分,同理a[1]等于0就表示目前还没有人得过1分……a[10]等于0就表示目前还没有人得过10分。
在这里插入图片描述
下面开始处理每一个人的分数,第一个人的分数是5分,我们就将相对应的a[5]的值在原来的基础增加1,即将a[5]的值从0改为1,表示5分出现过了一次。
在这里插入图片描述
同理第二个人的分数为3,我们就把相对应的 a[3]的值在原来的基础上增加1,即将a[3]的值从0改为1,表示3分出现过了一次。
在这里插入图片描述
注意此时第三个人的分数也是5分,所以 a[5]的值需要在此基础上再增加1,即将a[5]的值从1改为2,表示5分出现过了两次。
在这里插入图片描述
按照刚才的方法处理第四个和第五个人的分数。最终结果就是下面这个图啦。
在这里插入图片描述
你发现没有,a[0]~a[10]中的数值其实就是0分到10分每个分数出现的次数。接下来,我们只需要将出现过的分数打印出来就可以了,出现几次就打印几次,具体如下。

最终屏幕输出“23558”。
🔑Java代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int a[] =new int[11];
        int k;
        for(int i=0;i<=10;i++){
            a[i]=0; //初始化为0
        }
        for(int i=0;i<5;i++){ //读入五个数
            k=sc.nextInt(); //把每一个数读到变量k中
            a[k]++; //进行计数
        }
        for(int i=10;i>=0;i--){ //依次判断a[10]-a[0](题目要求从大到小输出)
            for(int j=i;a[j]>0;a[j]--){ //出现几次就打印几次
                System.out.print(i+" ");
            }
        }
    }
}
输入:
5 3 5 2 8
输出:
8 5 5 3 2 

📒时间复杂度

该算法的时间复杂度是O(m+n+m+n)即O(2*(m+n))。我们在说时间复杂度的时候可以忽略较小的常数,最终桶排序的时间复杂度为O(m+n)。还有一点,在表示时间复杂度的时候,n和m通常用大写字母即 O(M+N)。

📒说明

📒问题的引出:

📚冒泡排序

💡基本思想

冒泡排序的基本思想是:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。

💡思想分析

🔐举个栗子:
将12 35 99 18 76这5个数进行从大到小的排序。

🌱第一趟:
首先比较第1位和第2位的大小,现在第1位是12,第2位是35。发现12比35要小,因为我们希望越小越靠后嘛,因此需要交换这两个数的位置。交换之后这5个数的顺序是:
在这里插入图片描述
按照刚才的方法,继续比较第2位和第3位的大小,第2位是12,第3位是99。12比99要小,因此需要交换这两个数的位置。交换之后这5个数的顺序是:
在这里插入图片描述

根据刚才的规则,继续比较第3位和第4位的大小,如果第3位比第4位小,则交换位置。交换之后这5个数的顺序是:
在这里插入图片描述

最后,比较第4位和第5位。4次比较之后5个数的顺序是:
在这里插入图片描述

经过4次比较后我们发现最小的一个数已经就位(已经在最后一位,请注意12这个数的移动过程),是不是很神奇。现在再来回忆一下刚才比较的过程。每次都是比较相邻的两个数,如果后面的数比前面的数大,则交换这两个数的位置。一直比较下去直到最后两个数比较完毕后,最小的数就在最后一个了。就如同是一个气泡,一步一步往后“翻滚”,直到最后一位。所以这个排序的方法有一个很好听的名字“冒泡排序”。
在这里插入图片描述
下面我们将继续重复刚才的过程,将剩下的4个数一一归位。
🌱第二趟:
现在开始“第二趟”,目标是将第2小的数归位。首先还是先比较第1位和第2位,如果第1位比第2位小,则交换位置。交换之后这5个数的顺序是:
在这里插入图片描述
接下来你应该都会了,依次比较第⒉位和第3位,第3位和第4位。注意此时已经不需要再比较第4位和第5位。因为在第一趟结束后已经可以确定第5位上放的是最小的了。第二趟结束之后这5个数的顺序是:
在这里插入图片描述
🌱第三趟:
第三趟之后这5个数的顺序是:
在这里插入图片描述
🌱第四趟:
现在到了最后一趟“第四趟”。有的同学又要问了,这不是已经排好了吗?还要继续?当然,这里纯属巧合,你若用别的数试一试可能就不是了。

💡冒泡排序的原理

⭐️总结

如果有 n 个数进行排序,只需将n-1个数归位,也就是说要进行n-1趟操作。而“每一趟”都需要从第 1 位开始进行相邻两个数的比较,将较小的一个数放在后面,比较完毕后向后挪一位继续比较下面两个相邻数的大小,重复此步骤,直到最后一个尚未归位的数,已经归位的数则无需再进行比较(已经归位的数你还比较个啥?,浪费表情)。
🔑Java代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int[] a=new int[100];
        int n=sc.nextInt(); //输入一个数n,表示接下来有n个数
        int t;
        for(int i=1;i<=n;i++){ //循环读入n个数到数组a中
            a[i]=sc.nextInt();
        }
        //冒泡排序的核心部分
        for(int i=1;i<=n-1;i++){ //n个数排序,只用进行n-1趟
            for(int j=1;j<=n-i;j++){ //从第1位开始比较直到最后一个尚未归位的数,
                // 想一想为什么到n-i就可以了。
                if(a[j]<a[j+1]){ //比较大小并交换
                    t=a[j];
                    a[j]=a[j+1];
                    a[j+1]=t;
                }
            }
        }
        for(int i=1;i<=n;i++){ //输出结果
            System.out.print(a[i]+" ");
        }
    }
}

运行结果:

输入:
10
1 2 3 4 5 6 7 8 9 10
输出:
10 9 8 7 6 5 4 3 2 1 

现在我们就可以来解决之前桶排序留下的问题了

🔑代码如下:

import java.util.Scanner;

class Student{
    String name;
    int score;
}
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        Student[] s=new Student[100];
        for (int i = 0; i < 100; i++){
            s[i]=new Student(); //注意这一步,初始化每个数组
        }
        Student s2;
        int n=sc.nextInt();
        for(int i=0;i<n;i++){
            s[i].name=sc.next();
            s[i].score=sc.nextInt();
        }
        for(int i=0;i<n-1;i++){
            for(int j=0;j<n-i;j++){
                if(s[j].score<s[j+1].score){
                    s2=s[j];
                    s[j]=s[j+1];
                    s[j+1]=s2;
                }
            }
        }
        for(int i=0;i<n;i++){
            System.out.println(s[i].name);
        }
    }
}

运行结果:

输入:
5 
huhu 5 
haha 3 
xixi 5 
hengheng 2 
gaoshou 8
输出:
gaoshou
huhu
xixi
haha
hengheng

📒时间复杂度

冒泡排序的核心部分是双重嵌套循环。不难看出冒泡排序的时间复杂度是 O(N*N)。这是一个非常高的时间复杂度。

举报

相关推荐

0 条评论