当前位置: 首页 > news >正文

《 C++ 修炼全景指南:七 》优先级队列在行动:解密 C++ priority_queue 的实现与应用

1、引言

在现代编程中,处理动态优先级队列的需求随处可见,例如任务调度、路径规划、数据压缩等应用场景都依赖于高效的优先级管理。C++ 标准库提供了 priority_queue 这一强大的工具,它的独特之处在于它的排序特性,priority_queue 维护一个能够自动排序的元素集合,保证每次取出的元素都是最大或最小的,具体取决于所定义的排序规则,用于管理具有优先级的元素,使得操作变得更加高效和直观。然而,尽管 priority_queue 在标准库中已经得到了很好的实现,但理解其内部机制并能够自定义实现是提升编程技能的重要一步。

本文旨在深入探讨 C++ 中 priority_queue 的各个方面,帮助读者全面理解这一数据结构的工作原理和应用价值。首先,我们将介绍 priority_queue 的基本定义和特点,解释其如何基于堆(heap)结构来实现优先级管理。接着,我们将详细分析其底层实现,包括如何利用 std::vector 作为动态数组来支持堆操作,并介绍自定义堆的实现方式。

此外,本文还将探讨 priority_queue 在实际应用中的重要性,举例说明其在任务调度系统、A* 寻路算法和 Huffman 编码等领域的应用。通过这些实际案例,我们希望读者能够理解 priority_queue 在解决复杂问题中的作用。

为了进一步拓展读者的知识面,我们还将展示如何自定义实现 priority_queue,并探讨在自定义过程中可能遇到的挑战,如堆操作的复杂性、内存管理和性能优化。最后,我们将总结如何通过自定义实现和优化来满足特定需求,并提高程序的整体性能。

通过本文的深入探讨和详细讲解,读者将能够全面掌握 priority_queue 的实现原理和应用场景,提升在实际项目中使用这一数据结构的能力。无论是在处理优先级队列还是进行高级数据结构设计,本文提供的知识和技巧都将大有裨益。


2、什么是 Priority Queue?

2.1、定义与特性

priority_queue 是一种基于堆的容器,它支持按照元素的优先级进行排序。与常规的 queue 不同,priority_queue 中的元素并不按插入顺序排队,而是按优先级进行排序。默认情况下,优先级高的元素会首先被访问,这通常意味着最大值优先。但通过自定义比较器,priority_queue 也可以实现最小值优先等不同的排序规则。

2.2、应用场景

  • 任务调度: 操作系统中的任务调度器使用 priority_queue 来管理不同优先级的任务,确保优先级高的任务能被优先执行。
  • 图算法:DijkstraA* 算法中,priority_queue 被用于高效地找到当前最短路径的顶点。
  • 事件模拟系统: 在复杂的事件驱动模拟中,priority_queue 可用来按事件发生的先后顺序处理事件。

2.3、Priority Queue 的优点

  • 动态排序: 在插入元素时,priority_queue 会自动根据优先级进行排序,保证每次访问的都是当前优先级最高的元素。
  • 高效的堆操作: 由于 priority_queue 基于二叉堆实现,其插入和删除操作的复杂度为 O(log n),适合频繁需要动态调整优先级的场景。

3、Priority Queue 的底层原理

3.1、二叉堆(Binary Heap)

priority_queue 的底层数据结构是二叉堆。二叉堆是一种特殊的完全二叉树,它具有以下两个性质:

  1. 堆序性: 对于每一个节点,父节点的值总是大于或等于其子节点(大顶堆),或者父节点的值总是小于或等于其子节点(小顶堆)。
  2. 结构性: 二叉堆是一个完全二叉树,这意味着所有层都是满的,只有最底层可能部分填满,并且节点从左到右依次填入。

3.2、堆的操作

  • 插入元素(push): 当将元素插入堆时,新的元素会被加入到堆的末尾,然后通过 “向上调整” 操作 (AdjustUp) 调整其位置,确保堆的有序性。时间复杂度为 O(log n)
  • 删除最大/最小元素(pop): 当从堆中删除优先级最高的元素时,堆会将最后一个元素移到根节点,并通过 “向下调整” 操作 (AdjustDown) 重新调整堆的顺序,确保堆序性。时间复杂度为 O(log n)
  • 访问最大/最小元素(top): 堆的最大或最小元素始终位于根节点,可以直接访问,其复杂度为 O(1)。

