算法 - 排序 - 选择排序 (Selection Sort)

算法 - 排序 - 选择排序 (Selection Sort)

返回分类:全部文章 >> 基础知识

返回上级:算法 - 查找与排序 (Searching and Sorting)

本文将用C++实现堆排序算法。

常见的选择排序:

  • 简单选择排序 (Simple Selection Sort)

  • 堆排序 (Heap Sort)

  • 树形选择排序 (Tree Selection Sort) ,也称锦标赛排序; (不在这里讨论)

在查看本文之前,需要一些程序语言的基础,还需要熟悉"完全二叉树"

所有排序方法中,统一使用如下库与结构:

// Author: https://blog.csdn.net/DarkRabbit
// Sorted Dependency

#pragma once

#include <algorithm>
#include <vector>
#include <stack>

template<typename T>
struct MyItem
{
    int key;
    T data;

    MyItem(){ key = -1; }
    MyItem(const int& k) : key(k){ }
    MyItem(const int& k, const T& d) : key(k), data(d){ }
};

数据表统一使用了std::vector<MyItem<T>>,如果你使用静态数组MyItem<T>[]或指针数组MyItem<T>*,那么还要传入元素数量size

示例所用数据:

  • 元素数量为size = 15

  • 关键字为key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }



1 简单选择排序简述 (Simple Selection Sort)

  • 在 n-i 个关键字中选择出最小的;
    • 它不是这组数据第一个数据,则与第一个数据交换;
    • 在数据中排除掉它,再选择第一个关键字;
    • 重复这个过程。

简单排序是真的简单,不再多说。

详细过程:

key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }

简单选择排序:
 0:   3 122 565  22 123  64  73  44 287   6   9  83  25  42  13
 1:   3   6 565  22 123  64  73  44 287 122   9  83  25  42  13
 2:   3   6   9  22 123  64  73  44 287 122 565  83  25  42  13
 3:   3   6   9  13 123  64  73  44 287 122 565  83  25  42  22
 4:   3   6   9  13  22  64  73  44 287 122 565  83  25  42 123
 5:   3   6   9  13  22  25  73  44 287 122 565  83  64  42 123
 6:   3   6   9  13  22  25  42  44 287 122 565  83  64  73 123
 7:   3   6   9  13  22  25  42  44 287 122 565  83  64  73 123
 8:   3   6   9  13  22  25  42  44  64 122 565  83 287  73 123
 9:   3   6   9  13  22  25  42  44  64  73 565  83 287 122 123
10:   3   6   9  13  22  25  42  44  64  73  83 565 287 122 123
11:   3   6   9  13  22  25  42  44  64  73  83 122 287 565 123
12:   3   6   9  13  22  25  42  44  64  73  83 122 123 565 287
13:   3   6   9  13  22  25  42  44  64  73  83 122 123 287 565


2 堆排序简述 (Heap Sort)

堆排序,也称二叉堆排序,它是利用堆的运算来进行排序。

通常有两种形式:

  • 小根堆

  • 大根堆

由于小根堆记录关键字是从大到小,所以我们使用大根堆。

假设数据表为顺序存储,如下图,其排序过程:

0:123
122
565
22
3
64
73
44
287
6
9
83
25
42
13
  • 从右向左依次对非叶结点的结点进行大根堆。即73不动、64与83交换、3:与9交换、……,直到123结束,得到大根堆;

    0:565
    287
    123
    122
    9
    83
    73
    44
    22
    6
    3
    64
    25
    42
    13
  • 然后对数据表从后往前依次执行如下过程

    • 交换 0 与 i 的位置(确定最大值下标);
    • 对 0 到 i-1 的元素再次大根堆(排除最大值下标)。

详细过程:

key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }

