STL-Setmap

前言

大家好,我是jiantaoyab,我们将进入到C++STL 的学习。STL在各各C++的头文件中,以源代码的形式出现,不仅要会用,还要了解底层的实现。源码之前,了无秘密。

STL六大组件

image-20240323151905853

Container通过Allocator取得数据储存空间,Algorithm通过Iterator存取Container内容,Functor可以协助Algorithm完成不同的策略变化,Adapter可以修饰或者套接Functor。

关联式容器associative containers

Set

image-20240428231352539

  1. set是按照一定次序存储元素的容器
  2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  5. set在底层是用二叉搜索树(红黑树)实现的

注意:

  1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。

  2. set中的元素不可以重复(因此可以使用set进行去重)。multiset能插入重复的值,如果查找的话找的第一个节点是中序遍历的第一个节点

  3. set中的元素默认按照小于来比较,使用set的迭代器遍历set中的元素,可以得到有序序列

set的基本使用

//构造
void const()
{
   std::set<int> first;                           // empty set of ints
   int myints[]= {10,20,30,40,50};
   std::set<int> second (myints,myints+5);        // range
   std::set<int> third (second);                  // a copy of second
   std::set<int> fourth (second.begin(), second.end());  // iterator ctor.
   std::set<int,classcomp> fifth;                 // class as Compare
}

//插入
void insert()
{
    std::set<int> myset;
    std::set<int>::iterator it;
    std::pair<std::set<int>::iterator, bool> ret;
    
    for(int i = 1; i <= 5; i++) myset.insert(i);
    ret = myset.insert(2); //插入失败
    if(ret.second == false) it = ret.first; //指向20
    myset.insert(it, 9);
    
    for(it = myset.begin(); it != myset.end(); it++)
    {
        cout << *it <<" ";
	}
}


//查找
void find()
{
    std::set<int> myset;
    std::set<int>::iterator it;
    for(int i = 1; i <= 5; i++) myset.insert(i);
    it = myset.find(3);
    myset.erase(it);
}

Map

image-20240428233232502

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素,key值是不能修改的

  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair

  3. 在内部,map中的元素总是按照键值key进行比较排序的。

  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。

  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

  6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

    image-20240428233831725

在正式使用Map之前先看看pair和make_pair

image-20240428233452384

make_pair在pair的基础上做了一个自动推导

image-20240428234502828

可以看到pair是一个结构体里面有2个值,第一个叫first,第二个值叫second。在map中first的值就是key,second的值是value。

Map的使用

//pair<iterator,bool> insert (const value_type& val);
//返回值是一个pair
void  insert()
{
    map<string, string> dict;
    //假设插入失败
    auto it = dict.insert(make_pair("peach","桃子"));
    cout<< it.first->second <<end; //false
}
int main()
{
    pair<string, string> kv("apple", "苹果");
    map<string, string> dict;
    dict.insert(kv);   
    dict.insert(pair<string, string>("banana", "香蕉"); //匿名对象
    dict.inset(make_pair("grape", "葡萄"));
    map<string, string>::iterator it = dict.begin();
	while(it != dict.end())
    {
       // cout << *(it).first << ":" << *(it).second << " ";
   cout << it->first << ":" << it->second <<" " ; // map里面->进行了重载 ->->
	}
}

map中的[]

在C++中,可以通过下标操作符[]来访问和修改Map中的值。如果要修改一个键对应的值,可以直接用下标操作符访问该键然后赋予新值。如果该键不存在,则会在Map中创建一个新键,并赋予默认初始化的值。

image-20240506200301855

image-20240506200623063

调用完inset返回的是一个pair,.first取出iterator,iterator是指向插入的或者是已近存在的那个元素,*(iterator).first得到pair<const Key, T>,再.second得到T。

红黑树

image-20240506195546485

红黑树的性质:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL节点或空节点)是黑色。注意,这里的叶子节点指的是NIL节点或空节点。(NIL节点在红黑树中通常指的是空节点或叶子节点的占位符。在红黑树的实现中,为了简化逻辑和保证性质,通常假设每个节点都有两个子节点,即使这些子节点实际上并不存在。这些不存在的子节点由NIL节点(或称为空节点、哑节点、哨兵节点)来表示。)
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的。这一性质保证了不会出现连续的红色节点,有助于维护树的平衡性。
  5. 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。这一性质被称为“黑色节点路径长度相等”,它确保了红黑树的高度始终在对数级别。