3.3、堆的构建与维护

构建一个堆通常需要 O(n) 的时间,而插入或删除操作的复杂度为 O(log n)。这些特性使得 priority_queue 在需要频繁进行优先级排序的应用场景中表现出色。


4、C++ 中 Priority Queue 的使用

4.1、基本操作

C++ 标准库提供了 std::priority_queue 类,它包含了基本的插入、删除和访问操作。以下是一个简单的例子,展示了如何使用 priority_queue 进行最大值优先的操作:

#include <iostream>
#include <queue>
#include <vector>int main() {std::priority_queue<int> pq;pq.push(10);pq.push(20);pq.push(5);std::cout << "最大值: " << pq.top() << std::endl;  // 输出: 20pq.pop();std::cout << "最大值: " << pq.top() << std::endl;  // 输出: 10return 0;
}

在这个例子中,我们使用了默认的 priority_queue,其底层是一个大顶堆,因此最大值会优先被访问。


4.2、自定义比较器

通过自定义比较器,priority_queue 还可以实现其他排序规则,例如最小值优先。以下是一个使用最小值优先的例子:

#include <iostream>
#include <queue>
#include <vector>int main() {// 使用 lambda 表达式定义比较规则std::priority_queue<int, std::vector<int>, std::greater<int>> pq;pq.push(10);pq.push(20);pq.push(5);std::cout << "最小值: " << pq.top() << std::endl;  // 输出: 5pq.pop();std::cout << "最小值: " << pq.top() << std::endl;  // 输出: 10return 0;
}

在这个例子中,std::greater<int> 用作比较器,使得 priority_queue 成为小顶堆,从而优先访问最小值。


4.3、与其他容器的结合

priority_queue 的默认底层容器是 std::vector,但你也可以使用其他容器如 std::deque 来构建 priority_queue。只需要在声明时传入对应的容器类型即可:

std::priority_queue<int, std::deque<int>> pq;

尽管底层容器可以是 deque,但 priority_queue 的操作仍然基于堆,因此其复杂度依然是 O(log n)。


5、Priority Queue 自定义实现

虽然 C++ 标准库提供了内置的 std::priority_queue,但为了更好地理解其背后的原理和工作机制,我们可以尝试自己从头实现一个 priority_queue。在这一部分中,我们将展示如何自定义实现一个基于堆结构的 priority_queue,并解释其中的每个步骤。

5.1、自定义 Priority Queue 类的设计

为了实现一个通用的 priority_queue,我们将采用以下设计步骤:

  1. 堆存储结构: 使用动态数组(如 std::vector)来表示堆,因为它的大小可以动态扩展,并且可以方便地进行插入和删除操作。
  2. 插入操作(push): 每次插入时,元素会先被放到数组的最后,然后逐步 “向上调整” 到合适的位置。
  3. 删除操作(pop): 删除堆顶元素时,会将堆的最后一个元素移到堆顶,然后逐步 “向下调整” 到合适位置以保持堆的结构。
  4. 获取堆顶元素(top): 堆顶的元素始终是最大(或最小)的,可以通过访问数组的第一个元素实现。

我们可以通过模板使 priority_queue 支持不同类型的数据,并通过自定义比较器来实现不同的排序规则。

