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

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

基本概念

快速排序(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 placepi = partition(arr, low, high)// Separately sort elements before partition and after partitionquickSort(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 classtestPerson();// Test basic types quick sortbasicTypesQuickSortCase();basicTypesQuickSortNewCase();personQuickSortCase();return 0;
}#pragma warning(pop)
class Person:def __init__(self, name, age, score):self.name = nameself.age = ageself.score = scoredef __gt__(self, other):return self.score > other.scoredef __lt__(self, other):return self.score < other.scoredef __eq__(self, other):return self.score == other.score and self.age == other.age and self.name == other.namedef __ne__(self, other):return self.score != other.score or self.age != other.age or self.name != other.namedef __le__(self, other):return self.score <= other.score and self.age <= other.age and self.name <= other.namedef __ge__(self, other):return self.score >= other.score and self.age >= other.age and self.name >= other.namedef get_name(self):return self.namedef get_age(self):return self.agedef get_score(self):return self.scoredef partition(arr, low, high):pivot = arr[high]i = low - 1for j in range(low, high):if arr[j] <= pivot:i += 1arr[i], arr[j] = arr[j], arr[i]arr[i + 1], arr[high] = arr[high], arr[i + 1]return i + 1def 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 > person2assert not (person1 > person3)assert person2 < person1assert not (person3 < person1)assert person1 == person1assert not (person1 == person2)assert person1 != person2assert 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 randomdef 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 randomdef median_of_three_quick_sort(arr):if len(arr) <= 1:return arr# Choose three random elementsidx1, idx2, idx3 = random.sample(range(len(arr)), 3)elem1, elem2, elem3 = arr[idx1], arr[idx2], arr[idx3]# Sort the three elementsif elem1 > elem2:elem1, elem2 = elem2, elem1if elem2 > elem3:elem2, elem3 = elem3, elem2if elem1 > elem2:elem1, elem2 = elem2, elem1# Use the median element as the pivotpivot = elem2less = [x for x in arr if x <= pivot]greater = [x for x in arr if x > pivot]# Recursively sort the less and greater arraysreturn 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.mzph.cn/news/704809.shtml

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

相关文章

《论文阅读》一个基于情感原因的在线共情聊天机器人 SIGIR 2021

《论文阅读》一个基于情感原因的在线共情聊天机器人 前言简介数据集构建模型架构损失函数实验结果咨询策略总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Towards an Online Empathetic Chatbot…

EMQX Enterprise 5.5 发布:新增 Elasticsearch 数据集成

EMQX Enterprise 5.5.0 版本已正式发布&#xff01; 在这个版本中&#xff0c;我们引入了一系列新的功能和改进&#xff0c;包括对 Elasticsearch 的集成、Apache IoTDB 和 OpenTSDB 数据集成优化、授权缓存支持排除主题等功能。此外&#xff0c;新版本还进行了多项改进以及 B…

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候&#xff0c;问到许多年轻的Android开发他所会的设计模式是什么&#xff0c;基本上都会提到单例模式&#xff0c;但是对单例模式也是一知半解&#xff0c;在Android开发中我们经常会运用单例模式&#xff0c;所以我们还是要更了解单例模式才对…

vue3 使用qrcodejs2-fix生成二维码并可下载保存

直接上代码 <el-button click‘setEwm’>打开弹框二维码</el-button><el-dialog v-model"centerDialogVisible" align-center ><div class"code"><div class"content" id"qrCodeUrl" ref"qrCodeUrl&q…

【Vue】组件通信组件通信

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;JVM ⛺️稳中求进&#xff0c;晒太阳 组件通信 组件通信&#xff0c;就是指组件与组件之间的数据传递 组件的数据是独立的&#xff0c;无法直接访问其他组件的数据想用其他组件的数据--&…

Qt5转Qt6笔记

背景 现在的主程序和扩展的dll库都是qt5环境下编译发布的。但是想以后用qt6。所以考虑是否能够在qt5中兼容qt6的动态链接库进行加载。于是...就开始吧 开始 2024-02-23 安装好qt6后&#xff0c;在vs2019中需要新增qt6版本的安装路径。目录在&#xff1a;扩展->QT VS Tools…

Linux笔记--硬链接与软链接

一、硬链接 1.inode和block 文件包含两部分数据&#xff1a;文件属性和实际内容&#xff0c;属性放在inode中&#xff0c;实际内容放在data block中。还有个超级区块&#xff08;superblock&#xff09;记录整个文件系统的整体信息&#xff0c;包括inode和block的总量&#x…

python 循环语句 while 循环

