[算法沉淀记录]排序算法 —— 快速排序

排序算法 —— 快速排序介绍

基本概念

快速排序(Quicksort)是一种排序算法,最早由东尼·霍尔提出。在平均状况下,排序 n 个项目要 Ο(n log n) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上被优化掉。

算法描述

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上做的改进。

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它是怎么排序的。它的大概思路就是:找到一个基准点(一般是数组中间的数),然后将数组分为两个部分,一部分比这个基准点小,一部分比这个基准点大,然后递归对这两部分排序即可。

算法步骤

  1. 选择一个基准元素,将列表分割成两个子序列。
  2. 对每个子序列重复步骤1,直到列表只有一个元素为止。
  3. 合并排序。
  4. 返回排序后列表。
  5. 结束。

算法伪代码

function quickSort(arr[], low, high)
    if (low < high)
    {
        // pi is partitioning index, arr[p] is now at right place
        pi = partition(arr, low, high)
        // Separately sort elements before partition and after partition
        quickSort(arr, low, pi - 1)
        quickSort(arr, pi + 1, high)
    }

优缺点

优点

  1. 通常明显比其他 Ο(n log n) 算法更快。
  2. 内循环较小,快速排序通常内循环较少。
  3. 是一种分治算法。
  4. 是递归的。
  5. 是原地的。
  6. 不需要额外的存储。

缺点

  1. 快速排序的最差时间复杂度是 Ο(n²)。
  2. 快速排序是不稳定的。
  3. 快速排序的空间复杂度是 Ο(log n)。
  4. 快速排序的递归深度是 Ο(log n)。
  5. 快速排序的运行时间取决于分区的方式。

常见应用场景

  • 快速排序被广泛应用于各种应用中,例如对大型数据集进行排序、实现高效的排序算法、优化算法性能等。
  • 它也用于各种数据结构,如数组、链表和集合,以高效地搜索和操作数据。
  • 快速排序也用于各种排序算法中,例如堆排序和归并排序,作为数据分区的子例程。
  • 快速排序也用于图遍历的各种算法中,如深度优先搜索和广度优先搜索,以高效地访问图中的所有节点。

时间复杂度

  • 最好情况 : O(n log n)
  • 平均情况 : O(n log n)
  • 最坏情况 : O(n^2)

为什么时间复杂度是O(n log n)?

快速排序算法的时间复杂度为O(n log n),这是因为它对n个元素排序时具有线性时间复杂度,而将数组划分为更小的子数组时具有对数时间复杂度。

如何避免最坏情况下的时间复杂度?

为了避免最坏情况下的时间复杂度,可以使用随机版本的快速排序,它随机选择基准值元素,而不是使用第一个或最后一个元素。这确保了最坏的情况不会频繁发生。

空间复杂度

  • O(log n)

为什么空间复杂度是O(log n)?

快速排序算法的空间复杂度是O(log n),因为它使用栈来管理递归。在最坏的情况下,递归树的深度可能为O(n),但由于该算法是对输入向量进行原地排序,因此平均空间复杂度为O(log n)。

在每次递归调用中,算法都会将输入向量划分为两个大小大致相等的子向量。然后使用相同的算法对这些子向量进行排序,但输入向量更小。这个过程会一直持续,直到达到基线条件(即输入向量只有一个元素)。

实现

快速排序背后的思想是什么?

快速排序是一种分而治之的排序算法,它的工作原理是从数组中选择一个基准值元素,并根据其他元素是否小于基准值将它们划分为两个子数组。然后对子数组进行递归排序。这可以就地完成,只需要少量的额外内存来执行排序。

快速排序具有良好的平均性能,但当输入数组已经排好序或逆序时,其最差性能为O(n^2)。因此,对于需要考虑最坏情况性能的排序算法,例如针对系统库的排序算法,就不使用这个参数。

非递归版本的代码

template <typename T>
int partition(vector<T> &arr, int low, int high)
{
    T pivot = arr[high];
    int i = low - 1;

    for (int j = low; j <= high - 1; j++)
    {
        if (arr[j] <= pivot)
        {
            i++;
            swap(arr[i], arr[j]);
        }
    }

    swap(arr[i + 1], arr[high]);
    return i + 1;
}