#include <iostream>
#include <vector>namespace Lenyiin
{// 除了默认的限定符不一样,struct 和 class 在 C++ 中是一样的// 一般情况下,成员部分私有,部分共有,就用 class// 所有成员都开放成共有,就用 struct// 仿函数	函数对象template <class T>struct Less{bool operator()(const T& x1, const T& x2){return x1 < x2;}};template <class T>struct Greater{bool operator()(const T& x1, const T& x2){return x1 > x2;}};// 默认是大堆template <class T, class Container = vector<T>, class Compare = Less<T>>class Priority_queue{public:// 向上调整void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){// if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}// 向下调整void AdjustDown(int root){Compare com;int parent = root;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);parent = child;child = parent*2+1;}else{break;}}}void push(const T& data){// O(logN)_con.push_back(data);AdjustUp(_con.size() - 1);}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();// O(logN)AdjustDown(0);}T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

5.2、详细解释

模板参数:

  • T: 数据类型。
  • Compare: 比较器,用来决定堆的排序方式。默认是 std::less<T>,表示大顶堆。如果我们希望实现小顶堆,则可以传入 std::greater<T>

私有成员:

  • _con: 使用 std::vector 来存储堆中的元素。
  • com: 比较器对象,用于比较两个元素的大小。

插入操作(push):

  • 我们先将元素添加到 heap 的末尾,然后调用 AdjustUp 函数,从下向上调整元素的位置。每次将插入的元素与其父节点进行比较,如果子节点大于父节点(对于大顶堆),则交换两者的位置,直到堆序性被满足。

删除操作(pop):

  • 删除堆顶元素时,我们将堆的最后一个元素移到堆顶,然后调用 AdjustDown 函数,从上向下调整堆的顺序。通过比较父节点与左右子节点的大小,确保堆序性得以维持。

获取堆顶元素(top):

  • 直接返回堆的第一个元素,因为在堆中,最大(或最小)的元素总是位于堆顶。

5.3、测试

void test_Priority_queue()
{// 默认 建大堆Priority_queue<int> pq1;pq1.push(3);pq1.push(1);pq1.push(9);pq1.push(4);pq1.push(6);pq1.push(2);pq1.push(8);pq1.push(5);pq1.push(7);cout << "建大堆: ";while (!pq1.empty()){cout << pq1.top() << " ";pq1.pop();}cout << endl;// 建小堆	>Priority_queue<int, vector<int>, Greater<int>> pq2;pq2.push(3);pq2.push(1);pq2.push(9);pq2.push(4);pq2.push(6);pq2.push(2);pq2.push(8);pq2.push(5);pq2.push(7);cout << "建小堆: ";while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}cout << endl;
}int main()
{test_Priority_queue();// 建大堆: 9 8 7 6 5 4 3 2 1// 建小堆: 1 2 3 4 5 6 7 8 9return 0;
}

6、扩展

6.1、动态扩容和自定义数据类型

我们的 priority_queue 可以轻松扩展,以支持不同的数据类型和复杂的比较规则。例如,如果我们要处理一个由多个字段组成的结构体,我们可以自定义比较器来根据其中一个字段的优先级进行排序。

#include <iostream>
#include <string>
#include <queue>struct Task {std::string name;int priority;Task(std::string n, int p) : name(n), priority(p) {}
};// 自定义比较器: 按任务优先级从高到低排序
struct TaskComparator {bool operator()(const Task& a, const Task& b) {return a.priority < b.priority; // priority 越高, 任务优先级越高}
};int main() {// 使用自定义比较器的优先队列Priority_queue<Task, std::vector<Task>, TaskComparator> taskQueue;taskQueue.push(Task("Task 1", 5));taskQueue.push(Task("Task 2", 10));taskQueue.push(Task("Task 3", 1));while (!taskQueue.empty()) {std::cout << "处理任务: " << taskQueue.top().name << " 优先级: " << taskQueue.top().priority << std::endl;taskQueue.pop();}return 0;
}

在这个例子中,我们定义了一个 Task 结构体,包含任务名称和优先级,并使用 TaskComparator 来按优先级排序。这种灵活性使得 priority_queue 能够适应不同的业务需求。


6.2、Priority Queue 的性能优化

在某些情况下,我们可能需要优化 priority_queue 的性能,例如减少内存使用、加快操作速度等。以下是一些可能的优化策略:

