数据结构-选择类排序

1.1 简单选择排序

简单选择排序(Selection Sort)是一种直观的排序算法。它的基本思想是每次从待排序的元素中选出最小(或最大)的元素,将其与当前未排序部分的第一个元素交换位置。

算法步骤

1. 初始状态:从未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

2. 重复过程:从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3. 结束条件:重复上述步骤,直到所有元素均排序完毕。

void SelectionSort(int a[], int n) {
    for (int i = 0; i < n - 1; ++i) {
        int minIndex = i; // 假设当前元素是最小值
        for (int j = i + 1; j < n; ++j) {
            if (a[j] < a[minIndex]) {
                minIndex = j; // 找到更小的元素,更新最小值索引
            }
        }
        if (minIndex != i) {
            swap(a[i], a[minIndex]); // 交换当前元素和找到的最小元素
        }
    }
}

时间复杂度

·最优时间复杂度:O(n²)

·最坏时间复杂度:O(n²)

·平均时间复杂度:O(n²)

空间复杂度

·空间复杂度:O(1)(只需要常数级别的额外空间)

比较次数

简单选择排序的比较次数与数组的初始排列无关,总是固定的,比较次数:每次选择最小元素时,需要比较剩余的所有元素。对于一个长度为 ( n ) 的数组,总的比较次数为:

\sum_{i=1}^{n-1} (n - i) = \frac{n(n - 1)}{2}

移动次数

移动次数取决于数组的初始排列情况:

1. 最优情况(数组已经有序):

在最优情况下,不需要进行任何交换操作,因此移动次数为 0。

2. 最坏情况(数组逆序):

在最坏情况下,每次选择最小元素时,都需要将其移动到当前未排序部分的最前面。每次交换需要 3 次移动操作(一次交换涉及 3 次赋值操作)。总的移动次数为:3×(n−1),因此,最坏情况下的移动次数为 3(n−1)。

1.2 堆排序

堆排序(Heapsort)是一种基于堆数据结构的排序算法。堆是一种近似完全二叉树的结构,并同时满足堆的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。

概念

大顶堆(Max-Heap)

定义:在大顶堆中,每个节点的值都大于或等于其子节点的值。

性质:根节点(堆顶)的值是整个堆中的最大值。

       10
      /  \
     9    8
    / \  / \
   7  6 5  4

在这个大顶堆中,根节点 10 是最大值,每个父节点的值都大于或等于其子节点的值。

小顶堆(Min-Heap)

定义:在小顶堆中,每个节点的值都小于或等于其子节点的值。

性质:根节点(堆顶)的值是整个堆中的最小值。

       1
      / \
     3   2
    / \ / \
   7  6 5  4

在这个小顶堆中,根节点 1 是最小值,每个父节点的值都小于或等于其子节点的值。

算法步骤

1. 构建大顶堆:将待排序序列构造成一个大顶堆。

2. 交换堆顶元素和末尾元素:将堆顶的元素(最大值)与末尾元素交换,并将堆的尺寸缩小1。

3. 调整堆:重新调整堆,使其满足堆的性质。

4. 重复步骤2和3:直到堆的尺寸为1。

// 堆调整函数
void heapify(int a[], int n, int i) {
    int largest = i; // 初始化最大值为根节点
    int left = 2 * i + 1; // 左子节点
    int right = 2 * i + 2; // 右子节点

    // 如果左子节点大于根节点
    if (left < n && a[left] > a[largest])
        largest = left;

    // 如果右子节点大于当前最大值
    if (right < n && a[right] > a[largest])
        largest = right;

    // 如果最大值不是根节点
    if (largest != i) {
        swap(a[i], a[largest]); // 交换
        heapify(a, n, largest); // 递归调整子树
    }
}

// 堆排序函数
void heapSort(int a[], int n) {
    // 构建大顶堆
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(a, n, i);

    // 一个个取出元素
    for (int i = n - 1; i > 0; i--) {
        swap(a[0], a[i]); // 交换堆顶元素和末尾元素
        heapify(a, i, 0); // 调整堆
    }
}

时间复杂度

·最优时间复杂度:O(nlogn)

·最坏时间复杂度:O(nlogn)

·平均时间复杂度:O(nlogn)

空间复杂度

·空间复杂度:O(1)(原地排序)

稳定性

堆排序是一种不稳定的排序算法,因为相同元素的相对顺序可能会改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值