while循环 Python 编程中 while 语句用于循环执行程序&#xff0c;即在某条件下&#xff0c;循环执行某段程序&#xff0c;以处理需要重复处理的相同任务。其基本形式为&#xff1a; while 判断条件(condition)&#xff1a; 执行语句(statements)…… 执行语句可以是单个语句…

[Docker 教学] 常用的Docker 命令

Docker是一种流行的容器化技术。使用Docker可以将数据科学应用程序连同代码和所需的依赖关系打包成一个名为镜像的便携式工件。因此&#xff0c;Docker可以简化开发环境的复制&#xff0c;并使本地开发变得轻松。 以下是一些必备的Docker命令列表&#xff0c;这些命令将在你下一…

golang学习6,glang的web的restful接口传参

1.get传参 //get请求 返回json 接口传参r.GET("/getJson/:id", controller.GetUserInfo) 1.2.接收处理 package controllerimport "github.com/gin-gonic/gin"func GetUserInfo(c *gin.Context) {_ c.Param("id")ReturnSucess(c, 200, &quo…

基于雷达影像的洪水监测技术方法详解

洪水发生时候大多数是阴雨天气&#xff0c;光学影像基本上拍不到有效影像。雷达影像这时候就能发挥其不受天气影像的优点。现在星载的雷达卫星非常多&#xff0c;如高分三号、陆探一号、海丝一号&#xff08;巢湖一号&#xff09;、哨兵1号等。本文以哨兵1号L1地距(GRD)产品来介…

2018-02-14 新闻内容爬虫【上学时做论文自己爬新闻数据,原谅我自己懒发的图片】

2018-02-14新闻内容爬虫【上学时做论文自己爬新闻数据&#xff0c;原谅我自己懒发的图片】资源-CSDN文库https://download.csdn.net/download/liuzhuchen/88878591爬虫过的站点&#xff1a; 1QQ新闻 1&#xff0c;准备爬取滚动新闻页面 2 通过F12 开发工具查找发现&#xff…

高性能 Kafka 及常见面试题

Kafka 是一种分布式的&#xff0c;基于发布/订阅的消息系统&#xff0c;原本开发自 LinkedIn&#xff0c;用作 LinkedIn 的事件流&#xff08;Event Stream&#xff09;和运营数据处理管道&#xff08;Pipeline&#xff09;的基础。 基础原理详解可见 Kafka 基本架构及原理 基础…

嵌入式驱动学习第一周——git的使用

前言 本文主要介绍git的使用&#xff0c;包括介绍git&#xff0c;gitee&#xff0c;以及使用gitee创建仓库并托管代码 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xf…

【C进阶】顺序表详解

文章目录 &#x1f4dd;线性表的概念&#x1f320; 顺序表&#x1f309;顺序表的概念 &#x1f320;声明--接口&#x1f309;启动&#x1f320;初始化&#x1f309;扩容&#x1f320;尾插&#x1f309; 打印&#x1f320;销毁&#x1f309; 尾删&#x1f320;头插&#x1f309;…

探索便捷办公新选择:ONLYOFFICE 桌面编辑器

目录 引言 1. ONLYOFFICE 桌面编辑器简介 2. 功能特点 2.1 多格式支持 2.2 实时协作编辑 2.3 兼容性与格式保持 2.4 丰富的编辑功能 3. 使用方法 3.1 下载安装 3.2 打开文档 3.3 编辑文档 3.4 保存和共享 4. 注意事项 4.1 版本更新 4.2 网络连接 4.3 安全性 5.…

FL Studio Producer Edition2024中文进阶版Win/Mac

FL Studio Producer Edition&#xff0c;特别是其【中文进阶版 Win/Mac】&#xff0c;是数字音乐制作领域中的一款知名软件。它为广大音乐制作人、声音工程师以及音乐爱好者提供了一个从音乐构思到最终作品发布的完整解决方案。这个版本特别为中文用户优化&#xff0c;并兼容W…

【Android移动开发】Windows10平台安装Android Studio与人工智能算法模型部署案例

目录 一、Android Studio下载地址二、开发环境JDK三、开始安装Android Studio四、案例展示与搭建五、人工智能算法模型移动端部署案例参考 一、Android Studio下载地址 https://developer.android.google.cn/studio/install.html 电脑配置要求&#xff1a; 下载保存在指定文…

Java+SpringBoot+Vue+MySQL构建银行客户管理新平台

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

Linux按键输入实验-创建按键的设备节点

一. 简介 Linux内核针对 GPIO驱动开发,提供了 pinctrl子系统与gpio子系统,方便了 GPIO驱动程序的开发。 本文开始学习如何利用 Linux内核的 pinctrl子系统,与 gpio子系统提供的 API函数,开发按键驱动。 这里主要学习在设备树文件中创建按键的设备节点。 二. Linux按键…