排序之选择排序

概念:

选择排序是一种简单直观的排序算法,其基本思想是在每一轮选择中找到未排序部分的最小(或最大)元素,然后将其与未排序部分的第一个元素交换位置。选择排序无论最好、最坏和平均情况下的时间复杂度都是O(n^2),其中n是数组的长度。尽管选择排序不是最高效的排序算法,但它的优点是算法简单,且在数据量较小或部分数据已经有序的情况下,性能表现尚可。

算法步骤:

 

以下是选择排序的基本步骤:

  1. 找到最小元素:在未排序的数组部分,找到最小元素的索引。

  2. 交换元素:将找到的最小元素与未排序部分的第一个元素交换位置。

  3. 缩小范围:将未排序部分的范围缩小,排除已经排序好的元素。

  4. 重复选择:重复步骤1到3,直到整个数组都被排序。

我们通过例子来对选择排序进行解释(这里我们取少点的数字集合(比较好解释),当然,大的数字集合也一样)(也是默认从小到大)

EG :2 3 1 5

从第一个数开始

用第一个数与后面三个数进行比较

第一个数是2:

2与3比较,2<3,不交换;

2与1比较,1<2,交换;

交换后,第一个数为1,第三个数为2

1与5比较,1<5,不交换;

这么一轮下来,最小的数排放到了第一位;

1 3 2 5

以此类推:

3与后面的2,5比较

又这么一轮下来,第二小的数排放到了第二位;

1 2 3 5

..............

通过4-1轮(n-1)轮,就排序好了

OK,接下来,我们开始以选择排序的法子来写代码

注意:选择排序用的是双层循环

外层循环:用来表明我们要排多少次,是我们排序的次数:sz-1

内层循环:我们要比较的后面的数据

代码实现:

#include <iostream>
#include <vector>
#include <algorithm> // 引入algorithm库以使用std::swap

using namespace std;

// 选择排序函数
void selectionSort(vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n - 1; i++) {
        // 找到未排序部分的最小元素的索引
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        // 将找到的最小元素交换到未排序部分的起始位置
        swap(arr[minIndex], arr[i]);
    }
}

效果展示:

#include <iostream>
#include <vector>
#include <algorithm> // 引入algorithm库以使用std::swap

using namespace std;

// 选择排序函数
void selectionSort(vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n - 1; i++) {
        // 找到未排序部分的最小元素的索引
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        // 将找到的最小元素交换到未排序部分的起始位置
        swap(arr[minIndex], arr[i]);
    }
}
Original array: 64 25 12 22 11
Sorted array: 11 12 22 25 64

D:\2024C语言\data-structure\SelectionSort\x64\Debug\SelectionSort.exe (进程 9308)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .

selectionSort函数实现了选择排序算法。它通过两层循环来遍历数组,外层循环负责未排序部分的起始位置,内层循环负责在未排序部分找到最小元素的索引。然后使用swap函数将找到的最小元素交换到未排序部分的起始位置。printArray函数用于打印数组,让我们可以看到排序前后的对比。main函数中定义了一个未排序的数组,并调用selectionSort函数对其进行排序。

尽管选择排序的性能不是最优的,但它的不稳定性(相同元素可能会因为排序而改变顺序)和易于实现的特点使其在某些情况下仍然有其应用场景。

优化:

选择排序算法由于其固有的设计,其时间复杂度在最坏、最好和平均情况下都是O(n^2),这意味着它在处理大数据集时效率较低。然而,尽管不能从根本上改变其时间复杂度,我们仍然可以采取一些措施来优化选择排序算法,提高其在特定情况下的效率:

  1. 减少交换次数:在每次遍历中,如果发现最小元素已经是当前未排序部分的第一个元素,那么就不需要进行交换。

  2. 双向选择排序(也称为鸡尾酒排序):这种变体在每一轮中同时找到未排序部分的最小和最大元素,并分别将它们移动到正确的位置。这样可以减少遍历次数。

  3. 小数组优化:对于小数组,选择排序的性能可能与其他更复杂的排序算法相当,甚至更好。因此,如果预计数据集的大小较小,或者在排序前可以快速判断数据集的大小,选择排序可能是一个不错的选择。

  4. 并行化:在某些情况下,选择排序的最小元素查找部分可以并行化。例如,如果数据集分布在多个处理器上,每个处理器可以独立地找到其数据子集的最小元素。

  5. 优化数据移动:在找到最小元素后,如果它不在当前位置,可以一次性将所有元素移动到它们最终的位置,而不是仅仅交换最小元素。

  6. 使用更高效的算法:如果可能的话,考虑使用更高效的排序算法,如快速排序、归并排序或堆排序,这些算法在大多数情况下的性能都优于选择排序。

以下是双向选择排序(鸡尾酒排序)的C++代码:

#include <iostream>
#include <vector>
#include <algorithm> // 引入algorithm库以使用std::swap

using namespace std;

// 双向选择排序(鸡尾酒排序)
void cocktailSort(vector<int>& arr) {
    int n = arr.size();
    bool swapped = true;
    int start = 0, end = n - 1;

    while (swapped) {
        swapped = false;

        // 向左扫描,找到最小元素
        for (int i = start; i < end; i++) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                swapped = true;
            }
        }

        // 如果没有发生交换,数组已经排序完成
        if (!swapped)
            break;

        end--;

        // 向右扫描,找到最大元素
        for (int i = end; i > start; i--) {
            if (arr[i] < arr[i - 1]) {
                swap(arr[i], arr[i - 1]);
                swapped = true;
            }
        }

        start++;
    }
}

// 打印数组的函数
void printArray(const vector<int>& arr) {
    for (int num : arr) {
        cout << num << " ";
    }
    cout << endl;
}

// 主函数
int main() {
    vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
    cout << "Original array: ";
    printArray(arr);

    cocktailSort(arr);
    cout << "Sorted array: ";
    printArray(arr);

    return 0;
}

在这个示例中,cocktailSort函数实现了双向选择排序,它可以在每一轮中同时找到最小和最大元素,并将它们移动到数组的两端。这种方法可以减少遍历次数,提高排序效率。然而,即使如此,鸡尾酒排序的时间复杂度仍然是O(n^2)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值