  • 优化堆操作: 使用更高效的堆实现。虽然 priority_queue 的默认实现使用二叉堆,但在某些应用场景下,斐波那契堆或双端堆(double-ended heap)可能表现更优。你可以通过自定义堆来构建 priority_queue,从而提升性能或实现特殊功能。
  • 内存管理: 通过自定义内存分配器(如 std::allocator)来减少内存碎片,提高内存使用效率。
  • 并发处理: 如果 priority_queue 需要在多线程环境中使用,确保线程安全,避免竞态条件和死锁。这可以通过使用互斥锁(std::mutex)或其他同步机制来实现。在现代 C++ 中,还可以使用 std::priority_queuestd::lock_guard 结合来实现简单的线程安全操作。

7、Priority Queue 的常见应用

priority_queue 在各种实际应用中发挥着重要作用。以下是几个典型的应用场景,帮助读者更好地理解 priority_queue 的实际用途和价值。

7.1、任务调度系统

在任务调度系统中,任务可能有不同的优先级。priority_queue 可以有效地管理这些任务,确保高优先级的任务优先处理。例如,操作系统的任务调度器或后台作业管理系统通常会使用优先队列来处理不同优先级的任务。

#include <iostream>
#include <queue>
#include <string>struct Task {std::string description;int priority;Task(std::string desc, int pri) : description(desc), priority(pri) {}
};// 自定义比较器:按优先级排序
struct CompareTask {bool operator()(const Task& t1, const Task& t2) {return t1.priority < t2.priority;}
};int main() {std::priority_queue<Task, std::vector<Task>, CompareTask> taskQueue;taskQueue.push(Task("Fix bug #123", 3));taskQueue.push(Task("Develop new feature", 5));taskQueue.push(Task("Update documentation", 1));while (!taskQueue.empty()) {std::cout << "Processing task: " << taskQueue.top().description << " with priority " << taskQueue.top().priority << std::endl;taskQueue.pop();}return 0;
}

7.2、Dijkstra 最短路径算法

priority_queue 在图算法中有着广泛的应用。Dijkstra 算法通过 priority_queue 来维护距离最短的顶点,从而实现高效的最短路径搜索。以下是 Dijkstra 算法的简单实现:

#include <iostream>
#include <vector>
#include <queue>
#include <climits>struct Edge {int to;int weight;
};void dijkstra(int start, const std::vector<std::vector<Edge>>& graph, std::vector<int>& distances) {distances[start] = 0;std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> pq;pq.push({0, start});while (!pq.empty()) {int dist = pq.top().first;int node = pq.top().second;pq.pop();if (dist > distances[node]) continue;for (const auto& edge : graph[node]) {int newDist = dist + edge.weight;if (newDist < distances[edge.to]) {distances[edge.to] = newDist;pq.push({newDist, edge.to});}}}
}int main() {int n = 5;  // 顶点数std::vector<std::vector<Edge>> graph(n);// 定义边graph[0] = {{1, 10}, {2, 3}};graph[1] = {{2, 1}, {3, 2}};graph[2] = {{1, 4}, {3, 8}, {4, 2}};graph[3] = {{4, 7}};graph[4] = {{3, 9}};std::vector<int> distances(n, INT_MAX);dijkstra(0, graph, distances);for (int i = 0; i < n; ++i) {std::cout << "顶点 " << i << " 到源点的最短距离: " << distances[i] << std::endl;}return 0;
}

在这个例子中,priority_queue 被用于高效维护当前未访问的顶点,使得算法能够以 O(E log V) 的时间复杂度计算图中各顶点到源点的最短距离。


7.3、A* 寻路算法

A* 寻路算法广泛用于路径规划,尤其是在游戏开发和机器人导航中。priority_queue 在 A* 算法中用于管理待处理的节点,根据估算的代价优先处理代价最小的节点。

#include <iostream>
#include <queue>
#include <vector>
#include <cmath>struct Node {int x, y;double cost;Node(int x, int y, double c) : x(x), y(y), cost(c) {}bool operator>(const Node& other) const {return cost > other.cost;}
};int main() {std::priority_queue<Node, std::vector<Node>, std::greater<>> openList;openList.push(Node(0, 0, 0.0));openList.push(Node(1, 1, 1.0));openList.push(Node(2, 2, 0.5));while (!openList.empty()) {Node current = openList.top();openList.pop();std::cout << "Processing node at (" << current.x << ", " << current.y << ") with cost " << current.cost << std::endl;}return 0;
}

