排序算法 —— 冒泡排序
基本概念
冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表,一次比较两个元素,并交换它们的位置,如果它们不是按照升序排列的。这步遍历是重复进行的,直到没有再需要交换,也就是说该列表已经排序完成。该算法为交换排序之一。
算法步骤
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 重复步骤1~3,直到排序完成。
时间复杂度
冒泡排序算法的运行时间与输入数据有关。最佳情况下,数据已经排序,算法仅需一次遍历即可完成。在最坏情况下,数据是完全逆序的,需要 n-1
次遍历和 n-1
次比较。因此,其时间复杂度为 O(n^2)
。
最好的时间复杂度
当列表已经排序时,冒泡排序的最佳时间复杂度为 O(n)
。在最坏情况下,当列表反转时,时间复杂度为 O(n^2)
。
最坏的时间复杂度
当列表反转时,冒泡排序的最坏时间复杂度为 O(n^2)
。
平均时间复杂度
冒泡排序的平均时间复杂度为 O(n^2)
。
空间复杂度
冒泡排序的空间复杂度为 O(1)
,它只使用了两个附加变量。
稳定性
冒泡排序是一种稳定的排序算法,因为它不会改变相等元素的顺序。
优缺点
冒泡排序是一种简单的排序算法,但它也有其优缺点。它的优点是它的实现非常简单,并且对于小数据集来说,它的性能很好。然而,它的缺点是它对于大型数据集来说非常慢,并且它需要额外的空间来存储临时变量。因此,它最适合用于小数据集的排序。
优点
- 实现简单
- 对于小数据集来说,它的性能很好
- 它是一个稳定的排序算法,不会改变具有相等键的元素的相对顺序。
- 原地排序,不需要额外的内存。
缺点
- 对于大型数据集来说,它的性能很慢
- 它需要额外的空间来存储临时变量
应用场景
冒泡排序是一种基础的排序算法,由于其算法简单,因此常用于教学排序算法的入门。在实际应用中,由于其平均和最坏情况下的时间复杂度都是O(n^2)
,所以它并不适合处理大数据集。然而,冒泡排序在特定情况下仍然有其适用场景:
- 小型数据集:当数据量较小,特别是数据规模在几十到几百之间时,冒泡排序可以很快完成任务,因为其常数因子较小。
- 部分已排序的数组:如果数组已经部分排序,冒泡排序可以很快地将剩下的元素排到正确的位置,因为它在每一轮排序后至少会将一个元素放到最终位置。
- 几乎已排序的数组:对于几乎已经排序好的数组,冒泡排序的时间复杂度可以接近O(n),因为在这种情况下,内部循环的提前终止特性会发挥作用。
- 内存使用限制:冒泡排序是原地排序算法,除了交换元素时需要的常数额外空间,不需要额外的存储空间,这在有严格内存使用限制的环境下是一个优点。
- 实现简单:在一些简单的应用场景中,如嵌入式系统或教学示例中,可能会优先选择冒泡排序,因为它的实现代码简单,易于理解和维护。
- 稳定排序:冒泡排序是一个稳定的排序算法,如果需要保持相等元素的相对顺序不变,冒泡排序可以满足这一需求。
- 教学演示:在计算机科学教育中,冒泡排序经常被用来教授排序算法的基本概念,如比较和交换操作。
尽管冒泡排序在上述场景中有其应用,但在大多数需要高性能排序的应用中,更高效的算法如快速排序、归并排序或堆排序通常是更好的选择。
代码实现
下面是一个简单的python的案例:
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
接下来是一个C++代码案例:
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
下面是一个 C++ 模板的代码案例:
template <typename T>
void bubbleSort(T arr[], int n)
{
// Loop through the array n-1 times
for (int i = 0; i < n - 1; i++)
{
// Loop through the array n-i-1 times
for (int j = 0; j < n - i - 1; j++)
{
// If the element at index j is greater than the element at index j+1, swap them
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
完整 C++ 代码
下面是一个完整的C++代码案例:
#include <iostream>
#include <cassert>
#include <string>
using namespace std;
template <typename T>
void bubbleSort(T arr[], int n)
{
// Loop through the array n-1 times
for (int i = 0; i < n - 1; i++)
{
// Loop through the array n-i-1 times
for (int j = 0; j < n - i - 1; j++)
{
// If the element at index j is greater than the element at index j+1, swap them
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
class Person
{
public:
Person(string name, int age, int score)
{
this->name = name;
this->age = age;
this->socre = score;
}
// Override the operator> for other function to use.
bool operator>(const Person &other) const
{
// Compare the socre of two Person objects.
return this->socre > other.socre;
}
// Override the operator< for other function to use.
bool operator<(const Person &other) const
{
// Compare the socre of two Person objects.
return this->socre < other.socre;
}
// Override the operator== for other function to use.
bool operator==(const Person &other) const
{
// Compare the socre, age and name of two Person objects.
return this->socre == other.socre &&
this->age == other.age &&
this->name == other.name;
}
// Override the operator!= for other function to use.
bool operator!=(const Person &other) const
{
// Compare the socre, age and name of two Person objects.
return this->socre != other.socre ||
this->age != other.age ||
this->name != other.name;
}
// Now there are some get parameters function for this calss:
const string &getName() const { return this->name; }
int getAge() const { return this->age; }
int getSocre() const { return this->socre; }
private:
string name;
int age;
int socre;
};
// This is a unit test function for Person class.
void testPerson()
{
Person person1("Alice", 20, 90);
Person person2("Bob", 21, 80);
Person person3("Charlie", 22, 85);
// Test operator>
assert(person1 > person2);
assert(!(person1 > person3));
// Test operator<
assert(person2 < person1);
assert(!(person3 < person1));
// Test operator==
assert(person1 == person1);
assert(!(person1 == person2));
// Test operator!=
assert(person1 != person2);
assert(!(person1 != person1));
}
int main()
{
// Declare an array of integers
int arr[] = {64, 34, 25, 12, 22, 11, 90};
// Calculate the size of the array
int n = sizeof(arr) / sizeof(arr[0]);
// Call the bubbleSort function to sort the array
bubbleSort<int>(arr, n);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
double arr2[] = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Calculate the size of the array
int n2 = sizeof(arr2) / sizeof(arr2[0]);
// Call the bubbleSort function to sort the array
bubbleSort<double>(arr2, n2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n2; i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
char arr3[] = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Calculate the size of the array
int n3 = sizeof(arr3) / sizeof(arr3[0]);
// Call the bubbleSort function to sort the array
bubbleSort<char>(arr3, n3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n3; i++)
{
cout << arr3[i] << " ";
}
cout << endl;
testPerson();
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
Person arr4[] = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Calculate the size of the array
int n4 = sizeof(arr4) / sizeof(arr4[0]);
// Call the bubbleSort function to sort the array
bubbleSort<Person>(arr4, n4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n4; i++)
{
const auto& person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
// Declare an array of Person pointers
Person *arr5[4];
arr5[0] = new Person("John", 25, 90);
arr5[1] = new Person("Alice", 30, 85);
arr5[2] = new Person("Bob", 20, 78);
arr5[3] = new Person("Eve", 22, 89);
// Calculate the size of the array
int n5 = sizeof(arr5) / sizeof(arr5[0]);
// Call the bubbleSort function to sort the array
bubbleSort<Person *>(arr5, n5);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n5; i++)
{
const auto& person = arr5[i];
cout << person->getName() << " " << person->getAge() << " " << person->getSocre() << endl;
}
cout << endl;
return 0;
}
这段代码在最开始定义了一个模板函数bubbleSort
,用于对不同类型的数据(如整数、浮点数和字符)进行冒泡排序。然后,定义了一个名为Person
的类,该类具有name
、age
和score
属性,并重载了>
、<
、==
和!=
运算符,以便在排序时比较Person
对象。
接下来,定义了一个名为testPerson
的函数,用于测试Person
类。在这个函数中,创建了一些Person
对象,并测试了重载的运算符。
在main
函数中,首先对整数、浮点数和字符类型的数组进行冒泡排序,然后测试Person
类。最后,对Person
对象的数组和Person
指针的数组进行冒泡排序,并输出排序后的结果。
综上所述,这段代码演示了如何使用冒泡排序算法对不同类型的数据进行排序,并展示了如何使用Person
类进行排序。
扩展阅读
优化时间复杂度和空间复杂度的思路
冒泡排序的时间复杂度和空间复杂度优化通常涉及以下几个方面:
- 提前终止:在冒泡排序的过程中,如果在某一趟遍历中没有发生任何元素的交换,那么可以认为数组已经排序完成,可以提前终止排序过程。这种优化可以将最好情况下的时间复杂度从O(n^2)降低到O(n)。
- 双向冒泡(鸡尾酒排序):传统的冒泡排序每次只将最大的元素移动到数组的一端,而双向冒泡排序则是在每趟遍历中同时将最大元素和最小元素移动到数组的两端。这样可以在一定程度上减少排序所需的趟数。
- 梳排序(Comb Sort):梳排序是冒泡排序的一种改进,它通过设置一个逐渐减小的“间隔”(也称为“梳子”)来比较和交换元素。开始时,间隔较大,可以快速将大距离的元素移动到正确位置,随着排序的进行,间隔逐渐减小,最终变为1,这时数组几乎已经排序完成,进行最后一轮冒泡排序。梳排序的平均时间复杂度接近O(n2/2p),其中p是梳子间隔减小的速度。
- 泡沫优化:在冒泡排序中,每一趟遍历后,最后一个交换的位置之后的元素在下一趟遍历中不再需要比较,因为这部分的元素已经是排序好的。记录这个位置,下一趟遍历只需要遍历到这个位置即可。
- 差值交换:在冒泡排序中,如果使用差值交换代替传统的交换方式,可以减少交换操作的次数。差值交换是指只在需要交换的元素之间记录差值,而不是实际交换它们的位置。
常见的变种算法
历史上常用的冒泡排序变种包括:
- 经典冒泡排序:最基本的冒泡排序,每次遍历将最大的元素移动到数组的末尾。
- 鸡尾酒排序:也称为双向冒泡排序,每次遍历同时将最大元素移动到数组的一端,最小元素移动到另一端。
- 梳排序(Comb Sort):通过逐渐减小的间隔来比较和交换元素,最后进行一次冒泡排序来修正剩余的元素顺序。
- 奇偶排序:在冒泡排序的基础上,交替进行奇数索引和偶数索引的元素比较和交换。
- 混沌冒泡排序:引入随机性,每次随机选择两个元素进行比较和交换,用于某些特定场景下的排序。
需要注意的是,尽管这些优化可以在某些情况下提高冒泡排序的性能,但它们通常不能改变冒泡排序最坏情况下的时间复杂度O(n^2)。因此,对于大规模数据集的排序,更高效的算法如快速排序、归并排序或堆排序通常是更好的选择。
鸡尾酒排序(双向冒泡排序)
鸡尾酒排序(Cocktail Sort)也被称为双向冒泡排序或鸡尾酒搅拌排序,它是一种改进的冒泡排序算法。与传统的冒泡排序不同,鸡尾酒排序在每趟遍历中会同时将最大元素和最小元素移动到数组的两端,而不是只将最大元素移动到一端。这样可以在一定程度上减少排序所需的趟数。
算法步骤
算法步骤如下:
- 初始化:设置两个指针,一个指向数组的开始(left),另一个指向数组的末尾(right)。设置一个标志变量,用于检测在上一趟遍历中是否发生了元素交换。
- 正向遍历:从left开始,到right结束,比较相邻元素,如果它们的顺序错误,则交换它们。这一步将最大的元素移动到数组的末尾。
- 反向遍历:将right指针减一,从right开始,到left结束,比较相邻元素,如果它们的顺序错误,则交换它们。这一步将最小的元素移动到数组的开头。
- 重复步骤2和3:重复步骤2和3,直到在一次完整的正向遍历和反向遍历中都没有发生元素交换,这时数组已经排序完成。
- 结束:当left >= right时,排序结束。
伪代码描述
鸡尾酒排序的伪代码如下:
procedure cocktailSort(arr: list of sortable items)
n = length(arr)
swapped = true
start = 0
end = n - 1
while (swapped == true)
// 设置交换标志为false
swapped = false
// 正向遍历
for i = start to end - 1
if (arr[i] > arr[i + 1])
swap(arr[i], arr[i + 1])
// 发生了交换,设置交换标志为true
swapped = true
// 如果没有发生交换,数组已经排序完成
if (swapped == false)
break
// 将end指针减一
end = end - 1
// 设置交换标志为false
swapped = false
// 反向遍历
for i = end - 1 downto start
if (arr[i] > arr[i + 1])
swap(arr[i], arr[i + 1])
// 发生了交换,设置交换标志为true
swapped = true
// 将start指针加一
start = start + 1
// 结束循环
end procedure
C++ 模板代码
下面是使用C++模板实现的鸡尾酒排序:
template<typename T>
void cocktailSort(std::vector<T>& arr) {
bool swapped = true;
int start = 0;
int end = arr.size() - 1;
while (swapped) {
// 设置交换标志为false
swapped = false;
// 正向遍历
for (int i = start; i < end; ++i) {
if (arr[i] > arr[i + 1]) {
std::swap(arr[i], arr[i + 1]);
// 发生了交换,设置交换标志为true
swapped = true;
}
}
// 如果没有发生交换,数组已经排序完成
if (!swapped) {
break;
}
// 将end指针减一
--end;
// 设置交换标志为false
swapped = false;
// 反向遍历
for (int i = end - 1; i >= start; --i) {
if (arr[i] > arr[i + 1]) {
std::swap(arr[i], arr[i + 1]);
// 发生了交换,设置交换标志为true
swapped = true;
}
}
// 将start指针加一
++start;
}
}
梳排序(Comb Sort)
梳排序(Comb Sort)是一种由Wlodzimierz Dobosiewicz于1980年发明,由Tim Peter于1989年发表的排序算法。它是冒泡排序的一种改进算法,旨在减少其所需的交换次数。梳排序通过比较相隔一定“间隔”(也称为“梳子”)的元素来工作,逐渐减小这个间隔,最终进行一次冒泡排序来修正剩余的元素顺序。
算法步骤
算法步骤如下:
- 初始化间隔:开始时,间隔设置为数组长度除以1.3(这个值是经验值,也可以使用其他系数),向下取整。这个间隔会随着排序的进行而逐渐减小。
- 缩减间隔:在每趟排序之后,间隔会按照某个系数(通常也是1.3)减小,直到间隔变为1。
- 排序:对于当前的间隔,比较相隔该间隔的元素,如果它们的顺序错误,则交换它们。这个过程类似于冒泡排序,但是比较的元素间隔更大。
- 重复步骤2和3:重复步骤2和3,直到间隔减小到1。这时,数组应该已经基本有序。
- 最终冒泡排序:进行一次传统的冒泡排序,确保数组完全有序。
伪代码描述
梳排序的伪代码如下:
procedure combSort(arr: list of sortable items)
n = length(arr)
gap = n
shrink = 1.3
swapped = false
while gap > 1 or swapped
// 设置间隔
gap = floor(gap / shrink)
if gap < 1
gap = 1
swapped = false
// 对于当前的间隔,进行排序
for i = 0 to n - gap - 1
if arr[i] > arr[i + gap]
swap(arr[i], arr[i + gap])
swapped = true
// 最终进行一次冒泡排序
for i = 0 to n - 2
if arr[i] > arr[i + 1]
swap(arr[i], arr[i + 1])
end procedure
C++ 模板代码
下面是使用C++模板实现的梳排序:
#include <iostream>
#include <vector>
#include <cmath> // 用于计算地板除法
template<typename T>
void combSort(std::vector<T>& arr) {
int n = arr.size();
int gap = n;
bool swapped = false;
const double shrink = 1.3;
while (gap > 1 || swapped) {
// 设置间隔
gap = static_cast<int>(floor(gap / shrink));
if (gap < 1) {
gap = 1;
}
swapped = false;
// 对于当前的间隔,进行排序
for (int i = 0; i < n - gap; ++i) {
if (arr[i] > arr[i + gap]) {
std::swap(arr[i], arr[i + gap]);
swapped = true;
}
}
}
// 最终进行一次冒泡排序
for (int i = 0; i < n - 1; ++i) {
if (arr[i] > arr[i + 1]) {
std::swap(arr[i], arr[i + 1]);
}
}
}
混沌冒泡排序
混沌冒泡排序(Chaotic Bubble Sort)是一种基于冒泡排序的变体,它在比较和交换元素时引入了混沌理论的原理。混沌理论是一种研究在确定性系统中出现的看似随机或复杂行为的方法。在混沌冒泡排序中,混沌序列用于决定哪些元素进行比较和交换,而不是按照固定的顺序。
算法步骤
算法步骤如下:
- 生成混沌序列:首先,需要生成一个混沌序列,这个序列的长度与待排序数组的长度相同。混沌序列中的每个元素都是数组索引的一个排列,确保每个索引都会被访问到。
- 排序过程:使用生成的混沌序列进行排序。对于混沌序列中的每一对索引,比较对应的数组元素,如果它们的顺序错误,则交换它们。
- 重复排序:重复步骤2,直到没有更多的元素需要交换,即数组已经排序完成。
伪代码描述
混沌冒泡排序的伪代码如下:
procedure chaoticBubbleSort(arr: list of sortable items)
n = length(arr)
// 生成混沌序列
chaoticSequence = generateChaoticSequence(n)
// 初始化交换标志
swapped = true
while swapped
// 设置交换标志为false
swapped = false
// 使用混沌序列进行排序
for i = 1 to n - 1
// 获取混沌序列中的索引
index1 = chaoticSequence[i]
index2 = chaoticSequence[i + 1]
// 比较并交换元素
if arr[index1] > arr[index2]
swap(arr[index1], arr[index2])
// 发生了交换,设置交换标志为true
swapped = true
end while
end procedure
C++模板实现
下面是使用C++模板实现的混沌冒泡排序:
#include <iostream>
#include <vector>
#include <cstdlib> // 用于生成随机数
template<typename T>
void chaoticBubbleSort(std::vector<T>& arr) {
int n = arr.size();
std::vector<int> chaoticSequence(n);
bool swapped = true;
// 生成混沌序列
for (int i = 0; i < n; ++i) {
chaoticSequence[i] = i;
}
// 混沌打乱序列
for (int i = 0; i < n; ++i) {
std::swap(chaoticSequence[i], chaoticSequence[rand() % n]);
}
while (swapped) {
swapped = false;
// 使用混沌序列进行排序
for (int i = 0; i < n - 1; ++i) {
// 获取混沌序列中的索引
int index1 = chaoticSequence[i];
int index2 = chaoticSequence[i + 1];
// 比较并交换元素
if (arr[index1] > arr[index2]) {
std::swap(arr[index1], arr[index2]);
swapped = true;
}
}
}
}
这段代码定义了一个模板函数chaoticBubbleSort
,它可以接受任何类型的可排序元素数组。在main
函数中,我们创建了一个整数向量并使用chaoticBubbleSort
进行排序,然后打印排序后的结果。请注意,这个实现使用了std::rand()
来生成混沌序列,这并不是真正的混沌序列生成方法,而是一种简单的随机化方法。在实际应用中,可能需要使用更复杂的混沌映射函数来生成混沌序列。
奇偶排序
奇偶排序(Odd-Even Sort),也称为奇偶换位排序,是一种基于比较的排序算法,它是冒泡排序的一种变体。在奇偶排序中,排序过程分为两个阶段:奇数阶段和偶数阶段。在奇数阶段,比较所有奇数索引的元素对;在偶数阶段,比较所有偶数索引的元素对。这样交替进行,直到数组完全排序。
算法步骤
算法步骤如下:
- 初始化:设置一个标记变量,用于检测在上一轮排序中是否发生了元素交换。
- 奇数阶段:比较所有奇数索引的元素对(索引为1, 2, 3, …),如果它们的顺序错误,则交换它们。
- 偶数阶段:比较所有偶数索引的元素对(索引为0, 2, 4, …),如果它们的顺序错误,则交换它们。
- 重复步骤2和3:重复步骤2和3,直到在一次完整的奇数阶段和偶数阶段中都没有发生元素交换,这时数组已经排序完成。
伪代码描述
奇偶排序的伪代码如下:
procedure oddEvenSort(arr: list of sortable items)
n = length(arr)
swapped = true
while swapped
swapped = false
// 奇数阶段
for i = 1 to n - 2 by 2
if arr[i] > arr[i + 1]
swap(arr[i], arr[i + 1])
swapped = true
// 偶数阶段
for i = 0 to n - 2 by 2
if arr[i] > arr[i + 1]
swap(arr[i], arr[i + 1])
swapped = true
end while
end procedure
C++模板代码实现
下面是使用C++模板实现的奇偶排序:
#include <iostream>
#include <vector>
template<typename T>
void oddEvenSort(std::vector<T>& arr) {
bool swapped = true;
int n = arr.size();
while (swapped) {
swapped = false;
// 奇数阶段
for (int i = 1; i < n - 1; i += 2) {
if (arr[i] > arr[i + 1]) {
std::swap(arr[i], arr[i + 1]);
swapped = true;
}
}
// 偶数阶段
for (int i = 0; i < n - 1; i += 2) {
if (arr[i] > arr[i + 1]) {
std::swap(arr[i], arr[i + 1]);
swapped = true;
}
}
}
}
带扩展阅读的完整C++代码
#include <iostream>
#include <cassert>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
template <typename T>
void bubbleSort(T arr[], int n)
{
// Loop through the array n-1 times
for (int i = 0; i < n - 1; i++)
{
// Loop through the array n-i-1 times
for (int j = 0; j < n - i - 1; j++)
{
// If the element at index j is greater than the element at index j+1, swap them
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
class Person
{
public:
Person(string name, int age, int score)
{
this->name = name;
this->age = age;
this->socre = score;
}
// Override the operator> for other function to use.
bool operator>(const Person &other) const
{
// Compare the socre of two Person objects.
return this->socre > other.socre;
}
// Override the operator< for other function to use.
bool operator<(const Person &other) const
{
// Compare the socre of two Person objects.
return this->socre < other.socre;
}
// Override the operator== for other function to use.
bool operator==(const Person &other) const
{
// Compare the socre, age and name of two Person objects.
return this->socre == other.socre &&
this->age == other.age &&
this->name == other.name;
}
// Override the operator!= for other function to use.
bool operator!=(const Person &other) const
{
// Compare the socre, age and name of two Person objects.
return this->socre != other.socre ||
this->age != other.age ||
this->name != other.name;
}
// Now there are some get parameters function for this calss:
const string &getName() const { return this->name; }
int getAge() const { return this->age; }
int getSocre() const { return this->socre; }
private:
string name;
int age;
int socre;
};
// This is a unit test function for Person class.
void testPerson()
{
Person person1("Alice", 20, 90);
Person person2("Bob", 21, 80);
Person person3("Charlie", 22, 85);
// Test operator>
assert(person1 > person2);
assert(!(person1 > person3));
// Test operator<
assert(person2 < person1);
assert(!(person3 < person1));
// Test operator==
assert(person1 == person1);
assert(!(person1 == person2));
// Test operator!=
assert(person1 != person2);
assert(!(person1 != person1));
}
template <typename T>
void cocktailSort(vector<T> &arr)
{
// Initialize swapped to true to enter loop
bool swapped = true;
// Initialize start and end indices
int start = 0;
int end = arr.size() - 1;
// Loop until all swaps are done
while (swapped)
{
// Reset swapped to false
swapped = false;
// Loop through all elements in array
for (int i = start; i < end; ++i)
{
// If element is greater than next element, swap them
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
swapped = true;
}
}
// If no swaps, then array is sorted
if (!swapped)
{
break;
}
// Decrement end index
--end;
// Reset swapped to false
swapped = false;
// Loop through all elements in array
for (int i = end - 1; i >= start; --i)
{
// If element is greater than next element, swap them
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
swapped = true;
}
}
// Increment start index
++start;
}
}
template <typename T>
void combSort(vector<T> &arr)
{
// n is the size of the array
int n = arr.size();
// gap is the gap between elements
int gap = n;
// swapped is a flag to check if any elements have been swapped
bool swapped = false;
// the constant value of the gap is 1.3
const double shrink = 1.3;
// while the gap is greater than 1 or swapped is true
while (gap > 1 || swapped)
{
// gap is the new gap
gap = static_cast<int>(floor(gap / shrink));
// if the gap is less than 1, set it to 1
if (gap < 1)
{
gap = 1;
}
// set swapped to false
swapped = false;
// loop through the array
for (int i = 0; i < n - gap; ++i)
{
// if the current element is greater than the next element
if (arr[i] > arr[i + gap])
{
// swap them
swap(arr[i], arr[i + gap]);
// set swapped to true
swapped = true;
}
}
}
// loop through the array
for (int i = 0; i < n - 1; ++i)
{
// if the current element is greater than the next element
if (arr[i] > arr[i + 1])
{
// swap them
swap(arr[i], arr[i + 1]);
}
}
}
template <typename T>
void chaoticBubbleSort(vector<T> &arr)
{
// n is the size of the array
int n = arr.size();
// create a vector to store the chaotic sequence
vector<int> chaoticSequence(n);
// set swapped to true to start the loop
bool swapped = true;
// fill the chaotic sequence with the indices of the array
for (int i = 0; i < n; ++i)
{
chaoticSequence[i] = i;
}
// shuffle the chaotic sequence
for (int i = 0; i < n; ++i)
{
swap(chaoticSequence[i], chaoticSequence[rand() % n]);
}
// start the bubble sort loop
while (swapped)
{
swapped = false;
// loop through the array and compare each element to the one after it
for (int i = 0; i < n - 1; ++i)
{
// store the indices of the elements
int index1 = chaoticSequence[i];
int index2 = chaoticSequence[i + 1];
// if the element at the first index is greater than the one after it
if (arr[index1] > arr[index2])
{
// swap them
swap(arr[index1], arr[index2]);
// set swapped to true to start the next loop
swapped = true;
}
}
}
}
template <typename T>
void oddEvenSort(vector<T> &arr)
{
bool swapped = true;
int n = arr.size();
while (swapped)
{
swapped = false;
for (int i = 1; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
swapped = true;
}
}
for (int i = 0; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
swapped = true;
}
}
}
}
void bubbleSortTestCase()
{
// Declare an array of integers
int arr[] = {64, 34, 25, 12, 22, 11, 90};
// Calculate the size of the array
int n = sizeof(arr) / sizeof(arr[0]);
// Call the bubbleSort function to sort the array
bubbleSort<int>(arr, n);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
double arr2[] = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Calculate the size of the array
int n2 = sizeof(arr2) / sizeof(arr2[0]);
// Call the bubbleSort function to sort the array
bubbleSort<double>(arr2, n2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n2; i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
char arr3[] = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Calculate the size of the array
int n3 = sizeof(arr3) / sizeof(arr3[0]);
// Call the bubbleSort function to sort the array
bubbleSort<char>(arr3, n3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n3; i++)
{
cout << arr3[i] << " ";
}
cout << endl;
testPerson();
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
Person arr4[] = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Calculate the size of the array
int n4 = sizeof(arr4) / sizeof(arr4[0]);
// Call the bubbleSort function to sort the array
bubbleSort<Person>(arr4, n4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n4; i++)
{
const auto &person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
// Declare an array of Person pointers
Person *arr5[4];
arr5[0] = new Person("John", 25, 90);
arr5[1] = new Person("Alice", 30, 85);
arr5[2] = new Person("Bob", 20, 78);
arr5[3] = new Person("Eve", 22, 89);
// Calculate the size of the array
int n5 = sizeof(arr5) / sizeof(arr5[0]);
// Call the bubbleSort function to sort the array
bubbleSort<Person *>(arr5, n5);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < n5; i++)
{
const auto &person = arr5[i];
cout << person->getName() << " " << person->getAge() << " " << person->getSocre() << endl;
}
cout << endl;
}
void cocktailSortTestCase()
{
// Declare an array of integers
vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
// Call the bubbleSort function to sort the array
cocktailSort<int>(arr);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
vector<double> arr2 = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Call the bubbleSort function to sort the array
cocktailSort<double>(arr2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr2.size(); i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
vector<char> arr3 = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Call the bubbleSort function to sort the array
cocktailSort<char>(arr3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr3.size(); i++)
{
cout << arr3[i] << " ";
}
cout << endl;
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
vector<Person> arr4 = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Call the bubbleSort function to sort the array
cocktailSort<Person>(arr4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr4.size(); i++)
{
const auto &person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
}
void combSortTestCase()
{
// Declare an array of integers
vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
// Call the bubbleSort function to sort the array
combSort<int>(arr);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
vector<double> arr2 = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Call the bubbleSort function to sort the array
combSort<double>(arr2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr2.size(); i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
vector<char> arr3 = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Call the bubbleSort function to sort the array
combSort<char>(arr3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr3.size(); i++)
{
cout << arr3[i] << " ";
}
cout << endl;
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
vector<Person> arr4 = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Call the bubbleSort function to sort the array
combSort<Person>(arr4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr4.size(); i++)
{
const auto &person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
}
void chaoticButtleSortTestCase()
{
// Declare an array of integers
vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
// Call the bubbleSort function to sort the array
chaoticBubbleSort<int>(arr);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
vector<double> arr2 = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Call the bubbleSort function to sort the array
chaoticBubbleSort<double>(arr2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr2.size(); i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
vector<char> arr3 = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Call the bubbleSort function to sort the array
chaoticBubbleSort<char>(arr3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr3.size(); i++)
{
cout << arr3[i] << " ";
}
cout << endl;
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
vector<Person> arr4 = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Call the bubbleSort function to sort the array
chaoticBubbleSort<Person>(arr4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr4.size(); i++)
{
const auto &person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
}
void oddEvenSortTestCase()
{
// Declare an array of integers
vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
// Call the bubbleSort function to sort the array
oddEvenSort<int>(arr);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
// Declare an array of floats
vector<double> arr2 = {64.5, 34.2, 25.1, 12.6, 22.8, 11.9, 90.0};
// Call the bubbleSort function to sort the array
oddEvenSort<double>(arr2);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr2.size(); i++)
{
cout << arr2[i] << " ";
}
cout << endl;
// Declare an array of characters
vector<char> arr3 = {'g', 'e', 'k', 'i', 't', 'c', 'h'};
// Call the bubbleSort function to sort the array
oddEvenSort<char>(arr3);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr3.size(); i++)
{
cout << arr3[i] << " ";
}
cout << endl;
// Now I want to write some Person class's bubble sort examples in here:
// Declare an array of Person objects
vector<Person> arr4 = {Person("John", 25, 90), Person("Alice", 30, 85), Person("Bob", 20, 78), Person("Eve", 22, 89)}; // This is a dummy Person class, you need to implement it properly.
// Call the bubbleSort function to sort the array
oddEvenSort<Person>(arr4);
// Print the sorted array
cout << "Sorted array: \n";
for (int i = 0; i < arr4.size(); i++)
{
const auto &person = arr4[i];
cout << person.getName() << " " << person.getAge() << " " << person.getSocre() << endl;
}
cout << endl;
}
int main()
{
testPerson();
bubbleSortTestCase();
cocktailSortTestCase();
combSortTestCase();
chaoticButtleSortTestCase();
oddEvenSortTestCase();
return 0;
}
个人格言
追寻与内心共鸣的生活,未来会逐渐揭晓答案。
Pursue the life that resonates with your heart, and the future will gradually reveal the answer.