十大经典排序算法之冒泡排序(Bubble Sort)、选择排序(Selection Sort)

本文详细介绍了排序算法中的冒泡排序和选择排序,包括它们的基本原理、优化方法以及时间复杂度。冒泡排序通过不断交换相邻元素实现排序,优化版减少了不必要的比较。选择排序则分别寻找最小或最大元素与首位或末位交换,其交换次数少于冒泡排序。两者均为原地排序算法,空间复杂度为O(1),但选择排序在平均情况下性能优于冒泡排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、十大排序算法

在这里插入图片描述

  • 冒泡、选择、插入、归并、快速、希尔、堆排序,属于比较排序(Comparison Sorting)

二、冒泡排序(Bubble Sort)

  • 冒泡排序也叫做起泡排序
  • 执行流程
    ①、从头开始比较每一对相邻元素,如果第一个比第二个大,就交换它们的位置。
    执行完一轮后,最末尾那个元素就是最大的元素。
    ②、忽略①中曾经找到的最大元素,重复执行步骤①、直到全部元素有序。

在这里插入图片描述

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] array = {10,9,19,28,37,56,34};

        for (int end = array.length-1; 0 < end; end--) {
            for (int begin = 1; begin <= end; begin++) {
                if (array[begin] < array[begin - 1]){
                    int tmp = array[begin];
                    array[begin] = array[begin-1];
                    array[begin-1] = tmp;
                }
            }
        }
        System.out.println(Arrays.toString(array));
    }
}

(1)冒泡排序 — 优化①

  • 如果序列已经完全有序,可以提前终止冒泡排序。但是如果序列不是有序的,那么耗费的时间比上面还要多。
    在这里插入图片描述
  • 设置一个标志boolean sorted = true;如果sorted = true指的是序列是有序的,没有进行数值交换的for循环(内嵌的for循环),这样最外层的循环不用执行,提高效率。
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] array = {10,9,19,28,37,56,34};
        for (int end = array.length-1; 0 < end; end--) {
            boolean sorted = true;//假设每一次扫描之前序列都是有序的
            for (int begin = 1; begin <= end; begin++) {
                if (array[begin] < array[begin - 1]){
                    int tmp = array[begin];
                    array[begin] = array[begin-1];
                    array[begin-1] = tmp;
                    sorted = false;//只要能够进来就表示不是有序的
                }
            }
            if (sorted) break;//sorted = true指的是序列是有序的,没有进行交换的for循环,这样最外层的循环不用执行,提高效率
        }
        System.out.println(Arrays.toString(array));
    }
}

(2)冒泡排序 — 优化②

  • 如果序列尾部已经局部有序,可以记录最后1次交换的位置,减少比较次数
    在这里插入图片描述
    对于上面的数据来说,最后面的几项数据都是有序的,并且还比前面的数据都大。那么我们只需要对前面杂乱的数据进行排序即可。
static void bubbleSort3(Integer[] array){
   for (int end = array.length-1; 0 < end; end--) {
        //sortedIndex的初始值在数组完全有序的时候有用
        int sortedIndex = 1;//记录从哪个索引开始就已经排好序
        for (int begin = 1; begin <= end; begin++) {
            if (array[begin] < array[begin - 1]){
                int tmp = array[begin];
                array[begin] = array[begin-1];
                array[begin-1] = tmp;

                sortedIndex = begin;//记录最后一次的交换的位置
            }
        }
        end = sortedIndex;
    }
}
  • 最坏、平均时间复杂度:O(n2)
  • 最好时间复杂度:O(n)
  • 空间复杂度:O(1)

三、排序算法的稳定性(Stability)

  • 如果相等的2个元素,在排序前后的相对位置保持不变,那么这是稳定的排序算法
  • 排序前:5,1, 3𝑎,4, 7, 3𝑏
  • 稳定的排序: 1,3𝑎, 3𝑏, 4, 5, 7
  • 不稳定的排序:1,3𝑏, 3𝑎, 4, 5,7
  • 对自定义对象进行排序时,稳定性会影响最终的排序效果
  • 冒泡排序属于稳定的排序算法
  • 稍有不慎,稳定的排序算法也能被写成不稳定的排序算法,比如下面的冒泡排序代码是不稳定的
    在这里插入图片描述

四、原地算法(In-place Algorithm)

  • 原地算法:
    ①、不依赖额外的资源或者依赖少数的额外的资源,仅依靠输出覆盖输入。
    ②、空间复杂度为O(1)的都可以认为是原地算法。
  • 非原地算法,称为Not-in-place或者Out-of-place
  • 冒泡排序属于In-place

五、选择排序(Selection Sort)

  • (1)执行流程:
    ①、从系列中找出最小的那个元素,然后与最前面的元素交换位置。
    执行完一轮后,最前面的那个元素就是最小的元素
    ②、忽略①中曾经找到的最小元素,重复执行步骤①

在这里插入图片描述

static void selectionSort1(Integer[] array){
   // 总共要经过 N-1 轮比较
    for (int i = 0; i < array.length - 1; i++) {
        int min = i;

        // 每轮需要比较的次数 N-i
        for (int j = i + 1; j < array.length; j++) {
            if (array[j] < array[min]) {
                // 记录目前能找到的最小值元素的下标
                min = j;
            }
        }

        // 将找到的最小值和i位置所在的值进行交换
        if (i != min) {
            int tmp = array[i];
            array[i] = array[min];
            array[min] = tmp;
        }
    }
}
  • (2)执行流程:
    ①、从系列中找出最大的那个元素,然后与最末尾的元素交换位置。
    执行完一轮后,最末尾的那个元素就是最大的元素
    ②、忽略①中曾经找到的最大元素,重复执行步骤①
static void selectionSort2(Integer[] array){
    for (int end = array.length-1; end > 0; end--) {
        int maxIndex = 0;
        for (int begin = 1; begin <= end; begin++) {
            if (array[maxIndex] <= array[begin]){
                maxIndex = begin;
            }
        }
        int tmp = array[maxIndex];
        array[maxIndex] = array[end];
        array[end] = tmp;
    }
}
  • 选择排序的交换次数要远远少于冒泡排序,平均性能优于冒泡排序
  • 最好、最坏、平均时间复杂度:O(n2),空间复杂度:O(1),属于不稳定排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值