7.4、Huffman 编码

priority_queue 还被用于 Huffman 编码算法中,用来动态地生成最优二进制编码。Huffman 编码是一种用于数据压缩的算法,它依赖于优先队列来动态构建最优的编码树。priority_queue 可以用来管理字符频率的节点,构建 Huffman 树。这个算法将频率最高的字符优先放置在较短的编码中,从而减少数据的整体长度。

#include <iostream>
#include <queue>
#include <unordered_map>
#include <vector>struct HuffmanNode {char character;int frequency;HuffmanNode* left;HuffmanNode* right;HuffmanNode(char ch, int freq) : character(ch), frequency(freq), left(nullptr), right(nullptr) {}bool operator>(const HuffmanNode& other) const {return frequency > other.frequency;}
};void printHuffmanCodes(HuffmanNode* root, const std::string& prefix) {if (!root) return;if (!root->left && !root->right) {std::cout << root->character << ": " << prefix << std::endl;}printHuffmanCodes(root->left, prefix + "0");printHuffmanCodes(root->right, prefix + "1");
}int main() {std::unordered_map<char, int> frequencies = {{'a', 5}, {'b', 9}, {'c', 12}, {'d', 13}, {'e', 16}, {'f', 45}};std::priority_queue<HuffmanNode*, std::vector<HuffmanNode*>, std::greater<>> minHeap;for (const auto& pair : frequencies) {minHeap.push(new HuffmanNode(pair.first, pair.second));}while (minHeap.size() > 1) {HuffmanNode* left = minHeap.top(); minHeap.pop();HuffmanNode* right = minHeap.top(); minHeap.pop();HuffmanNode* internal = new HuffmanNode('\0', left->frequency + right->frequency);internal->left = left;internal->right = right;minHeap.push(internal);}printHuffmanCodes(minHeap.top(), "");return 0;
}

8、总结

本文全面解析了 C++ 标准库中的 priority_queue,从其定义和特点到底层实现和应用场景,再到可能的扩展和优化。通过深入理解 priority_queue 的工作原理和应用,开发者可以在实际项目中灵活运用这一强大的数据结构,并在特定需求下进行自定义扩展。

以下是对本文主要内容的总结:

  1. 定义与特点:
    • priority_queue 是一种基于堆的数据结构,用于管理优先级队列。在 C++ 标准库中,它使用大顶堆来确保每次访问堆顶时能够获取最大元素。
    • 主要操作包括插入元素(push)、删除堆顶元素(pop)和获取堆顶元素(top)。这些操作都需要通过堆的向上调整和向下调整操作来维护堆的性质。
  2. 底层实现:
    • priority_queue 通常基于 std::vector 实现,使用动态数组来存储堆元素。堆操作(如向上调整和向下调整)通过比较器来决定元素的优先级。
    • 自定义实现中,我们展示了如何从头实现一个 priority_queue,包括堆的基本操作,如 heapifyUpheapifyDown,以及如何处理动态扩容和模板参数。
  3. 应用场景:
    • 任务调度系统: 通过优先级队列可以有效管理不同优先级的任务,确保高优先级任务优先处理。
    • Dijkstra :priority_queue 被用于高效维护当前未访问的顶点,降低时间复杂度计算图中各顶点到源点的最短距离。
    • A* 寻路算法: 在路径规划中,priority_queue 用于管理待处理的节点,根据代价优先处理代价最小的节点。
    • Huffman 编码: 在数据压缩中,priority_queue 用于构建 Huffman 树,优化编码过程。
  4. 自定义实现挑战:
    • 堆操作复杂性: 插入和删除操作涉及到复杂的堆调整,需要确保堆性质保持不变。
    • 内存管理: 自定义实现需要小心处理内存分配和释放,避免内存泄漏和碎片化。
    • 性能优化: 对于大规模数据,可以考虑使用更高效的数据结构(如斐波那契堆)来提高性能。
  5. 扩展与优化:
    • 动态扩容: 使用动态数组(如 std::vector)简化了内存管理,但需要确保正确使用。
    • 自定义数据类型: 支持不同类型的数据和复杂的比较规则,使 priority_queue 更加灵活。
    • 性能优化: 优化比较器和操作逻辑,使用更高效的堆实现可以提升性能。