// This is a recursive quicksort code.
template <typename T>
void quickSort(vector<T> &arr, int low, int high)
{
    if (low < high)
    {
        int pivotIndex = partition(arr, low, high);
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}

现在我想解释一下上面的代码:

partition函数用于找到基准元素的正确位置。它接受一个数组、下标和大标作为参数。它返回基准值元素被放置到正确位置后的索引。基准值被选为数组的最后一个元素。然后,该函数遍历数组,将小于或等于基准值的元素替换到数组的左侧。最后,将基准值放在正确的位置,并返回基准值的下标。

No Recursive version of the code

template <typename T>
int partitionNew(vector<T> &arr, int low, int high)
{
    T pivot = arr[low];
    int i = low + 1;
    int j = high;

    while (i < j)
    {
        while (i <= j && arr[i] <= pivot)
        {
            i++;
        }

        while (i <= j && arr[j] >= pivot)
        {
            j--;
        }

        if (i < j)
        {
            swap(arr[i], arr[j]);
        }
    }

    swap(arr[low], arr[j]);
    return j;
}

template <typename T>
void quickSortNew(vector<T> &arr)
{
    stack<pair<int, int>> stk;
    stk.push(make_pair(0, arr.size() - 1));

    while (!stk.empty())
    {
        int low = stk.top().first;
        int high = stk.top().second;
        stk.pop();

        if (low >= high)
        {
            continue;
        }

        int pivot = partitionNew(arr, low, high);
        stk.push(make_pair(pivot + 1, high));
        stk.push(make_pair(low, pivot - 1));
    }
}

这段代码使用栈来管理递归,实现了快速排序算法。partitionNew函数是快速排序算法中使用的划分函数的修改版本。它接受一个元素向量和两个下标lowhigh作为输入,并返回对向量进行分区后主元素的下标。

quickSortNew函数是使用快速排序算法对输入向量进行排序的主要函数。它接受一个指向元素向量的引用作为输入,并对向量进行原地排序。该函数使用栈来管理递归,并调用partitionNew函数对向量进行分区并获得基准值索引。然后,它将接下来要排序的子向量的下标压入栈中,直到栈为空。

完整的代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <stack>
#include <cassert>

#pragma warning(push)
#pragma warning(disable : 4267)

using namespace std;

template <typename T>
int partition(vector<T> &arr, int low, int high)
{
    T pivot = arr[high];
    int i = low - 1;

    for (int j = low; j <= high - 1; j++)
    {
        if (arr[j] <= pivot)
        {
            i++;
            swap(arr[i], arr[j]);
        }
    }

    swap(arr[i + 1], arr[high]);
    return i + 1;
}

template <typename T>
int partitionNew(vector<T> &arr, int low, int high)
{
    T pivot = arr[low];
    int i = low + 1;
    int j = high;

    while (i < j)
    {
        while (i <= j && arr[i] <= pivot)
        {
            i++;
        }

        while (i <= j && arr[j] >= pivot)
        {
            j--;
        }

        if (i < j)
        {
            swap(arr[i], arr[j]);
        }
    }

    swap(arr[low], arr[j]);
    return j;
}

// This is a recursive quicksort code.
template <typename T>
void quickSort(vector<T> &arr, int low, int high)
{
    if (low < high)
    {
        int pivotIndex = partition(arr, low, high);
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}

template <typename T>
void quickSortNew(vector<T> &arr)
{
    stack<pair<int, int>> stk;
    stk.push(make_pair(0, arr.size() - 1));

    while (!stk.empty())
    {
        int low = stk.top().first;
        int high = stk.top().second;
        stk.pop();

        if (low >= high)
        {
            continue;
        }

        int pivot = partitionNew(arr, low, high);
        stk.push(make_pair(pivot + 1, high));
        stk.push(make_pair(low, pivot - 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;
    }

    // Override the operator<= for other fnction 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 getScore() 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));
}

void basicTypesQuickSortCase()
{
    // The int type test case:
    vector<int> intArr = {10, 7, 8, 9, 1, 5};
    quickSort<int>(intArr, 0, intArr.size() - 1);
    cout << "Sorted int array: ";
    for (int i = 0; i < intArr.size(); i++)
    {
        cout << intArr[i] << " ";
    }
    cout << endl;

    // The float type test case:
    vector<double> floatArr = {10.5, 7.2, 8.1, 9.6, 1.8, 5.3};
    quickSort<double>(floatArr, 0, floatArr.size() - 1);
    cout << "Sorted float array: ";
    for (int i = 0; i < floatArr.size(); i++)
    {
        cout << floatArr[i] << " ";
    }
    cout << endl;

    // The string type test case:
    vector<string> stringArr = {"apple", "banana", "cherry", "orange", "grape", "kiwi"};
    quickSort<string>(stringArr, 0, stringArr.size() - 1);
    cout << "Sorted string array: ";
    for (int i = 0; i < stringArr.size(); i++)
    {
        cout << stringArr[i] << " ";
    }
    cout << endl;
}

void basicTypesQuickSortNewCase()
{
    // The int type test case:
    vector<int> intArr = {10, 7, 8, 9, 1, 5};
    quickSortNew<int>(intArr);
    cout << "Sorted int array: ";
    for (size_t i = 0; i < intArr.size(); i++)
    {
        cout << intArr[i] << " ";
    }
    cout << endl;

    // The float type test case:
    vector<double> floatArr = {10.5, 7.2, 8.1, 9.6, 1.8, 5.3};
    quickSortNew<double>(floatArr);
    cout << "Sorted float array: ";
    for (size_t i = 0; i < floatArr.size(); i++)
    {
        cout << floatArr[i] << " ";
    }
    cout << endl;

    // The string type test case:
    vector<string> stringArr = {"apple", "banana", "cherry", "orange", "grape", "kiwi"};
    quickSortNew<string>(stringArr);
    cout << "Sorted string array: ";
    for (size_t i = 0; i < stringArr.size(); i++)
    {
        cout << stringArr[i] << " ";
    }
    cout << endl;
}

void personQuickSortCase()
{
    // Now I want to write some Person class's quick sort examples in here:
    vector<Person> personArr = {Person("John", 25, 88), Person("Alice", 30, 77), Person("Bob", 20, 66)};
    quickSortNew<Person>(personArr);
    cout << "Sorted Person array: ";
    const auto &personSize = personArr.size();
    for (size_t i = 0; i < personSize; i++)
    {
        const auto &person = personArr[i];
        cout << person.getName() << " " << person.getAge() << " " << person.getScore() << endl;
    }
    cout << endl;

    // Now I want to write some Person class's quick sort examples in here:
    vector<Person> personArrNew = {Person("Tom", 35, 77), Person("Panda", 22, 88), Person("Alex", 50, 99)};
    const auto &personSizeNew = personArrNew.size();
    quickSort<Person>(personArrNew, 0, personSizeNew - 1);
    cout << "Sorted Person array: " << endl;
    for (size_t i = 0; i < personSizeNew; i++)
    {
        const auto &person = personArrNew[i];
        cout << person.getName() << " " << person.getAge() << " " << person.getScore() << endl;
    }
    cout << endl;
}

int main()
{
    // Test Person class
    testPerson();
    // Test basic types quick sort
    basicTypesQuickSortCase();
    basicTypesQuickSortNewCase();
    personQuickSortCase();
    return 0;
}

#pragma warning(pop)

class Person:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __gt__(self, other):
        return self.score > other.score

    def __lt__(self, other):
        return self.score < other.score

    def __eq__(self, other):
        return self.score == other.score and self.age == other.age and self.name == other.name

    def __ne__(self, other):
        return self.score != other.score or self.age != other.age or self.name != other.name

    def __le__(self, other):
        return self.score <= other.score and self.age <= other.age and self.name <= other.name

    def __ge__(self, other):
        return self.score >= other.score and self.age >= other.age and self.name >= other.name

    def get_name(self):
        return self.name

    def get_age(self):
        return self.age

    def get_score(self):
        return self.score

def partition(arr, low, high):
    pivot = arr[high]
    i = low - 1
    for j in range(low, high):
        if arr[j] <= pivot:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]
    arr[i + 1], arr[high] = arr[high], arr[i + 1]
    return i + 1

def quick_sort(arr, low, high):
    if low < high:
        pivot_index = partition(arr, low, high)
        quick_sort(arr, low, pivot_index - 1)
        quick_sort(arr, pivot_index + 1, high)

def test_person():
    person1 = Person("Alice", 20, 90)
    person2 = Person("Bob", 21, 80)
    person3 = Person("Charlie", 22, 85)

    assert person1 > person2
    assert not (person1 > person3)

    assert person2 < person1
    assert not (person3 < person1)

    assert person1 == person1
    assert not (person1 == person2)

    assert person1 != person2
    assert not (person1 != person1)

def basic_types_quick_sort_case():
    int_arr = [10, 7, 8, 9, 1, 5]
    quick_sort(int_arr, 0, len(int_arr) - 1)
    print("Sorted int array:", int_arr)

    float_arr = [10.5, 7.2, 8.1, 9.6, 1.8, 5.3]
    quick_sort(float_arr, 0, len(float_arr) - 1)
    print("Sorted float array:", float_arr)

    string_arr = ["apple", "banana", "cherry", "orange", "grape", "kiwi"]
    quick_sort(string_arr, 0, len(string_arr) - 1)
    print("Sorted string array:", string_arr)

def person_quick_sort_case():
    person_arr = [Person("John", 25, 88), Person("Alice", 30, 77), Person("Bob", 20, 66)]
    quick_sort(person_arr, 0, len(person_arr) - 1)
    print("Sorted Person array:")
    for person in person_arr:
        print(person.get_name(), person.get_age(), person.get_score())

if __name__ == "__main__":
    # test_person()
    basic_types_quick_sort_case()
    person_quick_sort_case()

上面的代码是快速排序算法对基本数据类型和用户定义数据类型的完整实现。它包括针对每种数据类型的测试用例,以及如何在自定义数据类型上使用快速排序算法的演示。

总结

在本文中,我们梳理了快速排序算法,它的时间复杂度,以及如何用c++实现它。我们还学习了如何在基本数据类型和用户定义数据类型上使用快速排序算法。

扩展阅读

随机快速排序算法(Randomized Quick Sort)

随机快速排序是使用随机基准值的快速排序算法的一种变体。其基本思想是随机从数组中选择一个基准值,并根据其他元素是否小于基准值将其划分为两个子数组。然后对子数组进行递归排序。

使用随机基准值的主要好处是避免了对已经排序或倒序的输入数组的最差情况性能。通过随机选择基准值,得到糟糕基准值(将数组划分为两个大小不等的子数组)的机会减少了,从而提高了算法的平均性能。

随机快速排序通常用于未知输入数据是否已排序或逆序的情况,良好的平均性能比最差情况下的性能更重要。它对于大型数据集的排序特别有用,因为即使在最坏的情况下,预期的性能也非常好。

下面是随机快速排序的一个简单实现:

import random

def randomized_partition(arr, low, high):
    pivot_index = random.randint(low, high)
    arr[pivot_index], arr[high] = arr[high], arr[pivot_index]
    return partition(arr, low, high)

def randomized_quick_sort(arr, low, high):
    if low < high:
        pivot_index = randomized_partition(arr, low, high)
        randomized_quick_sort(arr, low, pivot_index - 1)
        randomized_quick_sort(arr, pivot_index + 1, high)

下面是随机快速排序算法的c++代码:

#include <iostream>
#include <vector>
#include <random>

std::random_device rd;
std::mt19937 gen(rd());

int randomized_partition(std::vector<int>& arr, int low, int high) {
    int pivot_index = std::uniform_int_distribution<>(low, high)(gen);
    std::swap(arr[pivot_index], arr[high]);
    return partition(arr, low, high);
}

void randomized_quick_sort(std::vector<int>& arr, int low, int high) {
    if (low < high) {
        int pivot_index = randomized_partition(arr, low, high);
        randomized_quick_sort(arr, low, pivot_index - 1);
        randomized_quick_sort(arr, pivot_index + 1, high);
    }
}

int main() {
    std::vector<int> arr = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    randomized_quick_sort(arr, 0, arr.size() - 1);

    for (int num : arr) {
        std::cout << num << " ";
    }

    return 0;
}

这段代码使用了c++ 11的随机数生成功能来随机选择一个主元素。randomized_partition函数是快速排序算法中使用的分区函数的修改版本。它接受一个元素向量的引用和两个索引,lowhigh,作为输入,并返回对向量进行分区后主元素的索引。

randomized_quick_sort函数是使用随机快速排序算法对输入向量进行排序的主要函数。它接受一个元素向量的引用和两个索引lowhigh作为输入,并对向量进行原地排序。该函数使用randomized_partition函数对向量进行分区并获得基准值索引。然后递归调用自己对子向量进行排序,直到栈为空。

三中位数快排(Median of Three Quick Sort)

三中位数快排算法(Median of Three fast Sort algorithm)是快速排序算法的一种变体,它随机选择三个元素中的中间元素作为基准值。这种方法旨在提高快速排序算法在处理有很多重复元素的数组或已经排序过的数组时的性能。

三中位数快排算法的中位数工作原理如下:

  1. 从数组中随机选择三个元素。
  2. 对这三个元素进行排序,找到中位数。
  3. 在快速排序算法中,使用中位数元素作为基准值。

这种方法背后的主要思想是,使用中位数元素作为基准值,可以减少遇到最坏情况的可能性,即分区过程导致子数组不平衡。这反过来又提高了快速排序算法的整体性能。

下面是三次快速排序中位数算法的简单Python实现:

import random

def median_of_three_quick_sort(arr):
    if len(arr) <= 1:
        return arr

    # Choose three random elements
    idx1, idx2, idx3 = random.sample(range(len(arr)), 3)
    elem1, elem2, elem3 = arr[idx1], arr[idx2], arr[idx3]

    # Sort the three elements
    if elem1 > elem2:
        elem1, elem2 = elem2, elem1
    if elem2 > elem3:
        elem2, elem3 = elem3, elem2
    if elem1 > elem2:
        elem1, elem2 = elem2, elem1

    # Use the median element as the pivot
    pivot = elem2
    less = [x for x in arr if x <= pivot]
    greater = [x for x in arr if x > pivot]

    # Recursively sort the less and greater arrays
    return median_of_three_quick_sort(less) + [pivot] + median_of_three_quick_sort(greater)

请注意,三中位数快排算法的中位数比标准快速排序算法的性能提升取决于特定的用例和输入数据的性质。在某些情况下,标准的快速排序算法仍然可能优于三种快速排序算法中的中位数。

下面是快速排序算法的中位数的c++实现:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

// Swap two elements in the vector
void swap(vector<int> &arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

// Median of Three function to find the median of three elements
int median_of_three(vector<int> &arr, int low, int high) {
    int mid = low + (high - low) / 2;
    if (arr[mid] < arr[low]) {
        swap(arr, low, mid);
    }
    if (arr[high] < arr[low]) {
        swap(arr, low, high);
    }
    if (arr[high] < arr[mid]) {
        swap(arr, mid, high);
    }
    swap(arr, mid, high - 1);
    return arr[high - 1];
}

// Quick Sort function
void quick_sort(vector<int> &arr, int low, int high) {
    if (low >= high) {
        return;
    }
    int pivot = median_of_three(arr, low, high);
    int i = low;
    int j = high - 1;
    while (i <= j) {
        while (arr[i] < pivot) {
            i++;
        }
        while (arr[j] > pivot) {
            j--;
        }
        if (i <= j) {
            swap(arr, i, j);
            i++;
            j--;
        }
    }
    quick_sort(arr, low, i - 1);
    quick_sort(arr, j + 1, high);
}

int main() {
    vector<int> arr = {3, 6, 8, 10, 1, 2, 1};
    quick_sort(arr, 0, arr.size() - 1);
    for (int i = 0; i < arr.size(); i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

这段代码定义了一个median_of_three函数,用于查找数组中三个元素的中位数,并将其用作基准值。然后,quick_sort函数被修改为使用这种三选中值基准值选择。main函数演示了一个示例数组的排序。

个人格言
追寻与内心共鸣的生活,未来会逐渐揭晓答案。

Pursue the life that resonates with your heart, and the future will gradually reveal the answer.

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arduino单片机基础介绍

&#xff08;本文为简单介绍&#xff0c;内容源于网络和AI&#xff09; Arduino单片机&#xff0c;自2005年诞生以来&#xff0c;已经成为全球爱好者和专业工程师们快速实现创意原型的重要工具。Arduino的普及不仅因其强大的功能和简易的操作&#xff0c;还在于其背后强大的社…

【数据结构】队列OJ题《用队列实现栈》(题库+解析+代码)

1.前言 通过前面队列的实现和详解大家对队列应该有一定熟悉了&#xff0c;现在上强度开始做题吧 队列详解&#xff1a;http://t.csdnimg.cn/dvTsW 2.OJ题目训练225. 用队列实现栈 题目分析 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0…

亿道丨三防平板丨手持平板丨加固平板丨助力地震救援

自土耳其发生7.8级大地震以来&#xff0c;一直都牵动着世人的心。2023年2月10日&#xff0c;据法新社最新消息&#xff0c;强震已造成土耳其和叙利亚两国超2万人遇难。报道称&#xff0c;相关官员和医护人员表示&#xff0c;地震造成土耳其17674人死亡&#xff0c;叙利亚则有33…

洛谷C++简单题小练习day22—小鱼记忆小程序!一题五解,高效学习

day22--小鱼记忆--2.26 习题概述 题目描述 小鱼最近被要求参加一个数字游戏&#xff0c;要求它把看到的一串数字 ai​&#xff08;长度不一定&#xff0c;以 0 结束&#xff09;&#xff0c;记住了然后反着念出来&#xff08;表示结束的数字 0 就不要念出来了&#xff09;。…

iOS App 上架指南及关键

引言 上架App Store是将iOS应用提交申请并上线的过程&#xff0c;旨在让应用在App Store上展示&#xff0c;吸引用户并获取流量。本文将介绍iOS上架的整体流程&#xff0c;并提供一些建议和注意事项。 一、iOS上架的整体流程 1. 申请开发者账号 首先&#xff0c;需要申请苹…

08_css

文章目录 CSS概念在HTML中引入CSS的三种方式CSS的选择器标签选择器类选择器id选择器后代选择器子类选择器并集选择器伪类选择器伪元素选择器属性选择器选择器的优先顺序 盒子模型边框的写法内外边距的写法外边距合并 标签的分类块级元素行级元素行内块 浮动 CSS 概念 css是层…

共同学习|Spring Cloud Alibaba一一服务网关Gateway

目录 服务网关-Gateway 环境搭建 负载均衡 Gateway Predicates Path After Before Cookie Header Weight GatewayFilter Factories StripPrefix AddResponseHeader 自定义全局Filter 网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连&…

北斗卫星赋能,宠物定位新篇章—追踪宠物,不再是难题

北斗卫星赋能&#xff0c;宠物定位新篇章—追踪宠物&#xff0c;不再是难题 随着社会的快速发展与科技的不断进步&#xff0c;人们的生活方式也在不断改变。宠物已经成为越来越多家庭的重要成员&#xff0c;在这个宠爱宠物的时代&#xff0c;如何确保宠物的安全&#xff0c;特…

js之继承

js之继承 1、原型 prototype 和 __proto__2、原型链3、继承4、hasOwnProperty 1、原型 prototype 和 proto 每个对象都有一个__proto__属性&#xff0c;并且指向它的prototype原型对象每个构造函数都有一个prototype原型对象prototype原型对象里的constructor指向构造函数本身…

淘金优化算法GRO求解不闭合SD-MTSP,可以修改旅行商个数及起点(提供MATLAB代码)

一、淘金优化算法GRO 淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;由Kamran Zolf于2023年提出&#xff0c;其灵感来自淘金热&#xff0c;模拟淘金者进行黄金勘探行为。淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;提…

vscode与vue/react环境配置

一、下载并安装VScode 安装VScode 官网下载 二、配置node.js环境 安装node.js 官网下载 会自动配置环境变量和安装npm包(npm的作用就是对Node.js依赖的包进行管理)&#xff0c;此时可以执行 node -v 和 npm -v 分别查看node和npm的版本号&#xff1a; 配置系统变量 因为在执…

Cloudera虚拟机配置(虚拟机环境自带Hadoop、Impala等大数据处理应用)

上学期的大数据处理课程&#xff0c;笔者被分配到Impala的汇报主题。然而汇报内容如果单纯只介绍Impala的理论知识&#xff0c;实在是有些太过肤浅&#xff0c;最起码得有一些实际操作来展示一下Impala的功能。但是Impala的配置实在是有些困难与繁琐&#xff0c;于是笔者通过各…

VSCode设置成中文语言环境

1&#xff0c;打开VSCode软件&#xff0c;按快捷键【CtrlShiftP】 2&#xff0c;在弹出的搜索框中输入configure language&#xff0c;然后选择Configure Display Language 3&#xff0c;在选择框中选择zh-cn 4&#xff0c;确认重启VSCode就可以了

【基础知识】MPP架构和hadoop架构比对

架构比对 简单一句描述。 mpp架构&#xff0c;就是找一群和自己能力差不多的任一起做事&#xff0c;每个人做的事情是一致的。 hadoop架构&#xff0c;就是找一群能力差一些的人&#xff0c;但只需要他们每个人只做一部分工作。 举例说明 一个特色小饭店如何成为连锁餐饮巨…

基于JAVA springboot+mybatis智慧生活分享平台设计和实现

基于JAVA springbootmybatis智慧生活分享平台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 可定制系统 欢迎点赞 收藏 …

代码随想录算法训练营第二十二天| 235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

文章目录 1.二叉搜索树的最近公共祖先2.二叉搜索树中的插入操作3.删除二叉搜索树中的节点 1.二叉搜索树的最近公共祖先 因为是有序树&#xff0c;所以中间节点如果是p、q的公共祖先&#xff0c;那么一定存在p<公共祖先<q 或 q<公共祖先<p 代码如下&#xff1a; /**…

树的基本概念和结构

目录 树的概念和结构 树的相关概念 树的特点 树的表示 树的基本应用 树的概念和结构 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合 &#x1f4cc; 把它叫做树是因为它看起来像一棵倒挂的树&#x…

springboot集成docker快速入门demo

一、docker介绍 Docker是一个开源的应用容器引擎&#xff0c;它允许开发者将应用及其依赖打包到一个可移植的容器中。这个容器可以在任何流行的 Linux或 Windows操作系统上运行&#xff0c;并且支持虚拟化。容器是完全基于沙箱机制的&#xff0c;这意味着它们之间不会有任何接口…

一般情况下,硬件中使用Repeating Sequence出现波形很奇怪就是数据的周期频率和mcu运行的频率不一致导致的

一般情况下&#xff0c;出现波形很奇怪就是数据的周期频率和mcu运行的频率不一致导致的 把timer values 修改为0 1就好了&#xff0c;如果是0&#xff0c;0.1就不行&#xff0c;不会有下面的波形

计算机组成原理 — 存储器(2)

高速缓冲存储器 大家好呀&#xff01;我是小笙&#xff0c;由于存储器这部分章节内容较多&#xff0c;我分成二部分进行总结&#xff0c;以下是第二部分&#xff0c;希望内容对你有所帮助&#xff01; 概述 目的&#xff1a;避免CPU空等现象 原理&#xff1a;程序访问的局部…
最新文章