【数据结构】基于比较的排序算法 - 选择排序

一,前言

排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减地排列起来的操作。而对于一个排序算法 而言,我们通常会从以下三个方面分析其性能:

  • 稳定性:假设待排序序列中存在多个重复值,若是经过排序后,重复值之间的相对位置不变,则称这个排序算法是稳定的,否则就是不稳定。
  • 时间复杂度:代码执行次数随n的增长趋势,通常使用大O的渐进法表示
  • 空间复杂度:额外存储随n的增长趋势,其中递归算法空间=递归栈的最大深度,通常使用大O渐进表示法

常见的基于比较的排序算法有七种,对于这七种排序算法,又因其实现方式不同划分为以下四类 :

  • 插入排序:直接插入排序、希尔排序
  • 选择排序:选择排序、堆排序
  • 交换排序:冒泡排序、快速排序
  • 归并排序:归并排序

本节内容主要讲解选择排序,并且都是以排升序为例进行讲解。

二,选择排序

1,算法思想

每一趟从待排序序列中选出最小(或最大)的元素,放到已排序序列的末尾(或开头),直到全部元素排完。

2,算法特性

该排序的比较次数与初始序列无关,且交换次数少,在元素移动成本高时更有优势。

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:不稳定

交换操作可能把相等元素的相对次序打乱。

3,排序过程演示

4,算法实现

java 复制代码
    /**
     * 选择排序
     * @param array 待排序序列
     */
    public static void selectionSort(int[] array) {
        if(array == null) return;
        int n = array.length;
        for(int i = 0; i < n - 1; i ++) {
            // 在待排序序列中找到最小值下标
            int minIndex = i;
            for(int j = i + 1; j < n; j ++) {
                if(array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            // 将最小值交换至有序位置
            if(minIndex != i) {
                swap(array, i, minIndex);
            }
        }
    }

    /**
     * 交换数组中两个下标的元素
     * @param array 待操作序列
     * @param i 下标1
     * @param j 下标2
     */
    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

三,堆排序

1,算法思想

利用堆这种完全二叉树结构进行排序,排升序建大根堆,排降序建立小根堆。以排升序为例,由于大根堆堆顶元素为整个数组最大值,则有:

1,将数组调整为大根堆

2,将堆顶元素与当前堆的最后一个元素交换,此时堆顶元素位于待排序序列尾部,有序

3,缩小堆的范围,对新的堆顶执行向下调整,使其重新恢复为大根堆

4,重复2,3操作,直到堆中只剩一个元素

2,算法特性

时间复杂度稳定,不受初始序列有序程度明显影响,适合数据量较大的场景,但实际性能通常不如快排。

时间复杂度:O(N * log N),底数为2

空间复杂度:O(1)

稳定性:不稳定

交换堆顶和末尾元素可能改变相同值元素的相对次序

3,排序过程演示

建堆略,之前的博客有,此处直接从排序开始演示。

4,算法实现

java 复制代码
    /**
     * 堆排序
     * @param array 待排序序列
     */
    public static void heapSort(int[] array) {
        if(array == null) return;
        int n = array.length;
        // 向下调整建堆(排升序,建大根堆)
        for(int parent = (n - 1 - 1) / 2; parent >= 0; parent --) {
            siftDown(array, parent, n);
        }
        // 堆排序
        for(int end = n - 1; end > 0; end --) {
            // -交换首尾节点,尾节点有序
            swap(array, 0, end);
            // -向下调整(传递end,则有序的尾节点不在本次调整范围内)
            siftDown(array, 0, end);
        }
    }

    /**
     * 向下调整-大根堆
     * @param array 待操作序列
     * @param parent 父节点下标
     * @param len 有效长度,调整范围为 [0, len)
     */
    private static void siftDown(int[] array, int parent, int len) {
        int child = parent * 2 + 1;
        while(child < len) {
            // child指向值最大的子节点
            if(child + 1 < len && array[child + 1] > array[child]) {
                child ++;
            }
            // 不符合大根堆则交换并继续向下调整,若是符合则无需调整退出循环
            if(array[child] > array[parent]) {
                swap(array, child, parent);
                parent = child;
                child = parent * 2 + 1;
            } else {
                break;
            }
        }
    }

    /**
     * 交换数组中两个下标的元素
     * @param array 待操作序列
     * @param i 下标1
     * @param j 下标2
     */
    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
相关推荐
听风若依2 小时前
C++模板初阶
c++·算法
纪念 2293 小时前
C++ 算法(模拟)
开发语言·c++·算法
揽星河..3 小时前
【C语言】函数
c语言·算法
zwc32104320553 小时前
Day 2:图像内存、数据类型与stride
c++·人工智能·opencv·算法·计算机视觉
重生之小比特3 小时前
【算法拾光】模拟|提莫攻击 + N 字形变换
算法·模拟
XiYang-DING4 小时前
P4104.环形链表判断
数据结构·链表
東隅已逝,桑榆非晚4 小时前
AVL数实现
c++·笔记·学习·算法
驭渊的小故事4 小时前
LeetCode 算法题解:滑动窗口与数组合并的实战应用
算法·leetcode·职场和发展
.YM.Z4 小时前
优选算法——【双指针算法2】C++实现
开发语言·c++·算法