[算法沉淀记录] 排序算法 —— 冒泡排序

news2024/11/20 2:19:39

排序算法 —— 冒泡排序

基本概念

冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表,一次比较两个元素,并交换它们的位置,如果它们不是按照升序排列的。这步遍历是重复进行的,直到没有再需要交换,也就是说该列表已经排序完成。该算法为交换排序之一。

算法步骤

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 重复步骤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),所以它并不适合处理大数据集。然而,冒泡排序在特定情况下仍然有其适用场景:

  1. 小型数据集:当数据量较小,特别是数据规模在几十到几百之间时,冒泡排序可以很快完成任务,因为其常数因子较小。
  2. 部分已排序的数组:如果数组已经部分排序,冒泡排序可以很快地将剩下的元素排到正确的位置,因为它在每一轮排序后至少会将一个元素放到最终位置。
  3. 几乎已排序的数组:对于几乎已经排序好的数组,冒泡排序的时间复杂度可以接近O(n),因为在这种情况下,内部循环的提前终止特性会发挥作用。
  4. 内存使用限制:冒泡排序是原地排序算法,除了交换元素时需要的常数额外空间,不需要额外的存储空间,这在有严格内存使用限制的环境下是一个优点。
  5. 实现简单:在一些简单的应用场景中,如嵌入式系统或教学示例中,可能会优先选择冒泡排序,因为它的实现代码简单,易于理解和维护。
  6. 稳定排序:冒泡排序是一个稳定的排序算法,如果需要保持相等元素的相对顺序不变,冒泡排序可以满足这一需求。
  7. 教学演示:在计算机科学教育中,冒泡排序经常被用来教授排序算法的基本概念,如比较和交换操作。
    尽管冒泡排序在上述场景中有其应用,但在大多数需要高性能排序的应用中,更高效的算法如快速排序、归并排序或堆排序通常是更好的选择。

代码实现

下面是一个简单的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的类,该类具有nameagescore属性,并重载了><==!=运算符,以便在排序时比较Person对象。

接下来,定义了一个名为testPerson的函数,用于测试Person类。在这个函数中,创建了一些Person对象,并测试了重载的运算符。

main函数中,首先对整数、浮点数和字符类型的数组进行冒泡排序,然后测试Person类。最后,对Person对象的数组和Person指针的数组进行冒泡排序,并输出排序后的结果。

综上所述,这段代码演示了如何使用冒泡排序算法对不同类型的数据进行排序,并展示了如何使用Person类进行排序。

扩展阅读

优化时间复杂度和空间复杂度的思路

冒泡排序的时间复杂度和空间复杂度优化通常涉及以下几个方面:

  1. 提前终止:在冒泡排序的过程中,如果在某一趟遍历中没有发生任何元素的交换,那么可以认为数组已经排序完成,可以提前终止排序过程。这种优化可以将最好情况下的时间复杂度从O(n^2)降低到O(n)。
  2. 双向冒泡(鸡尾酒排序):传统的冒泡排序每次只将最大的元素移动到数组的一端,而双向冒泡排序则是在每趟遍历中同时将最大元素和最小元素移动到数组的两端。这样可以在一定程度上减少排序所需的趟数。
  3. 梳排序(Comb Sort):梳排序是冒泡排序的一种改进,它通过设置一个逐渐减小的“间隔”(也称为“梳子”)来比较和交换元素。开始时,间隔较大,可以快速将大距离的元素移动到正确位置,随着排序的进行,间隔逐渐减小,最终变为1,这时数组几乎已经排序完成,进行最后一轮冒泡排序。梳排序的平均时间复杂度接近O(n2/2p),其中p是梳子间隔减小的速度。
  4. 泡沫优化:在冒泡排序中,每一趟遍历后,最后一个交换的位置之后的元素在下一趟遍历中不再需要比较,因为这部分的元素已经是排序好的。记录这个位置,下一趟遍历只需要遍历到这个位置即可。
  5. 差值交换:在冒泡排序中,如果使用差值交换代替传统的交换方式,可以减少交换操作的次数。差值交换是指只在需要交换的元素之间记录差值,而不是实际交换它们的位置。

