算法与数据结构-冒泡/插入/选择排序

本文详细介绍了三种基本排序算法:冒泡排序、插入排序和选择排序,包括它们的时间复杂度、排序过程及Java代码实现。冒泡排序每次找出最大元素,插入排序模拟打牌插入过程,选择排序则是逐个找到最小元素放置。这些算法在数据量小时相对高效,但在大数据场景下效率较低。
摘要由CSDN通过智能技术生成

1.冒泡排序:

时间复杂度 :

O(N^2), 与数据原始排列状态无关(即使原始数组已经排列好了,也是需要进行相同次数的操作)。

过程:

依次找出最大, 次大…放在arr[arr.length-1],arr[arr.length-2]…

代码实现:

public static void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }

        for (int e = arr.length - 1; e > 0; e--) { // 0~e
            for (int i = 0; i < e; i++) {
                if (arr[i] > arr[i + 1]) {
                    swap(arr, i, i + 1);
                }
            }
        }
    }

private static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
}

2.插入排序:

时间复杂度 :

与数据原始排列状态有关:O(N)(如果原始数列已经排好序) O(N^2)(如果原始数列未排好序)

过程:

视为打牌时每抽一张牌插入到手上的牌堆中。
假设a=[7,6,5,8], 将其从小到大排列:

  1. 第0~0位[7]是有序的,无需交换, a=[7,6,5,8]
  2. 第0~1位[7,6]是无序的(因为将6和7进行比较,需要交换),交换完后a=[6,7,5,8], 此时第0~1位是有序的
  3. 第0~2位[6,7,5]是无序的(因为将5和7进行比较,需要交换), 交换完后a=[6,5,7,8]; 再将5和6进行比较, 需要交换, a=[5,6,7,8], 此时第0~2位是有序的
  4. 第0~3位[5,6,7,8]是有序(因为将8和7进行比较,无需交换), 此时第0~3位是有序的

代码实现:

public static void insertionSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        // 0~0已经有序, 此时要满足0~i有序
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
                swap(arr, j, j+1);
            }
        }
    }

// i和j是一个位置的话会出错
public static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
}

3.选择排序:

时间复杂度 :

O(N^2), 与数据原始排列状态无关(即使原始数组已经排列好了,也是需要进行相同次数的操作)

过程:

第0位存放最小数,就要找arr[0~N-1]中的最小值
第1位存放次小数,就要找arr[1~N-1]中的最小值…

代码实现:

public static void selectionSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 0; i < arr.length; i++) { //i~N-1
            int minIndex = i; // 假设第i位置上为最小的数
            for (int j = i + 1; j < arr.length; j++) { //i~N-1上找最小值
                minIndex = arr[j] < arr[minIndex] ? j : minIndex;
            }
            swap(arr, i, minIndex);
        }
    }

private static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

4.tips:

为什么在swap函数中可以运用该三行代码完成两个数的交换? 异或运算(^):可以理解为无进位相加,首先了解其两个性质:
(1) 0 ^ N = N且N ^ N = 0
(2)满足交换律(通过无进位相考虑,假设a=110,b=012,c=101,a^b^c的结果是对每一位进行无进位相加,与顺序无关)和结合律
假设 int a = 2, b = 3:
执行完第一句后, a = 2 ^ 3, b = 3
执行完第二句后, a = 2 ^ 3, b = 2 ^ 3 ^ 3 = 2 ^ (3 ^ 3) = 2 ^ 0 = 2
执行完第三句后, a = 2 ^ 3 ^ 2 = 2 ^ 2 ^ 3 = 0 ^ 3 = 3, b = 2 ,此时实现交换!
注意:在一个数组中如果i==j,是不能通过这三行代码实现arr[i]和arr[j]间的交换,只会使得两个位置上的值变为0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值