大根堆:
 1: 123 122 565  22   3  64  73  44 287   6   9  83  25  42  13
 2: 123 122 565  22   3  83  73  44 287   6   9  64  25  42  13
 3: 123 122 565  22   9  83  73  44 287   6   3  64  25  42  13
 4: 123 122 565 287   9  83  73  44  22   6   3  64  25  42  13
 5: 123 122 565 287   9  83  73  44  22   6   3  64  25  42  13
 6: 123 287 565 122   9  83  73  44  22   6   3  64  25  42  13
 7: 565 287 123 122   9  83  73  44  22   6   3  64  25  42  13

交换 0 和 i , 后对 0 到 i-1 大根堆:
 8: 287 122 123  44   9  83  73  13  22   6   3  64  25  42 565
 9: 123 122  83  44   9  64  73  13  22   6   3  42  25 287 565
10: 122  44  83  25   9  64  73  13  22   6   3  42 123 287 565
11:  83  44  73  25   9  64  42  13  22   6   3 122 123 287 565
12:  73  44  64  25   9   3  42  13  22   6  83 122 123 287 565
13:  64  44  42  25   9   3   6  13  22  73  83 122 123 287 565
14:  44  25  42  22   9   3   6  13  64  73  83 122 123 287 565
15:  42  25  13  22   9   3   6  44  64  73  83 122 123 287 565
16:  25  22  13   6   9   3  42  44  64  73  83 122 123 287 565
17:  22   9  13   6   3  25  42  44  64  73  83 122 123 287 565
18:  13   9   3   6  22  25  42  44  64  73  83 122 123 287 565
19:   9   6   3  13  22  25  42  44  64  73  83 122 123 287 565
20:   6   3   9  13  22  25  42  44  64  73  83 122 123 287 565
21:   3   6   9  13  22  25  42  44  64  73  83 122 123 287 565


3 性能分析 (Performance Analysis)

排序方法最好时间最差时间平均时间辅助空间稳定性
简单选择排序O(n2)O(n2)O(n2)O(1)不稳定
堆排序O(n log2n)O(n log2n)O(n log2n)O(1)不稳定

4 简单选择排序C++代码 (Simple Selection Sort C++ Code)

// Author: https://blog.csdn.net/DarkRabbit
// Selection Sort
template<typename T>
void SelectionSort(std::vector<MyItem<T>>& list)
{
    for (int i = 0; i < list.size() - 1; i++)
    {
        int keyIndex = i;
        for (int j = i + 1; j < list.size(); j++)
        {
            if (list[keyIndex].key > list[j].key)
            {
                keyIndex = j;
            }
        }

        if (keyIndex != i)
        {
            std::swap(list[keyIndex], list[i]);
        }
    }
}

5 堆排序C++代码 (Heap Sort C++ Code)

// Author: https://blog.csdn.net/DarkRabbit
// Heap Sort

// 求大根堆
template<typename T>
void MaxHeap(std::vector<MyItem<T>>& list, int start, int end)
{
    if (list.empty())
    {
        return;
    }

    int parent = start;
    int left;
    int right;
    int selected;

    while (left < size)
    {
        // 求左右孩子
        left = 2 * parent + 1;
        right = left + 1;

        // 选择左右孩子key'大的
        selected = left;
        if (right < size && list[left].key < list[right].key)
        {
            selected = right;
        }

        if (list[parent].key > list[selected].key) // 如果父结点大返回
        {
            return;
        }
        else // 交换父结点
        {
            std::swap(list[parent], list[selected]);
            parent = selected;
        }
    }
}

template<typename T>
void HeapSort(std::vector<MyItem<T>>& list)
{
    if (list.empty())
    {
        return;
    }

    int size = list.size();

    // 最后一个非叶结点开始,
    for (int i = size / 2 -1; i >= 0; i--)
    {
        MaxHeap(list, i, size - 1);
    }

    for (int i = size - 1; i > 0; i--)
    {
        std::swap(list[0], list[i]); // 确定最大值下标
        MaxHeap(list, 0, i - 1); // 排除最大值后大根堆
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值