模拟实现红黑树

红黑树节点

enum Color
	{
		RED,
		BLACK
	};

	template<class K, class V>
	struct RBTreeNode
	{
		RBTreeNode<K, V>* _left;
		RBTreeNode<K, V>* _parent;
		RBTreeNode<K, V>* _right;
		Color _col;
		pair<K, V> _kv;
		RBTreeNode(const pair<K, V>& kv)
			:_left(nullptr)
			, _parent(nullptr)
			, _right(nullptr)
			, _col(RED) //默认给红色
			, _kv(kv)
		{}
	};

红黑树

//插入
bool insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}
	Node* cur = _root;
	Node* parent = nullptr;

	while (cur)
	{
		if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;
		}

	}
	cur = new Node(kv);
	cur->_col = RED;
	if (parent->_kv.first > kv.first)
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}


	//控制平衡
	while (parent && parent->_col == RED)
	{
		Node* g = parent->_parent;
		if (parent == g->_left)
		{
			Node* u = g->_right;
			//1.u存在且为红
			if (u && u->_col == RED)
			{
				//变色
				parent->_col = BLACK;
				u->_col = BLACK;
				g->_col = RED;
				// 向上处理
				cur = g;
				parent = cur->_parent;
			}

			//u不存在/u存在且为黑
			else
			{
				//          g
				//       p
				//  cur
				//右单旋
				if (cur == parent->_left)
				{
					RotateR(g);
			   	 	g->_col = RED;
					parent->_col = BLACK;
				}
				//      g
				//   p
				//      cur
				//左右双旋
				else
				{
					RotateL(parent);
					RotateR(g);
					cur->_col = BLACK;
					g->_col = RED;
				}
					break;
			}
		}
		//(parent == g->_right)
		else
		{
			Node* u = g->_left;
			//1.u存在且为红
			if (u&& u->_col == RED)
			{
				//变色
				parent->_col = BLACK;
				u->_col = BLACK;
				g->_col = RED;
				// 向上处理
				cur = g;
				parent = cur->_parent;
			}
			//u不存在 /u存在且为黑
			else
			{
				//    g
				//       p
				//          cur
			     if (parent->_right = cur)
				{
					RotateL(g);
					g->_col = RED;
					parent->_col = BLACK;
				}
				//    g
				//        p
				//   cur
				else
				{
					RotateR(parent);
					RotateL(g);
					cur->_col = BLACK;
					g->_col = RED;
				}
						break;
			}
		   }
			}
			_root->_col = BLACK;
			return true;
}

//判断平衡

bool _IsBalance(Node* root, const int refernum, int actualnum)
{
	if (root == nullptr)
	{
		if (refernum != actualnum)
		{
			cout << "实际值的黑色节点数目和参考值不一样" << endl;
			return false;
		}
		else return true;
	}

	if (root->_col == RED && root->_parent->_col == RED)
	{
		cout << "parent和cur都为红,出现连续的红节点" << endl;
		return false;
	}

	if (root->_col == BLACK)
		++actualnum;

	return _IsBalance(root->_left, refernum, actualnum)
				&& _IsBalance(root->_right, refernum, actualnum);

}
bool IsBalance()
{
	if (_root && _root->_col == RED)
	{
		cout << "根节点为红色" << endl;
		return false;
	}
		//选择一条路径记录黑色节点的数量做参考值
		int refernum = 0;
		Node* left = _root;
	while (left)
	{
	    if(left->_col == BLACK)
        {
           refernum++;
		  left = left->_left;
        }
			
	}
	int actualnum = 0;
	return _IsBalance(_root, refernum, actualnum);
}

红黑树模拟实现STL中的map和set

由于想要红黑树即能存k也能存pair,所以对上面的代码进行改造

红黑树部分

enum Color
{
	RED,
	BLACK
};