通过本文的学习,读者应能够全面理解 priority_queue 的实现原理及其实际应用,并能够根据特定需求进行自定义和优化。本文不仅介绍了标准库中的 priority_queue,还提供了自定义实现的详细步骤,帮助读者更好地掌握这一重要的数据结构。



希望这篇博客对您有所帮助,也欢迎您在此基础上进行更多的探索和改进。如果您有任何问题或建议,欢迎在评论区留言,我们可以共同探讨和学习。更多知识分享可以访问我的个人博客网站 : https://blog.lenyiin.com/ 。



相关文章:

《 C++ 修炼全景指南:七 》优先级队列在行动:解密 C++ priority_queue 的实现与应用

1、引言 在现代编程中&#xff0c;处理动态优先级队列的需求随处可见&#xff0c;例如任务调度、路径规划、数据压缩等应用场景都依赖于高效的优先级管理。C 标准库提供了 priority_queue 这一强大的工具&#xff0c;它的独特之处在于它的排序特性&#xff0c;priority_queue …...

通信工程学习:什么是HSS归属用户服务器

HSS&#xff1a;归属用户服务器 HSS&#xff08;归属用户服务器&#xff0c;Home Subscriber Server&#xff09;是IP多媒体子系统&#xff08;IMS&#xff09;中控制层的一个重要组成部分&#xff0c;它扮演着存储和管理用户相关信息的核心角色。以下是关于HSS归属用户服务器的…...

mysql workbench 如何访问远程数据库

要使用 MySQL Workbench 访问远程数据库&#xff0c;可以按照以下步骤操作&#xff1a; 步骤 1&#xff1a;获取远程数据库的连接信息 首先&#xff0c;确保你有远程数据库的以下信息&#xff1a; 主机名&#xff08;Host&#xff09;&#xff1a;通常是服务器的 IP 地址或域…...

ICMAN触摸感应芯片方案

ICMAN触摸感应芯片 ICMAN触摸感应芯片采用先进的电容感应技术&#xff0c;能够精确检测和识别触摸动作。这一技术通过感应人体与传感器之间的微小电容变化来实现触控功能。相比传统的电阻式触控技术&#xff0c;电容感应技术具有更高的灵敏度和响应速度&#xff0c;能够提供更…...

面向个小微型企业的开源大模型(Qwen2等)商业化, AI部署成本分析与优化策略(费用分析、资源消耗分析)

小微企业AI大模型部署服务器解决方案:资源及成本分析 1.GPU-LLM技术依赖评估依据 在当前全球化的背景下,本地化需求日益凸显,无论是企业拓展国际市场还是个人用户追求更加贴近本土化的服务体验,都对技术的本地化部署提出了更高要求。随着人工智能(AI)技术的飞速发展,尤…...

pandas判断一列中存在nan值

pandas判断一列中存在nan值 在使用 pandas 时,判断一列是否存在 NaN 值可以通过多种方法完成。以下是几种常用的方法: 使用 isna() 和 any() 方法 import pandas as pd import numpy as np# 创建示例数据 df = pd.DataFrame({A: [...

如何将 Electron 项目上架 Apple Store

前言 Electron 是一个开源框架,它允许开发者使用 Web 技术(HTML、CSS 和 JavaScript)来构建跨平台的桌面应用程序。 Electron 应用程序可以运行在 Windows、macOS 和 Linux 上,为用户提供了一种统一的方式来开发和维护软件。 本文将探讨如何将 Electron 构建的桌面应用程…...

R语言统计分析——功效分析2(t检验,ANOVA)

参考资料&#xff1a;R语言实战【第2版】 1、t检验 对于t检验&#xff0c;pwr.t.test()函数提供了许多有用的功效分析选项&#xff0c;如下&#xff1a; pwr.t.test(n,d,sig.level,power,type,alternative) 其中&#xff0c;n为样本大小&#xff1b; d为效应值&#xff0c;即…...

android 侧滑返回上一界面备忘