常见的变种算法

历史上常用的冒泡排序变种包括:

  • 经典冒泡排序:最基本的冒泡排序,每次遍历将最大的元素移动到数组的末尾。
  • 鸡尾酒排序:也称为双向冒泡排序,每次遍历同时将最大元素移动到数组的一端,最小元素移动到另一端。
  • 梳排序(Comb Sort):通过逐渐减小的间隔来比较和交换元素,最后进行一次冒泡排序来修正剩余的元素顺序。
  • 奇偶排序:在冒泡排序的基础上,交替进行奇数索引和偶数索引的元素比较和交换。
  • 混沌冒泡排序:引入随机性,每次随机选择两个元素进行比较和交换,用于某些特定场景下的排序。

需要注意的是,尽管这些优化可以在某些情况下提高冒泡排序的性能,但它们通常不能改变冒泡排序最坏情况下的时间复杂度O(n^2)。因此,对于大规模数据集的排序,更高效的算法如快速排序、归并排序或堆排序通常是更好的选择。

鸡尾酒排序(双向冒泡排序)

鸡尾酒排序(Cocktail Sort)也被称为双向冒泡排序或鸡尾酒搅拌排序,它是一种改进的冒泡排序算法。与传统的冒泡排序不同,鸡尾酒排序在每趟遍历中会同时将最大元素和最小元素移动到数组的两端,而不是只将最大元素移动到一端。这样可以在一定程度上减少排序所需的趟数。

算法步骤

算法步骤如下:

  1. 初始化:设置两个指针,一个指向数组的开始(left),另一个指向数组的末尾(right)。设置一个标志变量,用于检测在上一趟遍历中是否发生了元素交换。
  2. 正向遍历:从left开始,到right结束,比较相邻元素,如果它们的顺序错误,则交换它们。这一步将最大的元素移动到数组的末尾。
  3. 反向遍历:将right指针减一,从right开始,到left结束,比较相邻元素,如果它们的顺序错误,则交换它们。这一步将最小的元素移动到数组的开头。
  4. 重复步骤2和3:重复步骤2和3,直到在一次完整的正向遍历和反向遍历中都没有发生元素交换,这时数组已经排序完成。
  5. 结束:当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. 初始化间隔:开始时,间隔设置为数组长度除以1.3(这个值是经验值,也可以使用其他系数),向下取整。这个间隔会随着排序的进行而逐渐减小。
  2. 缩减间隔:在每趟排序之后,间隔会按照某个系数(通常也是1.3)减小,直到间隔变为1。
  3. 排序:对于当前的间隔,比较相隔该间隔的元素,如果它们的顺序错误,则交换它们。这个过程类似于冒泡排序,但是比较的元素间隔更大。
  4. 重复步骤2和3:重复步骤2和3,直到间隔减小到1。这时,数组应该已经基本有序。
  5. 最终冒泡排序:进行一次传统的冒泡排序,确保数组完全有序。
伪代码描述

梳排序的伪代码如下:

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)是一种基于冒泡排序的变体,它在比较和交换元素时引入了混沌理论的原理。混沌理论是一种研究在确定性系统中出现的看似随机或复杂行为的方法。在混沌冒泡排序中,混沌序列用于决定哪些元素进行比较和交换,而不是按照固定的顺序。

算法步骤

算法步骤如下:

  1. 生成混沌序列:首先,需要生成一个混沌序列,这个序列的长度与待排序数组的长度相同。混沌序列中的每个元素都是数组索引的一个排列,确保每个索引都会被访问到。
  2. 排序过程:使用生成的混沌序列进行排序。对于混沌序列中的每一对索引,比较对应的数组元素,如果它们的顺序错误,则交换它们。
  3. 重复排序:重复步骤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. 奇数阶段:比较所有奇数索引的元素对(索引为1, 2, 3, …),如果它们的顺序错误,则交换它们。
  3. 偶数阶段:比较所有偶数索引的元素对(索引为0, 2, 4, …),如果它们的顺序错误,则交换它们。
  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.

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】策略模式及函数式编程的替代