//T 代表  K或者是 pair<K,V>
template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _parent;
	RBTreeNode<T>* _right;
	Color _col;
	T _date; //用date,因为值是什么类型的并不知道
	RBTreeNode(const T& date)
		:_left(nullptr)
		, _parent(nullptr)
		, _right(nullptr)
		, _col(RED) //默认给红色
		, _date(date)
	{}
};

//map <class k,class V,MapKeyOfT>
//set <class k,class k,SetKeyOfT>
//通过KeyOfT返回值来用 
template < class K, class T, class KeyOfT>
class RBTree
{
public:
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, T&, T*> iterator;
	typedef RBTreeIterator<T, const T&, const T*> const_iterator;

	//开始就是中序最小的值
	iterator begin() 
	{
		Node* cur = _root;
		while (cur&& cur->_left)
			cur = cur->_left;
		return iterator(cur);
	}

	iterator end()
	{
		return iterator(nullptr);
	}


	RBTree()
		:_root(nullptr)
	{}

	RBTree(const RBTree<K, T, KeyOfT>& tree)
	{
		_root = Copy(tree._root);
	}

	RBTree<K, T, KeyOfT>& operator=(RBTree<K, T, KeyOfT> t)
	{
		swap(_root, t);
		return *this;
	}

	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}
private:

	void Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}

	Node * Copy(Node* root)
	{

		if (root == nullptr)
			return nullptr;

		//生成一个新根+换颜色
		Node* newtree = new Node(root->_date);
		newtree->_col = root->_col;

		newtree->_left = Copy(root->_left);
		newtree->_right = Copy(root->_right);

		//处理newtree的parent
		if (newtree->_left)
			newtree->_left->_parent = newtree;
		else
		{
			newtree->_right->_parent = newtree;			
		}

		return newtree; 
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* parentparent = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		//parent是别人的子树
		else
		{
			if (parentparent->_left == parent)
				parentparent->_left = subL;
			else
				parentparent->_right = subL;

			subL->_parent = parentparent;
		}

		parent->_left = subLR;
		//subLR 可能不存在
		if (subLR)
		{
			subLR->_parent = parent;
		}


	}
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		if (subRL)
		{
			subRL->_parent = parent;
		}
		Node* parentparent = parent->_parent;
		if (parent == _root)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (parentparent->_left == parent)
				parentparent->_left = subR;
			else
				parentparent->_right = subR;
			subR->_parent = parentparent;
		}
		subR->_left = parent;
		parent->_parent = subR;
		parent->_right = subRL;
	}


public:
	pair<iterator, bool> insert(const T& date)
	{

		if (_root == nullptr)
		{
			_root = new Node(date);
			_root->_col = BLACK;
			return make_pair(iterator(_root),true);
		}

		Node* cur = _root;
		Node* parent = nullptr;
		KeyOfT key;
		while (cur)
		{
			if (key(cur->_date) > key(date))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (key(cur->_date) < key(date))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return make_pair(iterator(cur), false);
			}

		}

		cur = new Node(date);
		Node* newnode = cur;
		cur->_col = RED;//新增给红,只影响新增所在的路径
		if (key(parent->_date) > key(date))
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = cur;
			cur->_parent = parent;
		}


		//控制平衡
		while (parent && parent->_col == RED)
		{
			Node* g = parent->_parent;
			if (parent == g->_left)
			{
				Node*u = g->_right;
				//1.u存在且为红
				if (u&& u->_col == RED)
				{
					//变色
					parent->_col = BLACK;
					u->_col = BLACK;
					g->_col = RED;
					// 向上处理
					cur = g;
					parent = cur->_parent;
				}

				//u不存在/u存在且为黑
				else
				{
					//          g
					//       p
					//  cur
					//右单旋
					if (cur == parent->_left)
					{
						RotateR(g);
						g->_col = RED;
						parent->_col = BLACK;
					}
					//      g
					//   p
					//      cur
					//左右双旋
					else
					{
						RotateL(parent);
						RotateR(g);
						cur->_col = BLACK;
						g->_col = RED;
					}

					break;
				}

			}
			//(parent == g->_right)
			else
			{
				Node* u = g->_left;
				//1.u存在且为红
				if (u&& u->_col == RED)
				{
					//变色
					parent->_col = BLACK;
					u->_col = BLACK;
					g->_col = RED;
					// 向上处理
					cur = g;
					parent = cur->_parent;
				}
				//u不存在 /u存在且为黑
				else
				{
					//    g
					//       p
					//          cur
					if (parent->_right = cur)
					{
						RotateL(g);
						g->_col = RED;
						parent->_col = BLACK;
					}
					//    g
					//        p
					//   cur
					else
					{
						RotateR(parent);
						RotateL(g);
						cur->_col = BLACK;
						g->_col = RED;
					}

					break;
				}
			}
		}
		
		_root->_col = BLACK;
		return make_pair(iterator(newnode), true);
	}

	