ParfoisMeng/SlideBack: 无需继承的Activity侧滑返回库 类全面屏返回手势效果 仿“即刻”侧滑返回 (github.com)...

golang学习笔记18——golang 访问 mysql 数据库全解析

推荐学习文档 golang应用级os框架&#xff0c;欢迎star基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总golang学习笔记01——基本数据类型golang学习笔记02——gin框架及基本原理golang学习笔记03——gin框架的核心数据结构golang学…...

苹果账号登录后端验证两种方式 python2

import time import jwt import requests import json import base64def decode_jwt(jwt_token):try:h,p,s jwt_token.split(.)except:return {},{},{},"","",""header json.loads(base64.urlsafe_b64decode(h )) # 可能需要调整填充pa…...

FlinkCDC 3.2.0 新增优点 Pattern Replacement in routing rules

新增优点&#xff1a;Pattern Replacement in routing rules flinkcdc 3.2.0版本相较于3.1.0版本&#xff0c;避免了多表多sink多次写 route 路由的麻烦&#xff0c;类似于统一前后缀的形式多表多sink&#xff0c;通过<>正则&#xff0c;大大减少了书写 官网&#xff1…...

《 C++ 修炼全景指南:六 》深入探索 C++ 标准库中的 stack 与 queue 容器适配器

1、引言 1.1、容器适配器的概念与应用 容器适配器&#xff08;Container Adapters&#xff09;是 C 标准库提供的一种特殊容器&#xff0c;它不是一种独立的容器&#xff0c;而是对其他标准容器的封装&#xff0c;用来实现特定的数据结构如栈&#xff08;stack&#xff09;和…...

高级java每日一道面试题-2024年9月07日-JVM篇-说一下类加载的执行过程?

如果有遗漏,评论区告诉我进行补充 面试官: 说一下类加载的执行过程? 我回答: 在Java中&#xff0c;类的加载是一个重要的过程&#xff0c;它是由Java虚拟机&#xff08;JVM&#xff09;的类加载器系统负责的。类加载的过程不仅仅包括加载类的字节码到内存中&#xff0c;还包…...

笔试强训day09

添加逗号 import sysa list(input())[::-1] s "" cnt 0 for v in a:cnt 1s vif cnt%30:s , print(s.rstrip(,)[::-1])跳台阶 import sys import functools functools.cache def dfs(u):if u1 or u2:# print(f"u {u}")return ureturn dfs(u-1)dfs(…...

软件测试中的黑盒测试方法,包括其定义、目的及主要步骤。

黑盒测试&#xff08;Black Box Testing&#xff09;是一种软件测试方法&#xff0c;它侧重于软件的功能性需求验证&#xff0c;而不考虑程序内部结构或代码实现细节。这种方法是从最终用户的角度出发&#xff0c;检查系统是否按照规格说明书的要求工作。黑盒测试的主要目的是验…...

Shell脚本计算π的近似值

计算π的公式很多,本文使用“π的莱布尼茨公式”来计算π的近似值,对应的公式如下: http://upload.wikimedia.org/math/9/e/8/9e804b8a1a11e442be93fed1d52205a9.png 由此我们可以得到求解π的公式为:π=4*(1-(1/3)+(1/5)-(1/7)+(1/9)...) 下面是在linux下使用shell脚本命令…...

进程间通信之消息队列