本文介绍策略模式以及使用函数式编程替代简单的策略模式。 策略模式 在策略模式&#xff08;Strategy Pattern&#xff09;中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式定义了一系列算法或策略&#xff0c;并将每个算法封装在独立…

介绍 PIL+IPython.display+mtcnn for 音视频读取、标注

1. nn.NLLLoss是如何计算误差的? nn.NLLLoss是负对数似然损失函数&#xff0c;用于多分类问题中。它的计算方式如下&#xff1a;首先&#xff0c;对于每个样本&#xff0c;我们需要将其预测结果通过softmax函数转换为概率分布。softmax函数可以将一个向量映射为一个概率分布&…

Three.js加载PLY文件

这是官方的例子 three.js webgl - PLY 我在Vue3中使用&#xff0c;测试了好久始终不显示点云数据。在网上查询后发现ply文件要放置在public目录下才行 <el-row><el-button type"primary" class"el-btn" click"IniThree1">PLY</…

【C++初阶】--类和对象(下)

目录 一.const成员 1.权限放大问题 2.权限的缩小 二.再谈构造函数 1.构造函数体赋值 2.初始化列表 (1)概念 (2)使用 ①在对象实例化过程中&#xff0c;成员变量先依次进行初始化 ②再进行函数体内二次赋值 3.explicit关键字 (1)C为什么要存在自动隐式类型转换…

Java之线程同步、synchronized用法及原理

线程的同步 场景1&#xff1a;两个线程同时访问一个变量&#xff0c;一个线程自增&#xff0c;一个线程自减 public class thread11 {public static void main(String[] args) throws InterruptedException {Thread thread1 new AddThread();Thread thread2 new DecThread(…

编曲学习:高叠和弦 挂留和弦 和弦实战应用

高叠和弦 挂留和弦 和弦实战应用小鹅通-专注内容付费的技术服务商https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_65d4826fe4b04c10a1310517?course_id=course_2XLKtQnQx9GrQHac7OPmHD9tqbv 七和弦 以三和弦举例,三和弦上面叠一个三度的音,就变成了七和弦。 从下到…

opencv python投影变换效果

变换原理&#xff1a; https://www.cnblogs.com/txwtech/p/18024547 python示范代码&#xff1a; src2原图&#xff0c;4个坐标点 dst2转换后&#xff0c;4个坐标点 p_touyin cv2.getPerspectiveTransform(src2,dst2) #计算投影变换矩阵 #利用矩阵值进行图像投影变换 r…

全流程点云机器学习(二)使用PaddlePaddle进行PointNet的机器学习训练和评估

前言 这不是高支模项目需要嘛&#xff0c;他们用传统算法切那个横杆竖杆流程复杂耗时很长&#xff0c;所以想能不能用机器学习完成这些工作&#xff0c;所以我就来整这个工作了。 基于上文的数据集切分 &#xff0c;现在来对切分好的数据来进行正式的训练。 本系列文章所用的…

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture11 Advanced_CNN 实现GoogleNet和ResNet

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture11 Advanced_CNN 代码&#xff1a; Pytorch实现GoogleNet import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import torch.nn as nn import torch.nn.fun…

内核解读之内存管理(8)什么是page cache

文章目录 0. 文件系统的层次结构1.什么是page cache2.感观认识page cache3. Page Cache的优缺点3.1 Page Cache 的优势3.2 Page Cache 的劣势 0. 文件系统的层次结构 在了解page cache之前&#xff0c;我们先看下文件系统的层次结构。 1 VFS 层 VFS &#xff08; Virtual Fi…

【Ubuntu】解决Ubuntu 22.04开机显示器颜色(高对比度/反色)异常的问题

