直接选择排序和冒泡排序

直接选择排序和冒泡排序

一.直接选择排序(Straight Selection Sort)

1、直接选择排序的基本思想

n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:
 
①初始状态: 无序区为R[1…n],有序区为空。
②第1趟排序
 在无序区R[1…n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1…1]和R[2…n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
  ……
③第i趟排序
  第i趟排序开始时,当前有序区和无序区分别为R[1…i-1]和Ri…n。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1…i]和R[i+1…n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
 这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

2.代码实现:

import java.util.Arrays;
public class SortTest {
    public static void main(String[] args) {
        // 定义需要升序排序的数组arr
        int [] arr={8,4,15,2,1};
        // 对数组升序排序
        for (int i = 0; i < arr.length - 1; i++) {
            int  min = i;
            // 找出第i个元素之后最小值的索引
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) {
                    min = j;
                }
            }
            // 交换最小值
            if (min != i) {
                int tmp = arr[min];
                arr[min] = arr[i];
                arr[i] = tmp;
            }
        }
        // 输出排序后的数组,使用java.util.Arrays包下的Arrays类调用toString方法可以打印数组元素
        System.out.println(Arrays.toString(arr));
    }
}

输出结果:

[1, 2, 4, 8, 15]

排序过程:

原始数组:8 4 15 2 1
第一次排序结果:1 4 15 2 8。排好了第1位。
第二次排序结果:1 2 15 4 8。排好了第2位。
第三次排序结果:1 2 4 15 8。排好了第3位。
第四次排序结果:1 2 4 8 15。排好了第4位。

3.直接选择排序de稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,
若经过排序,这些记录的相对次序保持不变,
即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,
则称这种排序算法是稳定的;否则称为不稳定的。

所以选择排序是一个不稳定的排序算法

4.时间复杂度分析

第一次内循环比较N - 1次,然后是N-2次,N-3次,……,最后一次内循环比较1次。
共比较的次数是 (N - 1) + (N - 2) + … + 1,求等差数列和,得 (N - 1 + 1)* N / 2 = N^2 / 2。
舍去最高项系数,其时间复杂度为 O(N^2)。

虽然选择排序和冒泡排序的时间复杂度一样,但实际上,选择排序进行的交换操作很少,最多会发生 N - 1次交换。
而冒泡排序最坏的情况下要发生N^2 /2交换操作。从这个意义上讲,交换排序的性能略优于冒泡排序。
而且,交换排序比冒泡排序的思想更加直观。

5.例题:使用直接选择排序(按升序)对给定的数组排序,并输出每次排序结果以及排序完成后的数组,具体要求如下

