彻底搞懂排序算法!从稳定排序到不稳定排序的全面解析

目录

排序算法是编程世界的基础,也是面试中的常客。但你真的搞清楚了哪些算法是稳定的,哪些是不稳定的吗?别担心,这篇文章将带你轻松搞懂常见排序算法,并彻底掌握“稳定”和“不稳定”排序的核心区别。无论你是新手还是想加深理解,本文都将是你不可错过的宝藏。

1. 排序算法的稳定性是什么?

举个例子:

2. 常见的稳定排序算法

1. 冒泡排序(Bubble Sort)

2. 插入排序(Insertion Sort)

3. 归并排序(Merge Sort)

4. 计数排序(Counting Sort)

3. 常见的不稳定排序算法

1. 选择排序(Selection Sort)

2. 快速排序(Quick Sort)

3. 堆排序(Heap Sort)

4. 稳定排序 VS 不稳定排序:如何选择?

稳定排序适合的场景:

不稳定排序适合的场景:

结论


排序算法是编程世界的基础,也是面试中的常客。但你真的搞清楚了哪些算法是稳定的,哪些是不稳定的吗?别担心,这篇文章将带你轻松搞懂常见排序算法,并彻底掌握“稳定”和“不稳定”排序的核心区别。无论你是新手还是想加深理解,本文都将是你不可错过的宝藏。


1. 排序算法的稳定性是什么?

在排序算法中,稳定性指的是相等元素的相对顺序是否在排序后保持不变。简单来说,如果排序前两个相等的元素在数组中的相对位置是固定的,排序后它们的位置依然不变,那么这种算法就是稳定排序;如果排序后位置可能会变化,那就是不稳定排序

举个例子:

假设你要排序一组学生信息,他们的成绩相同,但你希望保持先录入的顺序。这时候你就需要一个稳定的排序算法。如果你用的是不稳定排序算法,虽然成绩排好了,但录入顺序可能会被打乱。


2. 常见的稳定排序算法

1. 冒泡排序(Bubble Sort)

  • 原理:每次比较相邻两个元素,发现顺序不对就交换,直到没有需要交换的元素为止。

  • 特点:因为相等的元素不会互相交换,所以是稳定排序

  • 适用场景:小数据集或已经基本排好序的数组。

public class BubbleSort {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

2. 插入排序(Insertion Sort)

  • 原理:将元素插入到已排序部分的正确位置,向左移动比它大的元素。

  • 特点:不会改变相等元素的顺序,因此是稳定的

  • 适用场景:小数据集或几乎已排好序的数据。

public class InsertionSort {
    public static void insertionSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
    }
}

3. 归并排序(Merge Sort)

  • 原理:采用分治法,将数组分成两半,分别排序后再合并。

  • 特点:在合并时,优先合并左边的相等元素,保持相对顺序,稳定排序

  • 适用场景:大规模数据,追求稳定性的场景。

public class MergeSort {
    public static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }
    }
}

4. 计数排序(Counting Sort)

  • 原理:通过统计每个值的出现次数,按顺序排列。

  • 特点:计数过程不会改变相同元素的相对顺序,所以是稳定的

  • 适用场景:数据范围有限的整数排序。


3. 常见的不稳定排序算法

1. 选择排序(Selection Sort)

  • 原理:每次遍历数组,找到未排序部分的最小元素,放到前面。

  • 特点:在找到最小值后进行交换时,可能会打乱相等元素的顺序,所以是不稳定的

  • 适用场景:需要减少交换次数的情况,但对稳定性要求不高。

public class SelectionSort {
    public static void selectionSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

2. 快速排序(Quick Sort)

  • 原理:选择一个基准元素,将数组分为两部分,左边比基准小,右边比基准大,递归排序。

  • 特点:在划分过程中,相等的元素可能被分到不同的部分,导致相对顺序发生变化,不稳定

  • 适用场景:速度快,适用于大数据集,但对稳定性没有要求的场景。

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high);
            quickSort(arr, low, pi - 1);
            quickSort(arr, pi + 1, high);
        }
    }
​
    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        return i + 1;
    }
}

3. 堆排序(Heap Sort)

  • 原理:利用堆这种数据结构,首先构建最大堆,然后逐步将堆顶元素与末尾元素交换,并重新调整堆。

  • 特点:在构建堆和调整堆的过程中,可能会改变相等元素的相对顺序,不稳定

  • 适用场景:数据量较大,且对稳定性要求不高的场景。


4. 稳定排序 VS 不稳定排序:如何选择?

  • 什么时候选择稳定排序?

    • 当排序的元素有多个关键字,且你希望在一个关键字上排序后,再根据另一个关键字进行排序时,稳定性非常重要。

    • 例如,排序一组学生成绩时,成绩相同的情况下,还希望保持他们的录入顺序。

  • 什么时候选择不稳定排序?

    • 当你不关心相等元素的相对顺序,或者排序效率更重要时(比如快速排序通常速度很快),可以选择不稳定排序。

稳定排序适合的场景:

  • 数据相对较小或需要多次排序时。

  • 需要保持数据原有顺序时,例如数据库的二次排序。

不稳定排序适合的场景:

  • 大数据集,追求更高的性能时。

  • 不关心相等元素的相对顺序时。


结论

不同排序算法的稳定性特性,使得它们在不同场景下表现各异。对于需要保持数据相对顺序的情况,可以选择稳定排序算法。而在追求速度的场景下,不稳定排序算法可能更具优势。

掌握这些排序算法的稳定性,将帮助你在实际开发中更有针对性地选择合适的算法,写出更高效的代码!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值