【C++】STL学习之优先级队列

🔥博客主页 小羊失眠啦.
🎥系列专栏《C语言》 《数据结构》 《C++》 《Linux》
❤️感谢大家点赞👍收藏⭐评论✍️


在这里插入图片描述

文章目录

  • 前言
  • 一、优先级队列的使用
    • 1.1 基本功能
    • 1.2 优先级模式切换
    • 1.3 相关题目
  • 二、模拟实现优先级队列
    • 2.1 构造函数
    • 2.2 基本功能
    • 2.3 仿函数的使用
    • 2.4 特殊场景
  • 三、整体代码

前言

优先级队列 priority_queue 是容器适配器中的一种,常用来进行对数据进行优先级处理,比如优先级高的值在前面,这其实就是初阶数据结构中的 ,它俩本质上是一样东西,底层都是以数组存储的完全二叉树,不过优先级队列 priority_queue 中加入了 泛型编程 的思想,并且属于 STL 中的一部分


一、优先级队列的使用

首先需要认识一下优先级队列 priority_queue

在这里插入图片描述

1.1 基本功能

优先级队列的构造方式有两种:直接构造一个空对象通过迭代器区间进行构造

在这里插入图片描述

直接构造一个空对象

#include <iostream>
#include <vector>  //优先级队列包含在 queue 的头文件中
#include <queue>

using namespace std;

int main()
{
	priority_queue<int> pq;   //直接构造一个空对象, 默认为大堆
	cout << typeid(pq).name() << endl;   // 查看类型
	return 0;
}

在这里插入图片描述

注意: 默认比较方式为 less,最终为 优先级高的值排在上面(大堆

通过迭代器区间构造对象

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

int main()
{
	vector<char> v = { 'a', 'b', 'c', 'd', 'e' };
	priority_queue<char, deque<char>, greater<char>> pq(v.begin(), v.end());
	cout << typeid(pq).name() << endl << endl;
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}

	return 0;
}

在这里插入图片描述

注意: 将比较方式改为 greater 后,生成的是 小堆,并且如果想修改比较方式的话,需要指明模板参数 底层容器,因为比较方式位于模板参数最后,不能跳跃缺省(遵循缺省参数规则)

小测试27,15,19,18,28,34,65,49,25,37 分别生成大堆与小堆

大堆

vector<int> v = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
priority_queue<int, vector<int>, less<int>> pq(v.begin(), v.end());
//priority_queue<int, vector<int>> pq(v.begin(), v.end());  //写法一样

在这里插入图片描述

小堆

vector<int> v = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
priority_queue<int, vector<int>, greater<int>> pq(v.begin(), v.end());  //生成小堆

在这里插入图片描述

接下来使用优先级队列(以大堆为例)中的各种功能:入堆出堆查看堆顶元素查看堆中元素个数

在这里插入图片描述

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

void Print(const priority_queue<int>& pq)
{
	cout << "pq.empty(): " << pq.empty() << endl;
	cout << "pq.size(): " << pq.size() << endl;
	cout << "pq.top(): " << pq.top() << endl << endl;
}

int main()
{
	vector<int> v = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
	priority_queue<int, vector<int>> pq(v.begin(), v.end());  
	Print(pq);

	pq.push(10);
	pq.push(100);
	Print(pq);

	pq.pop();
	pq.pop();
	pq.pop();
	Print(pq);

	return 0;
}

在这里插入图片描述

1.2 优先级模式切换

创建优先级队列时,默认为 大堆,因为比较方式(仿函数)缺省值为 less,这个设计比较反人类,小于 less 是大堆,大于 greater 是小堆…

如果想要创建 小堆,需要将比较方式(仿函数)改为 greater

注意: 因为比较方式(仿函数) 位于参数3,而参数2也为缺省参数,因此如果想要修改参数3,就得指明参数2

priority_queue<int> pqBig;	//大堆
priority_queue<int, vector<int>, greater<int>> pqSmall;	//小堆

1.3 相关题目

优先级队列(堆)可以用来进行排序和解决 Top-K 问题,比如 查找第 k 个最大的值 就比较适合使用优先级队列

215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