private:
	Node* _root;

};

红黑树迭代器

template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr>Self;
	Node* _node;

	//节点来构造迭代器
	RBTreeIterator(Node* node)
		:_node(node)
	{}

	Ref operator*()
	{
		return _node->_date;
	}

	Ptr operator->()
	{
		return &_node->_date;//返回date的地址 ->优先级高
	}

	//中序
	Self& operator++(){
		// 1.如果右树不为空就访问右树最左节点
		if (_node->_right){
			Node* min = _node->_right;
			while (min->_left){
				min = min->_left;
			}
			_node = min;
		}
		//2.右树为空,说明所在子树访问完了
		else{
			Node* cur = _node;
			Node* parent = cur->_parent;
			//沿着到根路径往上走
			while (parent && cur == parent->_right){
				cur = cur->_parent;
				parent = parent->_parent;
			}
			//找左孩子是父亲的祖父节点,继续更新直到父亲为空
			_node = parent;
		}

		return *this;
	}


	Self& operator--(){

		//1.访问左子树最右节点
		if (_node->_left){
			Node* max= _node->_left;
			while (max->_right){
				max = max->_right;
			}

			_node = max;
		}
		//2.左为空说明访问完了
		else{
			Node* cur = _node;
			Node* parent = cur->_parent;
			//沿着到根路径往上走
			while (parent &&cur==parent->left){
				cur = cur->_parent;
				parent = parent->_parent;
			}
			//找右孩子是父亲的祖父节点,继续更新直到父亲为空
			_node = parent;

		}
		return *this;
	}
	
	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}

	bool operator==(const Self& s)  const
	{
		return _node == s._node;
	}

};

map.h

#pragma once
namespace jt
{
	template<class K,class V>
	class map
	{
	public:
		struct MapKeyOfT
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}
		};

		typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
		
		iterator begin()
		{
			return _t.begin();
		}

		iterator end()
		{
			return _t.end();
		}

		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _t.insert(kv);
		}
		
		V& operator[](const K& key)
		{
			auto ret = _t.insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};

}

set.h

namespace jt
{
	template<class K>
	class set
	{
	public:

		struct SetKeyOfT
		{
			const K& operator()(const K& k)
			{
				return k;
			}
		};

		typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;

		iterator begin()
		{
			return _t.begin();
		}

		iterator end()
		{
			return _t.end();
		}

		pair<iterator, bool> insert(const K& key)
		{
			return _t.insert(key);
		}

	private:
		RBTree<K, K, SetKeyOfT> _t;
	};

}

map和set是适配器吗?

容器:容器是存储数据的对象,这些对象提供了对它们所包含元素的访问。C++ 标准库提供了多种容器,如 vector, list, deque, map, set, unordered_map, unordered_set 等。

适配器:适配器是设计模式中的一种,它允许将一个类的接口转换为客户端所期望的另一个接口。在 C++ 标准库中,适配器通常是指那些不直接存储数据,但提供对数据的访问或修改操作的类。常见的适配器包括 stack, queue, priority_queue 等,它们通常基于其他容器(如 deque)来实现。

mapset 是直接存储数据的容器。它们内部有自己的数据结构(通常是红黑树)来存储和管理元素。与此不同,适配器通常不直接存储数据,而是基于其他容器来提供特定的接口或行为。

例如,stack 是一个适配器,它基于一个底层容器(如 deque)来提供栈的行为(如 push, pop, top 等)。但 stack 本身并不存储数据,它只是将 deque 的接口转换为栈的接口。