使用Ubuntu 22.04时强制关机了一下&#xff08;make -j16把电脑搞崩了&#xff09;&#xff0c;开机后系统显示的颜色异常&#xff0c;类似高对比度或反色&#xff0c;如下图。看着很难受&#xff0c;字体也没办法辨认。还好之前遇到过类似的问题&#xff0c;应该是一个配置文件…

装修避坑干货|阳台洗衣柜洗衣机一体柜设计。福州中宅装饰,福州装修

装修的时候常常会在洗衣柜中嵌入洗衣机&#xff0c;其实阳台柜的安装并不像看起来的那么简单&#xff0c;下面给大家说说几个注意事项‼️ 01.水电位置 在安装阳台柜之前&#xff0c;务必确认水电管道的位置。确保阳台柜不会阻碍水电管道的使用&#xff0c;以免造成不必要的麻…

Three.js-02Vue框架入手

1.创建项目 说明&#xff1a;默认有vue基础&#xff0c;node版本18以上。 vue create threejs 2.选择vue3 4.安装 npm i three 5. 修改页面 <template> <div></div> </template><script setup> import * as THREE from three;const width win…

查看仓库版本记录

打开命令行窗口 输入git log即可。 若发现分支不对&#xff0c;方法如下 查看项目目录&#xff0c;命令行输入dir可以查看 多个moudel&#xff0c;进入到需要查版本记录的moudel下 命令行输入cd .\文件名如wowo-win-server\ 切换到wowo-win-server文件夹下后&#xff0c;再输入…

【Unity】提示No valid Unity Editor liscense found.Please active your liscense.

有两个软件&#xff0c;如果只有一个&#xff0c;点黑的不会有效果、、、、&#xff08;楼主是这个原因&#xff0c;可以对号入座一下&#xff09; 简而言之&#xff0c;就是去下载Unity Hub&#xff0c;再里面激活管理通行证 问题情境&#xff1a; 点击unity出现以下弹窗&a…

板块一 Servlet编程:第八节 文件上传下载操作 来自【汤米尼克的JavaEE全套教程专栏】

板块一 Servlet编程&#xff1a;第八节 文件的上传下载操作 一、文件上传&#xff08;1&#xff09;前端内容&#xff08;2&#xff09;后端内容 二、文件下载&#xff08;1&#xff09;前端的超链接下载&#xff08;2&#xff09;后端下载 在之前的内容中我们终于结束了Servle…

C++——基础语法(2):函数重载、引用

4. 函数重载 函数重载就是同一个函数名可以重复被定义&#xff0c;即允许定义相同函数名的函数。但是相同名字的函数怎么在使用的时候进行区分呢&#xff1f;所以同一个函数名的函数之间肯定是要存在不同点的&#xff0c;除了函数名外&#xff0c;还有返回类型和参数两部分可以…

【Linux】 faillock 命令使用

faillock 命令 faillock 命令是 PAM (Pluggable Authentication Modules) 的一部分&#xff0c;它被设计用来跟踪失败的登录尝试&#xff0c;并在连续失败尝试超过某个阈值时锁定账户。这个功能可以帮助系统管理员识别和防止暴力破解攻击。当一个用户连续多次输入错误的密码后&…

Vue.js+SpringBoot开发超市商品管理系统

目录 一、摘要1.1 简介1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 超市区域模块2.3 超市货架模块2.4 商品类型模块2.5 商品档案模块 三、系统设计3.1 用例图3.2 时序图3.3 类图3.4 E-R图 四、系统实现4.1 登录4.2 注册4.3 主页4.4 超市区域管理4.5 超市货架管理4.6 商品类型…

Python中的functools模块详解

大家好&#xff0c;我是海鸽。 函数被定义为一段代码&#xff0c;它接受参数&#xff0c;充当输入&#xff0c;执行涉及这些输入的一些处理&#xff0c;并根据处理返回一个值&#xff08;输出&#xff09;。当一个函数将另一个函数作为输入或返回另一个函数作为输出时&#xf…