今天学习了一些简单的排序算法
,其实在我们平时解决问题中经常用到,今天正好一起看了看,记录一下。如果对你也有帮助,我很开心~
桶排序是一种排序算法,它将数组划分为一些有序的桶,然后每个桶再分别排序。最后,将所有的桶合并起来,得到一个有序的数组。桶排序的核心思想是将数据分散到不同的桶中,每个桶内部进行排序,最后将所有桶的数据合并。
思路:
- 确定桶的数量,并创建这些桶
- 遍历原始数组,将每个元素放入相应的桶中
- 对每个桶内部进行排序。可以使用其他排序算法,或者递归地使用桶排序
- 将所有桶的元素按顺序合并成最终的有序数组
适用于
数据分布比较均匀
的情况,因为如果每个桶的大小相对一致,就减少了在桶内进行排序的工作量,时间复杂度
由桶的数量和每个桶内采用的内部排序算法相关
小唐有话说
:我感觉桶排序也是拿空间换时间的感觉,和哈希表有点像有没有!!!但是他们的主要的区别在于桶排序是一种排序算法,重于对元素的排序,而哈希表是一种数据结构,用于快速查找和插入
// 桶排序函数
void bucketSort(vector<float>& arr) {
// 找到最大值和最小值
//*max_element,*min_element是 C++ 标准库 头文件中的函数,分别用于找到范围内的最大值和最小值。
float max_val = *max_element(arr.begin(), arr.end());
float min_val = *min_element(arr.begin(), arr.end());
int bucket_count = 10; // 这里假设使用 10 个桶
vector<vector<float>> buckets(bucket_count);// 创建桶
// 将元素放入桶中
for (float num : arr) {//是 C++11 引入的一种基于范围的 for 循环语法,也称为范围-based for循环
//表示遍历浮点数数组 arr 中的每个元素,并将每个元素赋值给变量 num,然后执行循环体内的操作。
int index = int(bucket_count * (num - min_val) / (max_val - min_val));
buckets[index].push_back(num);
}
// 对每个桶内部进行排序,这里使用标准库的排序函数
for (auto& bucket : buckets) {
sort(bucket.begin(), bucket.end());
}
// 将所有桶的元素合并
arr.clear();
for (const auto& bucket : buckets) {
arr.insert(arr.end(), bucket.begin(), bucket.end());
}
}
对于此处的例子,时间复杂度: O(n + 10 * log(10))
,其中10是是因为分了10个桶,分桶的过程时间复杂度是 O(n),std::sort是一种改进的快速排序算法,它的平均时间复杂度是O(n log n)
冒泡排序是一种简单的排序算法,其基本思想是通过不断地交换相邻元素,将较大的元素逐渐移到右侧(或较小的元素逐渐移到左侧),从而达到排序的目的。
小唐有话说
:不知道大家有没有印象!反正小唐印象超级无敌深刻,大一学C语音的时候就对它印象深刻,到现在仍然记忆尤新,当初看了好多好多遍才弄懂的算法,现在看简直简单的不能再简单,这就是轻舟已过万重山叭!
思路:
- 从第一个元素开始,依次比较相邻的两个元素
- 如果发现顺序不对(即当前元素大于下一个元素),则交换这两个元素的位置
- 继续进行相邻元素的比较和交换,直到整个序列变得有序
- 重复上述步骤,每次都会确定一个最大(或最小)元素的位置,直到整个序列有序为止
冒泡排序的时间复杂度为 O(n^2)
,因为时间复杂度较高,在实际应用中较少使用,特别是对于大规模数据集。
// 冒泡排序函数
void bubbleSort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; ++i) {
for (int j = 0; j < n - i - 1; ++j) { //这里注意,内层循环只用到n-i-1,因为后面的已经排过啦
// 如果当前元素大于下一个元素,则交换它们
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
}
}
}
}
快速排序是一种高效的排序算法,属于比较排序的一类。它基于分治法的思想,通过选择一个基准元素,将数组分成两个子数组,使得左边的元素都小于基准元素,右边的元素都大于基准元素,然后对这两个子数组分别递归地应用相同的排序算法。
思路:
- 选择一个基准元素(通常是数组中间的元素)
- 将数组分成两个子数组,左边的元素小于等于基准元素,右边的元素大于等于基准元素
- 对左右子数组分别递归地应用快速排序
- 合并排序好的左右子数组
// 快速排序函数
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
int pivot = arr[high];// 选择最右边的元素作为基准元素
int i = low - 1;
cout << i << endl;
// 将小于等于基准元素的元素移动到左边
for (int j = low; j < high; ++j) {
if (arr[j] <= pivot) {
++i;
swap(arr[i], arr[j]);
}
}
// 将基准元素移动到正确的位置
swap(arr[i + 1], arr[high]);
int pivotIndex = i + 1;
// 递归排序左右子数组
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
快速排序的平均时间复杂度为O(n log n)
,最差时间复杂度是 O(n^2)
,发生在数组已经有序或近乎有序的情况下。
写了快速排序的话就顺便在这最后介绍一下
std::sort
std::sort 是 C++ 标准库提供的排序函数,其实现通常基于一种改进的快速排序算法(introsort)
相同点:
1.平均时间复杂度都为 O(n log n)
2.两者都基于分治法
的思想,通过递归地划分数组并排序子数组来完成排序。
不同点:
1.std::sort 的具体实现可能会结合多种排序算法,而不仅仅是快速排序。标准库通常会选择在给定情况下最适合的排序算法,这可能包括快速排序、堆排序、插入排序等。
2.std::sort 通常是稳定排序的,即相等元素的相对顺序在排序后保持不变。而经典的快速排序算法是不稳定的,尽管可以通过一些改进策略使其成为稳定排序。
3.适应性: std::sort 可能会根据输入数据的性质在不同情况下选择不同的排序算法,以提高性能。这种自适应性是标准库排序函数的一个特点。
小唐有话说:
总得来说官方给的就是比我们自己写的厉害!没要求自己写,咱们平时就还是用官方的叭!当然原理还是得掌握的!
以上就是今天总结的内容,一些简单的排序算法,主要具体的还是根据题目随机应变,后续也会继续记录学习的一些算法呀,唐怡佳继续加油!