另一方面,map 提供了键值对的存储和查找,而 set 提供了唯一元素的存储和查找。这些功能是通过它们自己的数据结构和算法来实现的,而不是通过适配其他容器的接口。因此,mapset 被归类为容器,而不是适配器。

红黑树与AVL树对比

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(log2N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,红黑树的设计确保了任何不平衡都可以在三次旋转之内解决。所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

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

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

相关文章

系统集成项目管理工程师第4章思维导图发布

2024年开年&#xff0c;软考系统集成项目管理工程师官方教程&#xff0c;迎来了阔别7年的大改版&#xff0c;改版之后的软考中项考试&#xff0c;离同宗兄弟高项考试渐行渐远。 中项第3版教程&#xff0c;仅仅从教程来看&#xff0c;其难度已经不亚于高级的信息系统项目管理师&…

Android Studio连接MySQL8.0

【序言】 移动平台这个课程要做一个app的课设&#xff0c;我打算后期增加功能改成毕设&#xff0c;就想要使用MySQL来作为数据库&#xff0c;相对于SQLlite来说&#xff0c;我更熟悉MySQL一点。 【遇到的问题】 一直无法连接上数据库&#xff0c;开始的时候查了很多资料&#…

Linux:进程概念(三.详解进程:进程状态、优先级、进程切换与调度)

上次讲了进程这些内容&#xff1a;Linux&#xff1a;进程概念&#xff08;二.查看进程、父进程与子进程、进程状态详解&#xff09; 文章目录 1.Linux中的进程状态1.1前台进程和后台进程运行状态睡眠状态磁盘休眠状态停止状态kill指令—向进程发送信号 死亡状态 2.僵尸进程2.1僵…

一文读懂NVIDIA AI全景:从芯片到应用,全面解析未来科技

英伟达 NVIDIA AI 全景解析 NVIDIA 概述 公司概况 NVIDIA作为全球顶尖科技公司&#xff0c;早期深耕图形处理器设计制造&#xff0c;现已跃升为人工智能领域的领军者&#xff0c;产品和服务覆盖AI应用的全方位&#xff0c;引领科技潮流。 NVIDIA&#xff0c;1993年创立于美国…

机器学习实战宝典:用scikit-learn打造智能应用

书接上文——《数据探险家的终极指南&#xff1a;用Python挖掘机器学习的奥秘》 前文我们在这段精彩的机器学习探险之旅中&#xff0c;从基础概念出发&#xff0c;深入探索了使用Python和scikit-learn库进行数据分析和模型构建的全过程。 我们首先了解了机器学习的基本原理&am…

RabbitMQ - 以 MQ 为例,手写一个 RPC 框架 demo

目录 前言 一、再谈自定义应用层协议 二、再谈 BrokerServer 三、再谈 Connection、Channel 四、Demo a&#xff09;启动服务器 b&#xff09;客户端连接 前言 本篇文章来自于笔者之前写过的一个系列 —— “根据源码&#xff0c;模拟实现 RabbitMQ” 系列&#xff0c…

WPF之工具栏菜单栏功能区。

1&#xff0c;菜单栏&#xff0c;工具栏&#xff0c;状态栏。 1.1&#xff0c;Menu中可添加菜单分隔条<Separator></Separator>作为分割线&#xff0c;使用Separator可以通过改变其template来自定义&#xff0c;Separator是无焦点的&#xff0c;如果简单的在MenuIt…

c++ 获取机器码

看到网上代码代码都没什么好的&#xff0c;自己备用一个 #include <iostream> #include <string> #include <sstream> #include <iomanip> #include <Windows.h> #include <iphlpapi.h> // 包含这个头文件以获取 PIP_ADAPTER_INFO #inclu…

面试官:SPA(单页应用)首屏加载速度慢怎么解决

一、什么是首屏加载 首屏时间&#xff08;First Contentful Paint&#xff09;&#xff0c;指的是浏览器从响应用户输入网址地址&#xff0c;到首屏内容渲染完成的时间&#xff0c;此时整个网页不一定要全部渲染完成&#xff0c;但需要展示当前视窗需要的内容 首屏加载可以说是…

Macbook2024电脑必备系统优化软件CleanMyMacX

随着时间的推移&#xff0c;你可能会发现你的MacBook运行速度变慢&#xff0c;甚至在执行一些基本任务时也会感觉到卡顿。这不仅影响了工作效率&#xff0c;也大大降低了使用体验。特别是当你运行大型应用程序&#xff0c;比如视频编辑软件或图形设计工具时&#xff0c;卡顿现象…

Python计算器程序代码

from tkinter import * import random class App: def __init__(self, master): self.master master self.initwidgets() #表达式的值 self.expr None def initwidgets(self): #定义一个输入组件 self.show Label(relief SUNKEN, font (Courier New, 24), width 25, bg …

[JAVASE] 类和对象(二)

目录 一. 封装 1.1 面向对象的三大法宝 1.2 封装的基本定义与实现 二. 包 2.1 包的定义 2.2 包的作用 2.3 包的使用 2.3.1 导入类 2.3.2 导入静态方法 三. static 关键字 (重要) 3.1 static 的使用 (代码例子) 3.1.1 3.1.2 3.1.3 3.1.4 四. 总结 一. 封装 1.1 面向对象…

反了!美国假冒邮政服务钓鱼网站访问量竟然超过正规官网

美国邮政是美国主要的包裹信件投递机构之一&#xff0c;长期以来该单位都是网络钓鱼和诈骗的针对目标。对美国公民来说&#xff0c;在假期通常都会收到声称来自美国邮政的诈骗。美国邮政甚至单独建设的网页提醒消费者警惕诈骗信息&#xff1a; 专用提醒网页 Akamai 的研究人员…

IP证书签发申请

IP证书签发申请 IP证书的全称是IP SSL证书&#xff0c;其主要的作用是为IP实现https访问&#xff0c;且IP SSL证书可以完美的解决企业对于IP地址实现https加密需求。 这种类型的证书特别适合于那些没有域名只有公网IP或者不方便使用域名的企业或个人。证书允许通过特定的IP地…

简单的表单初始密码验证的实现

目录 简单示例&#xff1a;表单初始密码验证 1.1准备工作(图1&#xff09; 1.2 index部分 1.3 css部分 1.3.1先把css部分链接到index.html中&#xff0c;注意链接的地址。 1.3.2添加样式 1.4 JS部分 1.4.1 先把js部分链接到index.html中&am…

LAE SHOW 2024 大湾区国际低空经济产业博览会

LAE SHOW 2024 大湾区国际低空经济产业博览会 2024 CHN GBA Intl Low-Altitude Economy Industrial Show ◎ 展会基本信息&#xff1a; 展览时间&#xff1a;2024年12月4日-6日 展览地点&#xff1a;深圳国际会展中心&#xff08;宝安新馆&#xff09; 展览面积&#xff1a…

2万字干货:如何从0到1搭建一套会员体系(2)

2.用户等级 还是一样&#xff0c;我们为什么要搭建用户等级&#xff1f; 一个国家有几亿人口的时候你怎么来管理&#xff1f;老祖宗秦始皇给出了我们答案&#xff1a;郡县制。发展到现在则演进成了省-市-区县-乡镇(街道)-村(社区)5层行政治理结构。 产品同理&#xff0c;当你…

人脸识别技术在访客管理中的应用

访客办理体系&#xff0c;能够使用于政府、戎行、企业、医院、写字楼等众多场所。在办理时&#xff0c;需求对来访人员身份进行精确认证&#xff0c;才能保证来访人员的进入对被访单位不被外来风险入侵。在核实身份时&#xff0c;比较好的方法就是选用人脸辨认技能&#xff0c;…

QT 小项目:登录注册账号和忘记密码(下一章实现远程登录)

一、环境搭建 参考上一章环境 二、项目工程目录 三、主要源程序如下&#xff1a; registeraccountwindow.cpp 窗口初始化&#xff1a; void registeraccountWindow::reginit() {//去掉&#xff1f;号this->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButt…

针对 % 号 | 引起的 不安全情况

把网站开放的课程都检索下来了 一、情况1 org.apache.tomcat.util.http.Parameters processParameters 信息: Character decoding failed. Parameter [Mac] with value [%%%] has been ignored. Note that the name and value quoted here may be corrupted due to the failed…