思路1:利用数组建立大小为 k 的小堆,将剩余数据与堆顶值比较,如果大于,就入堆

  • 为什么建小堆?因为此时需要的是最大的值,建大堆可能会导致次大的值无法入堆
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int, vector<int>, greater<int>> pq(nums.begin(), nums.begin() + k);
        auto it = nums.begin() + k;
        while (it != nums.end())
        {
            if (*it > pq.top())
            {
                pq.pop();
                pq.push(*it);
            }
            ++it;
        }

        return pq.top();
    }
};

思路2:将数组排序,取第k个

bool myfunction (int i, int j) 
{ 
    return i > j; 
}

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        
        sort(nums.begin(),nums.end(), myfunction);
        return nums[k - 1];
    }
};

二、模拟实现优先级队列

优先级队列 priority_queue 属于容器适配器的一种,像栈和队列一样,没有迭代器,同时也不需要实现自己的具体功能,调用底层容器的功能就行了,不过因为堆比较特殊,需要具备 向上调整向下调整 的能力,确保符合堆的规则

2.1 构造函数

注: 现在实现的是没有仿函数的版本

优先级队列的基本框架为

#pragma once

namespace Aron
{
    //默认底层结构为 vector
	template<class T, class Container = vector<T>>
	class priority_queue
	{
	public:
	private:
		Container _con;
	};
}

默认构造函数:显式调用底层结构的默认构造函数

priority_queue()
	: _con()
{}

迭代器区间构造:将区间进行遍历,逐个插入即可

template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
	: _con()
{
	while (first != last)
	{
		push(*first);
		first++;
	}
}

测试:

void test_pq1()
{
	vector<int> arr = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
	priority_queue<int> pq(arr.begin(), arr.end());

	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
}

在这里插入图片描述

2.2 基本功能

因为是容器适配器,所以优先级队列也没有迭代器

同时基本功能也比较少,首先来看看比较简单的容量相关函数

容量相关

判断是否为空:复用底层结构的判空函数

bool empty() const
{
	return _con.empty();
}

获取优先级队列大小:复用获取大小的函数

size_t size() const
{
	return _con.size();
}

获取堆顶元素:堆顶元素即第一个元素(完全二叉树的根)

const T& top() const
{
	return _con.front();
}

注意: 以上三个函数均为涉及对象内容的改变,因此均使用 const 修饰 this 指针所指向的内容

数据修改

因为在插入/删除数据后,需要确保堆能符合要求

  • 大堆:父节点比子节点大
  • 小堆:父节点比子节点小

因此每进行一次数据修改相关操作,都需要检查当前堆结构是否被破坏,这一过程称为 调整

插入数据:尾插数据,然后向上调整

void push(const T& val)
{
	_con.push_back(val);
	adjust_up(size() - 1);
}

向上调整:将当前子节点与父节点进行比较,确保符合堆的特性,如果不符合,需要进行调整