接收给定的数据(如:4 88 43 43 98 #…,其中第一个数代表数组长度,其余数代表数组元素,# 号用于终止接收数据),遇到 # 号终止接收;
创建数组,使用直接选择排序(按升序)对给定的数组排序,并输出每次排序结果以及排序完成后的数组。

注意:数字分隔符为空格。
import java.util.Scanner;
import java.util.Arrays;

public class SortTest {
    public static void main(String[] args) {
        // 请在Begin-End间编写代码
        /********** Begin **********/
        // 接收给定数据
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // 定义数组
        int a[] = new int [n];
        // 给数组赋值
        for(int i=0;i<n;i++){
            a[i]=input.nextInt();
        }
        // 使用直接选择排序法对数组升序排序,并输出每次排序的结果
        int count=0;
        for(int i=0;i<a.length-1;i++){
            int min =i;
            for(int j=i+1;j<a.length;j++){
                if(a[min]>a[j]){
                    min = j;                    
                }
            }
            if(min!=i){
                int t = a[min];
                a[min]=a[i];
                a[i]=t;              
            }
            count++;
            System.out.println("第"+count+"次排序:"+Arrays.toString(a));
        }
        // 输出排序后的数组
        System.out.println("排序后的结果为:"+Arrays.toString(a));
        /********** End **********/
    }
}

测试输入:9 1 6 53 54 2 89 54 90 21 #

—— 预期输出 ——
第1次排序:[1, 6, 53, 54, 2, 89, 54, 90, 21]
第2次排序:[1, 2, 53, 54, 6, 89, 54, 90, 21]
第3次排序:[1, 2, 6, 54, 53, 89, 54, 90, 21]
第4次排序:[1, 2, 6, 21, 53, 89, 54, 90, 54]
第5次排序:[1, 2, 6, 21, 53, 89, 54, 90, 54]
第6次排序:[1, 2, 6, 21, 53, 54, 89, 90, 54]
第7次排序:[1, 2, 6, 21, 53, 54, 54, 90, 89]
第8次排序:[1, 2, 6, 21, 53, 54, 54, 89, 90]
排序后的结果为:[1, 2, 6, 21, 53, 54, 54, 89, 90]

二.冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法。它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

1.冒泡排序算法的原理如下:

1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。 
2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 
3.针对所有的元素重复以上的步骤,除了最后一个。 
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 

2.代码实现:

import java.util.Arrays;
public class SortTest {
    public static void main(String[] args) {
        // 定义需要升序排序的数组arr
        int [] arr={8,4,15,2,1};
        // 对数组升序排序
        for(int i =0;i<arr.length-1;i++) {       // 外循环为排序趟数,n个数进行n-1趟
     
            for(int j=0;j<arr.length-1-i;j++) {    //内循环为每趟比较的次数,第i趟比较n-i次
                if(arr[j]>arr[j+1]) {       //相邻元素比较,若逆序则交换(升序为左大于右,降序反之)
                    int temp = arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
        // 输出排序后的数组,使用java.util.Arrays包下的Arrays类调用toString方法可以打印数组元素
        System.out.println(Arrays.toString(arr));
    }
}

输出结果:

[1, 2, 4, 8, 15]

排序过程:

原始数组:8 4 15 2 1
第一次排序结果:4 8 2 1 15。排好了最后1位。
第二次排序结果:4 2 1 8 15。排好了倒数第2位。
第三次排序结果:2 1 4 8 15。排好了倒数第3位。
第四次排序结果:1 2 4 8 15。排好了倒数第4位。

3.冒泡排序算法稳定性

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

4.时间复杂度

冒泡排序最好的时间复杂度为O(n)
冒泡排序的最坏时间复杂度为O(n²)

综上,因此冒泡排序总的平均时间复杂度为 O(n²)

三.直接选择排序和冒泡排序的优缺点

1.冒泡排序

优点是比较简单,空间复杂度较低,是稳定的;缺点是时间复杂度太高,效率慢。

2.选择排序

优点是一轮比较只需要换一次位置;缺点是效率慢,不稳定。

四.总结:

数组全部输出

可以使用java.util.Arrays包下的Arrays类调用toString方法可以打印数组元素 System.out.println(Arrays.toString(arr));

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
直接选择排序冒泡排序是两种常见的排序算法,它们的实现方式有一些区别。 直接选择排序的实现思路是,首先将待排序序列中的最小元素找出,并与序列的第一个元素交换位置;然后在剩下的元素中找出最小元素,并与序列的第二个元素交换位置;以此类推,直到整个序列有序。其代码实现如下: ```python def selection_sort(arr): n = len(arr) for i in range(n): min_index = i for j in range(i+1, n): if arr[j] < arr[min_index]: min_index = j arr[i], arr[min_index] = arr[min_index], arr[i] return arr ``` 冒泡排序的实现思路是,通过相邻元素的比较和交换,将最大的元素逐渐"冒泡"到序列的末尾。具体地,从第一个元素开始,依次比较相邻的两个元素,如果它们的顺序不对,则交换它们的位置;一轮比较下来,最大的元素就会被交换到序列的最后一个位置。然后再从第一个元素开始进行下一轮比较,直到整个序列有序。其代码实现如下: ```python def bubble_sort(arr): n = len(arr) for i in range(n-1): for j in range(n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr ``` 可以看到,直接选择排序冒泡排序的代码实现上有一些区别: - 在直接选择排序中,每一轮循环都会找到最小元素的索引,然后与当前位置进行交换,而冒泡排序中则是通过相邻元素的比较和交换来逐渐将最大元素"冒泡"到末尾。 - 直接选择排序的外层循环是从第一个元素开始,冒泡排序的外层循环是从第一个元素到倒数第二个元素。 - 直接选择排序的内层循环是从外层循环的下一个元素开始,冒泡排序的内层循环是从第一个元素开始,并且每一轮循环都会比较到当前未排序元素的前一个位置。 总的来说,直接选择排序冒泡排序都是基于比较和交换的排序算法,它们的区别在于具体的实现方式和交换元素的时机。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

848698119

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值