作用 进程间通信 特点 1 、消息队列中的消息是有类型的。 类型 : 自定义的结构体 , 第一个成员必须是 long 型的 . 表示为该消息的类型 如 : typedef struct 结构体名称 { long type; // 消息的正文 char name[50]; char sex[10]; int age; ... } 别名 ; 2 、消息队…...

人生苦短我用Python 5-xlwings自动调整表格

人生苦短我用Python 5-xlwings自动调整表格 前言依赖主要类App类Books类Sheet 类 示例代码 前言 使用pandas库openpyxl库实现了csv与excel文件的互相转换&#xff0c;csv转excel后若数据超出了单元格的宽度&#xff0c;部分数据无法完整显示。需要手动打开Excel文件&#xff0…...

移动跨平台框架Flutter详细介绍和学习线路分享

Flutter是一款移动应用程序SDK&#xff0c;一份代码可以同时生成iOS和Android两个高性能、高保真的应用程序。 Flutter目标是使开发人员能够交付在不同平台上都感觉自然流畅的高性能应用程序。我们兼容滚动行为、排版、图标等方面的差异。 在全世界&#xff0c;Flutter正在被越…...

线性代数基础:向量、矩阵、张量及其在机器学习中的应用详解

线性代数基础&#xff1a;向量、矩阵、张量及其在机器学习中的应用详解 线性代数基础&#xff1a;向量、矩阵、张量及其在机器学习中的应用详解一、向量 (Vectors)1. 向量的定义2. 向量在机器学习中的应用3. 向量空间 二、矩阵 (Matrices)1. 矩阵的定义2. 矩阵在机器学习中的应…...

Dockerfile中的RUN、CMD、ENTRYPOINT指令区别

RUN在构建过程中在镜像中执行命令。CMD容器创建时的默认命令。&#xff08;可以被覆盖&#xff09;ENTRYPOINT容器创建时的主要命令。&#xff08;不可被覆盖&#xff09; 指令介绍 1.RUN 在构建过程中在镜像中执行命令&#xff0c;是在 docker build中执行 2.CMD 作用&am…...

css grid布局属性详解

Grid布局 前言一、认识Grid1.1容器和项目1.2行和列1.3单元格和网格线 二、容器属性2.1.grid-template-columns与grid-template-rows属性2.1.1 直接使用长度单位比如px2.1.2 使用百分比 %2.1.3 使用repeat函数2.1.4 按比例划分 fr 关键字2.1.5 自动填充 auto 关键字2.1.6 最大值…...

Tranformer分布式特辑

随着大模型的发展&#xff0c;如何进行分布式训练也成了每位开发者必备的技能。 1. 单机训练 CPU OffloadingGradient Checkpointing 正向传播时&#xff0c;不存储当前节点的中间结果&#xff0c;在反向传播时重新计算&#xff0c;从而起到降低显存占用的作用 Low Precision…...

【Moveit2官方教程】使用 MoveIt Task Constructor (MTC) 框架来定义和执行一个机器人任务

#include <rclcpp/rclcpp.hpp> // ROS 2 的核心库 #include <moveit/planning_scene/planning_scene.h> // MoveIt 规划场景相关的头文件 #include <moveit/planning_scene_interface/planning_scene_interface.h> // MoveIt 规划场景接口 #include <m…...

使用docker配置wordpress

docker的安装 配置docker yum源 sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo下载最新版本docker sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-…...

JVM字节码

JVM字节码详解 引言 JVM&#xff08;Java Virtual Machine&#xff0c;Java虚拟机&#xff09;字节码是一种中间代码&#xff0c;主要用于Java平台上的程序在不同硬件平台上的移植。Java程序通过编译器将源代码编译成字节码&#xff0c;然后通过JVM解释或即时编译&#xff08…...

python访问mysql

要在 Python 中访问 MySQL 数据库&#xff0c;通常会使用 mysql-connector-python 或 pymysql 这两个库之一。以下是使用这两个库的基本示例&#xff1a; 使用 mysql-connector-python 安装库: pip install mysql-connector-python示例代码: import mysql.connector# 连接到 M…...

Java工具插件

一、springboot集成mqtt订阅 阿里云MQTT使用教程_复杂的世界311的博客-CSDN博客_阿里云mqtt 阿里云创建MQTT服务 先找到产品与服务,然后选择物联网平台,找到公共实例,创建一个产品。 创建产品 然后在左侧下拉栏找到设备管理,在设备管理下拉栏找到设备,然后添加设备。添加…...

Class3——Esp32|Thonny——网络连接主机-wifi连接(源代码带教程)

废话不多说——直接上配置源码和图片 一.电脑连接到wifi上&#xff08;不能是5G&#xff09; 二.网络调试助手信息设置绑定 1.获取电脑wifi信息 2.设置网络调试助手为一致&#xff0c;然后打开&#xff0c;主机地址是上面的192.168.2.149端口自己设置&#xff0c;UDP然后打开…...