void adjust_up(size_t child)
{
	size_t parent = (child - 1) / 2;

	while (child != 0)
	{
		if (_con[child] > _con[parent])
		{
			std::swap(_con[child], _con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

注意: 如果在调整过程中,发现遵循堆的特性,那么此时不需要再调整,直接 break 即可

删除数据:将堆顶数据交换至堆底,删除堆底元素,再向下调整堆

void pop()
{
	if (empty())
		return;
	std::swap(_con.front(), _con.back());
	_con.pop_back();
	adjust_down(0);
}

向下调整:将当前父节点与 【较大 / 较小】 子节点进行比较,确保符合堆的特性,如果不符合,需要进行调整

void adjust_down(size_t parent)
{
	size_t child = parent * 2 + 1;

	while (child < size())
	{
		if (child + 1 < size() && _con[child + 1] > _con[child])
			child++;

		if (_con[child] > _con[parent])
		{
			std::swap(_con[child], _con[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

注意: 删除时,需要先判断当前堆是否为空,空则不执行删除

测试:

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

#include "priority_queue.h"

void Print(const Aron::priority_queue<int>& pq)
{
	cout << "pq.empty(): " << pq.empty() << endl;
	cout << "pq.size(): " << pq.size() << endl;
	cout << "pq.top(): " << pq.top() << endl << endl;
}

int main()
{
	vector<int> v = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
	Aron::priority_queue<int, vector<int>> pq(v.begin(), v.end());  
	Print(pq);
	
	pq.push(10);
	pq.push(100);
	Print(pq);
	
	pq.pop();
	pq.pop();
	pq.pop();
	Print(pq);
	
	return 0;
}

在这里插入图片描述

假设先使用 小堆,需要将下图中的三处逻辑判断,改为 <

在这里插入图片描述

难道每次使用时都得手动切换吗?而且如果我想同时使用大堆和小堆时该怎么办?

  • 答案是没必要,通过 仿函数 可以轻松解决问题,这也是本文的重点内容

2.3 仿函数的使用

仿函数又名函数对象 function objects,仿函数的主要作用是 借助类和运算符重载,做到同一格式兼容所有函数 这有点像函数指针,相比于函数指针又长又难理解的定义,仿函数的使用可谓是很简单了

下面是两个仿函数,作用是比较大小

template<class T>
struct less
{
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

template<class T>
struct greater
{
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

此时 priority_queue 中的模板参数升级为3个,而参数3的缺省值就是 less

template<class T, class Container = vector<T>, class Comper = less<T>>

当需要进行逻辑比较时(大小堆需要不同的比较逻辑),只需要调用 operator() 进行比较即可

这里采用的是匿名对象调用的方式,当然也可以直接实例化出一个对象,然后再调用 operator() 进行比较

在使用仿函数后,向上调整向下调整 变成了下面这个样子

void adjust_up(size_t child)
{
	size_t parent = (child - 1) / 2;

	while (child != 0)
	{
		if (Comper()(_con[parent], _con[child]))  //匿名对象调用 operator()
		{
			std::swap(_con[child], _con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

void adjust_down(size_t parent)
{
	size_t child = parent * 2 + 1;

	while (child < size())
	{
		if (child + 1 < size() && Comper()(_con[child], _con[child + 1]))
			child++;

		if (Comper()(_con[parent], _con[child]))
		{
			std::swap(_con[child], _con[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

使用仿函数后,可以轻松切换为小堆

void Print(const Aron::priority_queue<int, vector<int>, Aron::greater<int>>& pq)
{
	cout << "pq.empty(): " << pq.empty() << endl;
	cout << "pq.size(): " << pq.size() << endl;
	cout << "pq.top(): " << pq.top() << endl << endl;
}

int main()
{
	vector<int> v = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
	Aron::priority_queue<int, vector<int>, Aron::greater<int>> pq(v.begin(), v.end());  
	Print(pq);
	
	pq.push(10);
	pq.push(100);
	Print(pq);
	
	pq.pop();
	pq.pop();
	pq.pop();
	Print(pq);
	
	return 0;
}

在这里插入图片描述

注意: 为了避免自己写的仿函数名与库中的仿函数名起冲突,最好加上命令空间,访问指定域中的仿函数

仿函数作为 STL 六大组件之一,处处体现着泛型编程的思想

在这里插入图片描述

仿函数给我们留了很大的发挥空间,只要我们设计的仿函数符合调用规则,那么其中的具体比较内容可以自定义(后续在进行特殊场景的比较时,作用很大)

2.4 特殊场景

假设此时存在 日期类(部分)

class Date

class Date
{
public:
	Date(int year = 1970, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
	friend std::ostream& operator<<(std::ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

创建数据为 Date 的优先级队列(大堆),取堆顶元素(判断是否能对自定义类型进行正确调整)

void test_pq2()
{
	priority_queue<Date> pq;
	pq.push(Date(2013, 4, 30));
	pq.push(Date(2014, 5, 30));
	pq.push(Date(2024, 5, 1));
	cout << pq.top() << endl;
}

在这里插入图片描述

结果:正确,因为在实际比较时,调用的是 Date 自己的比较逻辑,所以没问题

但如果此时数据为 Date*,再进行比较

结果:错误,多次运行结果不一样!因为此时调用的是指针的比较逻辑(地址是随机的,因此结果也是随机的)

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

解决方法:

  1. 通过再编写指针的仿函数解决
  2. 通过模板特化解决

这里介绍法1,法2在下篇文章《模板进阶》中讲解

仿函数给我们提供了极高的自由度,因此可以专门为 Date* 编写一个仿函数(曲线救国)

template<class T>
struct DateLess
{
	bool operator()(const T& x, const T& y)
	{
		return *x < *y;
	}
};

template<class T>
struct DateGreater
{
	bool operator()(const T& x, const T& y)
	{
		return *x > *y;
	}
};

在构建对象时,带上对对应的 仿函数 就行了

void test_pq3()
{
	priority_queue<Date*, vector<Date*>, DateLess<Date*>> p1;
	p1.push(new Date(2013, 4, 30));
	p1.push(new Date(2014, 5, 30));
	p1.push(new Date(2024, 5, 1));
	cout << *(p1.top()) << endl;

	priority_queue<Date*, vector<Date*>, DateGreater<Date*>> p2;
	p2.push(new Date(2013, 4, 30));
	p2.push(new Date(2014, 5, 30));
	p2.push(new Date(2024, 5, 1));
	cout << *(p2.top()) << endl;
}

在这里插入图片描述

关于 Date* 仿函数的具体调用过程,可以自己下去通过调试观察


三、整体代码

priority_queue.h

#pragma once

namespace Aron
{
	class Date
	{
	public:
		Date(int year = 1970, int month = 1, int day = 1)
			: _year(year)
			, _month(month)
			, _day(day)
		{}
		bool operator<(const Date& d)const
		{
			return (_year < d._year) ||
				(_year == d._year && _month < d._month) ||
				(_year == d._year && _month == d._month && _day < d._day);
		}
		bool operator>(const Date& d)const
		{
			return (_year > d._year) ||
				(_year == d._year && _month > d._month) ||
				(_year == d._year && _month == d._month && _day > d._day);
		}
		friend std::ostream& operator<<(std::ostream& _cout, const Date& d)
		{
			_cout << d._year << "-" << d._month << "-" << d._day;
			return _cout;
		}
	private:
		int _year;
		int _month;
		int _day;
	};

	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	template<class T>
	struct DateLess
	{
		bool operator()(const T& x, const T& y)
		{
			return *x < *y;
		}
	};

	template<class T>
	struct DateGreater
	{
		bool operator()(const T& x, const T& y)
		{
			return *x > *y;
		}
	};

	/*template<class T>
	struct less<T*>
	{
		bool operator()(const T& x, const T& y)
		{
			return *x < *y;
		}
	};

	template<class T>
	struct greater<T*>
	{
		bool operator()(const T& x, const T& y)
		{
			return *x > *y;
		}
	};*/

	template<class T, class Container = vector<T>, class Comper = less<T>>
	class priority_queue
	{
	public:
		priority_queue()
			: _con()
		{}

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			: _con()
		{
			while (first != last)
			{
				push(*first);
				first++;
			}
		}

		bool empty() const
		{
			return _con.empty();
		}

		size_t size() const
		{
			return _con.size();
		}

		const T& top() const
		{
			return _con.front();
		}

		void push(const T& val)
		{
			_con.push_back(val);
			adjust_up(size() - 1);
		}

		void pop()
		{
			if (empty())
				return;
			std::swap(_con.front(), _con.back());
			_con.pop_back();
			adjust_down(0);
		}

	protected:
		void adjust_up(size_t child)
		{
			size_t parent = (child - 1) / 2;

			while (child != 0)
			{
				if (Comper()(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
					break;
			}
		}

		void adjust_down(size_t parent)
		{
			size_t child = parent * 2 + 1;

			while (child < size())
			{
				if (child + 1 < size() && Comper()(_con[child], _con[child + 1]))
					child++;

				if (Comper()(_con[parent], _con[child]))
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}

	private:
		Container _con;
	};

	void test_pq1()
	{
		vector<int> arr = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
		priority_queue<int> pq(arr.begin(), arr.end());

		while (!pq.empty())
		{
			cout << pq.top() << " ";
			pq.pop();
		}
	}
    
    void test_pq2()
    {
        priority_queue<Date> pq;
        pq.push(Date(2013, 4, 30));
        pq.push(Date(2014, 5, 30));
        pq.push(Date(2024, 5, 1));
        cout << pq.top() << endl;
    }

	void test_pq3()
	{
		priority_queue<Date*, vector<Date*>, DateLess<Date*>> p1;
		p1.push(new Date(2013, 4, 30));
		p1.push(new Date(2014, 5, 30));
		p1.push(new Date(2024, 5, 1));
		cout << *(p1.top()) << endl;

		priority_queue<Date*, vector<Date*>, DateGreater<Date*>> p2;
		p2.push(new Date(2013, 4, 30));
		p2.push(new Date(2014, 5, 30));
		p2.push(new Date(2024, 5, 1));
		cout << *(p2.top()) << endl;
	}
}

在这里插入图片描述

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

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

相关文章

AI赋能不应贵气:深度解读AI助力企业渡过经济寒冬以及如何落地AI的路径

AI很棒可是给人感觉“很贵”因此我不敢用 继GPT4后Dalle3、Sora、GPT4.5、GPT5的消息以及前天突然出现的GPT 2.0&#xff08;GPT二代&#xff0c;有人说这就是OPEN AI的新产品&#xff1a;Q*&#xff09;但凡涉及到AI的一系列新闻给人予很震撼的感觉。放眼望去AI正在欣欣向荣。…

洛谷 P5854:【模板】笛卡尔树

【题目来源】https://www.luogu.com.cn/problem/P5854【题目描述】 给定一个 1∼n 的排列 p&#xff0c;构建其笛卡尔树。 即构建一棵二叉树&#xff0c;满足&#xff1a; 1.每个节点的编号满足二叉搜索树的性质。← 优先级 pri 满足二叉搜索树&#xff08;BST&#xff09;的性…

强化学习(Reinforcement learning)基本概念

概念&#xff1a; 强化学习是在与环境互动中为达到一个目标而进行的学习过程 三层结构&#xff1a; 基本元素&#xff1a;agent、environment、goal agent&#xff1a;可以理解为玩家&#xff0c;即某个游戏的参与方 environment&#xff1a;环境本身&#xff0c;可以理…

Web后端开发中对三层架构解耦之控制反转与依赖注入

内聚与耦合 内聚 比如说我们刚刚书写的员工的实现类 在这里我们仅仅书写的是和员工相关的代码 而与员工无关的代码都没有放到这里 说明内聚程度较高 耦合 以后软件开发要高内聚 低耦合 提高程序灵活性 扩拓展性 分析代码 如何解耦 创建容器 提供一个容器 存储东西 存储E…

基于FPGA的数字信号处理(5)--Signed的本质和作用

前言 Verilog中的signed是一个很多人用不好&#xff0c;或者说不太愿意用的一个语法。因为不熟悉它的机制&#xff0c;所以经常会导致运算结果莫名奇妙地出错。其实了解了signed以后&#xff0c;很多时候用起来还是挺方便的。 signed的使用方法主要有两种&#xff0c;其中一种…

Android View事件分发面试问题及回答

问题 1: 请简述Android中View的事件分发机制是如何工作的&#xff1f; 答案: 在Android中&#xff0c;事件分发机制主要涉及到三个主要方法&#xff1a;dispatchTouchEvent(), onInterceptTouchEvent(), 和 onTouchEvent(). 当一个触摸事件发生时&#xff0c;首先被Activity的…

配置 Trunk,实现相同VLAN的跨交换机通信

1.实验环境 公司的员工人数已达到 100 人&#xff0c;其网络设备如图所示。现在的网络环境导致广播较多网速慢&#xff0c;并且也不安全。公司希望按照部门划分网络&#xff0c;并且能够保证一定的网络安全性。 其网络规划如下。 PC1和 PC3为财务部&#xff0c;属于VLAN 2&…

邦注科技 温控箱对企业的重要性

注塑加工是将加热的熔融塑料注入模具中形成所需产品的工艺过程。良好的注塑加工工艺需要控制好许多参数&#xff0c;其中最重要的因素之一就是模具的温度。模具温度的不稳定会导致产品尺寸大小、表面缺陷等方面的问题&#xff0c;甚至会导致生产不良品&#xff0c;加大生产成本…

Educational Codeforces Round 165 (Rated for Div. 2 ABCDE 题)视频讲解

A. Two Friends Problem Statement Monocarp wants to throw a party. He has n n n friends, and he wants to have at least 2 2 2 of them at his party. The i i i-th friend’s best friend is p i p_i pi​. All p i p_i pi​ are distinct, and for every i ∈…

通义灵码实战系列:一个新项目如何快速启动,如何维护遗留系统代码库?

作者&#xff1a;别象 进入 2024 年&#xff0c;AI 热度持续上升&#xff0c;翻阅科技区的文章&#xff0c;AI 可谓是军书十二卷&#xff0c;卷卷有爷名。而麦肯锡最近的研究报告显示&#xff0c;软件工程是 AI 影响最大的领域之一&#xff0c;AI 已经成为了软件工程的必选项&…

FLUKE万用表17B+的电压档最大内阻

项目中遇到一个测量兆欧级别电阻两端电压的问题&#xff0c;发现按照上图中的电路搭建出来的电路测得的电压为8.25V左右&#xff0c;按理说应为9V才对&#xff0c;后来想到万用表测量电压档不同的档位会有不同内阻&#xff0c;测量的电阻应远小于万用表电压档内阻才有效。本次测…

顶尖页面性能优化跃升之道:uniapp首屏加载性能极致优化策略权威指南(白屏现象终结攻略)

页面加载性能优化至关重要&#xff0c;直接影响用户体验满意度及网站流量转化。优化加载性能可以减少用户等待时间&#xff0c;提升交互响应&#xff0c;有效减少出现白屏的情况&#xff0c;增加用户留存&#xff0c;同时有利于搜索引擎排名&#xff0c;对网站流量、品牌形象及…

【常规】解决win11的Edge浏览器掉线问题

文章目录 【问题】【解决】step1 右键点击wifi--【网络和Internet设置】step2 点击打开后&#xff0c;打开【高级网络设置】后边的箭头step3 进入下一级以后&#xff0c;点击【WLAN】右侧的箭头step4 【更多适配选项】--【编辑】step5 取消Internet协议版本6&#xff08;TCP/IP…

php反序列化字符串逃逸

字符串逃逸 字符串逃逸是通过改变序列化字符串的长度造成的php反序列化漏洞 一般是因为替换函数使得字符串长度发生变化&#xff0c;不论变长还是变短&#xff0c;原理都大致相同 在学习之前&#xff0c;要先了解序列化字符串的结构&#xff0c;在了解结构的基础上才能更好理解…

Qt Creator导入第三方so库和jar包——Qt For Android

前言 之前了解了在Android Studio下导入so库和jar包&#xff0c;现在实现如何在Qt上导入so库和jar包。 实现 下面是我安卓开发&#xff08;需调用安卓接口的代码&#xff09;的目录&#xff08;图1&#xff09;&#xff0c;此目录结构和原生态环境&#xff08;Android Studi…

PS证件照

证件照尺寸 小一寸&#xff1a;2.2cm*3.3cm 一寸&#xff1a;2.5cm*3.5cm 像素413*295 &#xff08;分辨率为300像素/英寸&#xff09; 比例5&#xff1a;7 二寸&#xff1a;3.5cm*4.9cm 二寸照相比例是4&#xff1a;3&#xff0c;像素是626*413 蓝底&#xff1a;R&a…

python学习之词云图片生成

代码实现 import jieba import wordcloudf open("D:/Pythonstudy/data/平凡的世界.txt", "r", encoding"utf-8") t f.read() print(t) f.close() ls jieba.lcut(t) txt " ".join(ls)w wordcloud.WordCloud(font_path"D:/cc…

【Unity动画系统】详解Root Motion动画在Unity中的应用(二)

Root Motion遇到Blend Tree 如果Root Motion动画片段的速度是1.8&#xff0c;那么阈值就要设置为1.8&#xff0c;那么在代码中的参数就可以直接反映出Root Motion的最终移动速度。 Compute Thresholds&#xff1a;根据Root Motion中某些数值自动计算这里的阈值。 Velocity X/…

使用 Python 和 OpenCV 进行实时目标检测的详解

使用到的模型文件我已经上传了&#xff0c;但是不知道能否通过审核&#xff0c;无法通过审核的话&#xff0c;就只能 靠大家自己发挥实力了&#xff0c;^_^ 目录 简介 代码介绍 代码拆解讲解 1.首先&#xff0c;让我们导入需要用到的库&#xff1a; 2.然后&#xff0c;设…

《QT实用小工具·四十三》历史编辑器(支持历史搜索 关键字匹配)

1、概述 源码放在文章末尾 该项目实现了在输入框中输入部分信息能全部展现之前的历史输入信息&#xff0c;支持历史搜索和关键词匹配&#xff0c;项目demo演示如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #include "historymodel.h" #include <QM…