【数据结构】—搜索二叉树(C++实现,超详细!)

news2024/9/24 5:27:37

                                                      🎬慕斯主页修仙—别有洞天

                                                       ♈️今日夜电波:消えてしまいそうです—真夜中

                                                                1:15━━━━━━️💟──────── 4:18
                                                                    🔄   ◀️   ⏸   ▶️    ☰  

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


目录

一、二叉搜索树概念

        什么是二叉搜索树? 

        二叉搜索树的基本操作

二、二叉搜索树的实现

         节点的定义

         二叉搜索树的定义

非递归操作

        插入操作

        查找操作 

        删除操作(重点及难点!!!)

递归法操作 

        中序遍历排升序(经典操作!) 

         插入操作(递归)

         查找操作(递归)

        删除操作(递归) 

 二叉搜索树的应用

        KV模型二叉搜索树

三、整体代码 


一、二叉搜索树概念

        什么是二叉搜索树? 

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,它满足以下几个条件:

  1. 左子树中所有节点的值小于当前节点的值。
  2. 右子树中所有节点的值大于当前节点的值。
  3. 左子树和右子树也都是二叉搜索树。

        二叉搜索树的中序遍历可以得到一个升序的序列,因此它常被用来实现有序集合或映射。在二叉搜索树中,查找、插入和删除操作的时间复杂度通常为O(logn),其中n为树中节点的数量,这得益于二叉搜索树的结构和查找方法。

         如下便是一颗二叉搜索树:

        一句话总结二叉搜索树:

                左子树节点总是比父节点小,右子树节点总是比父节点大的二叉树。

        二叉搜索树的基本操作

         利用二叉搜索树特性排升序。一听到二叉树,我们通常会想到的是什么?递归!请细细想想我们二叉搜索树的特点->左边的节点总是比父节点小,右边的节点总是比父节点大!那么我们对它使用中序遍历会发生什么呢?还是上面的那颗二叉树,对他进行中序遍历后:

        中序遍历结果:arr={1,3,4,6,7,8,10,13,14};

二、二叉搜索树的实现

         节点的定义

          说来惭愧作者在此前实现数据结构都是用C语言实现的 o (╥﹏╥)o. ,本文应该是作为作者第一篇用C++实现的数据结构,也算是一个新的起点吧!

        与C语言的区别主要还是在于在此使用struct(实际上是类)可以在定义时就进行初始化,利用的就是类的初始化列表的作用,这就省去了我们C语言时需要额外定义以及调用的初始化操作。只能说有了C++,C语言什么的不认识啦ʅ(´◔౪◔)ʃ

	//节点定义
	template<class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _key;

		BSTreeNode(const K& key)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
		{}
	};

         二叉搜索树的定义

         对于节点实例化并且重命名,并且给数据进行缺省赋值。

	//二叉搜索树
	template<class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
    //...诸多的操作
	private:
		Node* _root = nullptr;
	};

非递归操作

        插入操作

        插入的具体过程如下:

        a. 树为空,则直接新增节点,赋值给root指针

        b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

         思路:判断是否为空->是-》直接给根节点赋值->否->进行循环遍历对要插入的值进行“比大小”->大往右,小往左遍历,直到空为止->比较空位置父节点的大小,大插右,小插左

		//插入操作,按照左小右大的规则
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				parent = cur;
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

				cur = new Node(key);
				if (parent->_key < key)
				{
					parent->_right = cur;
				}
				else
				{
					parent->_left = cur;
				}

				return true;
		}

        查找操作 

        通过搜索二叉树的特性,通过比较大小即可完成查找。

		//查找操作
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}
			return false;
		}

        删除操作(重点及难点!!!)

         首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

        a. 要删除的结点无孩子结点

        b. 要删除的结点只有左孩子结点

        c. 要删除的结点只有右孩子结点

        d. 要删除的结点有左、右孩子结点

        看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

        情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除

        情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除

        情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除

        而在b、c、d这三种情况中,b和c又很相似,所以以大类来划分,我们实际可以分为两种。一种是要删除的节点只有一个左孩子或者右孩子,另一种是有两个孩子节点。

         现在详细介绍这两种情况:

        当只有一个孩子节点时: 当要删节点的左孩子为空时,我们只需要将右半边给他的父亲就行,当然我们也需要注意以下两点:1、如果要删节点是根节点,那么我们需要将它的右孩子的地址覆盖原节点。2、要删节点不是根节点,那么我们也需要判断要删节点是它父节点的左孩子还是右孩子;左孩子则父节点的左孩子节点指向要删孩子的右孩子,右孩子则父节点的右孩子节点指向要删孩子的右孩子。当要删右孩子时也是同理,只是需要注意此时要注意的第二点中要指向的是要删节点是右孩子。下面上半部分的图为此部分的图解~

          当有两个孩子节点时:我们则需要用到替换法。首先,我们需要根据以下规则中的一个规则:1、找到要删节点的左子树的最大节点。2、找到要删奇点的右子树的最小节点。接着,交换要删节点和找到的这个节点。最后,删除找到节点的位置,这个时候,我们就需要返回到上一部分我们只有一个孩子节点时要走的步骤,进行相应的操作为什么呢?因为我们都知道要找最小或者最大只有在最左或者最右。而此时我们一定满足只有一个孩子节点时的于要求。下面下半部分的图为此部分的图解,这里取右子树的最小~

        实现如下: 

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else//表示已经找到,进行删除操作
				{
					//左为空的情况
					if (cur->_left == nullptr)
					{
						if (cur == _root)//要删即为根节点
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)//因为左一定为空,为父节点的左则将右半边给父即可
							{
								parent->_left = cur->_right;
							}
							else//同理为父节点的右则将右半边给父
							{
								parent->_right = cur->_right;
							}
						}

						delete cur;
					}
					else if (cur->_right == nullptr)//右为空的情况
					{
						//同理左为空
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}

						delete cur;
					}
					else//左右都不为空
					{//可以选择找该节点左子树的最大节点(最右节点)或者右子树的最小节点(最左节点)
						//这里找右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subleft = cur->_right;
						while (subleft->_left)
						{
							parent = subleft;
							subleft = subleft->_left;
						}

						swap(cur->_key, subleft->_key);
						//由于找到的是最左,则默认左为空,所以只需将右链接给父节点
						if (subleft == parent->_left)
						{
							parent->_left = subleft->_right;
						}
						else
						{
							parent->_right = subleft->_right;
						}

						delete subleft;

					}

					return true;


				}
			}
			return false;
		}

        

递归法操作 

        中序遍历排升序(经典操作!) 

        上面详细介绍过了,不多阐述~

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

			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}

         插入操作(递归)

        实际上同非递归的原理是相同的,不多阐述。实在不行画递归展开图就理解了~

		bool _InsertR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}

			if (root->_key < key)
				return _InsertR(root->_right, key);
			else if (root->_key > key)
				return _InsertR(root->_left, key);
			else
				return false;
		}

         查找操作(递归)

		bool _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}

			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return true;
			}
		}

        删除操作(递归) 

        实际上操作同非递归是一致的 ,特别注意接口的对于root的引用,这对于后续删除很有作用。当要删除只有一个孩子节点的节点时,同非递归的思想是一样的。当要删节点有两个孩子节点时,在最后面采取的是装换成在子树中去删除,同非递归中的找到替换节点转到只有一个孩子的操作是一样的思想。

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;

			if (root->_key < key)
			{
				return _EraseR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _EraseR(root->_left, key);
			}
			else//找到了开始删除
			{
				//实际上的操作同非递归差不多,这里巧妙的对root运用了引用
				if (root->_left == nullptr)
				{
					Node* del = root;
					root = root->_right;
					delete del;
					
					return true;
				}
				else if (root->_right == nullptr)
				{
					Node* del = root;
					root = root->_left;
					delete del;

					return true;
				}
				else//找右子树的最大
				{
					Node* subleft = root->_right;
					while (subleft->_left)
					{
						subleft = subleft->_left;

					}
					swap(root->_key, subleft->_key);

					// 转换成在子树去递归删除
					return _EraseR(root->_right, key);
				}
			}
		}

 二叉搜索树的应用

        以上我们实现的二叉搜索树实际上也被称为K模型,而实际上还有一种模型叫做KV模型,以下为详细介绍:
         1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。比如:

        给一个单词word,判断该单词是否拼写正确,具体方式如下:

        以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树

        在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

        2. KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:比如

        英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;

        再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对

        KV模型二叉搜索树

        KV模型实际上同K模型差不多, 只是在K模型的基础上加了一个value值,对于其它的操作都是相似的,以下给出KV模型的整体代码:

namespace kv
{
	template<class K, class V>
	struct BSTreeNode
	{
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;
		K _key;
		V _value;

		BSTreeNode(const K& key, const V& value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		{}
	};

	template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;
	public:
		bool Insert(const K& key, const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key, value);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				parent = cur;

				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(key, value);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}

			return true;
		}

		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return cur;
				}
			}

			return nullptr;
		}

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					// 准备删除  20:15继续
					if (cur->_left == nullptr)
					{//左为空
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}
					}
					else if (cur->_right == nullptr)
					{//右为空
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
					}
					else
					{//左右都不为空

						// 右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subLeft = cur->_right;
						while (subLeft->_left)
						{
							parent = subLeft;
							subLeft = subLeft->_left;
						}

						swap(cur->_key, subLeft->_key);

						if (subLeft == parent->_left)
							parent->_left = subLeft->_right;
						else
							parent->_right = subLeft->_right;
					}

					return true;
				}
			}

			return false;
		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;

			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};

}

三、整体代码 

#pragma once
#include<iostream>
using namespace std;

namespace K
{
	//节点定义
	template<class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _key;

		BSTreeNode(const K& key)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
		{}
	};

	//二叉搜索树
	template<class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
		//插入操作,按照左小右大的规则
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				parent = cur;
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

				cur = new Node(key);
				if (parent->_key < key)
				{
					parent->_right = cur;
				}
				else
				{
					parent->_left = cur;
				}

				return true;
		}

		//查找操作
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}
			return false;
		}

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else//表示已经找到,进行删除操作
				{
					//左为空的情况
					if (cur->_left == nullptr)
					{
						if (cur == _root)//要删即为根节点
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)//因为左一定为空,为父节点的左子树则将右半边给父即可
							{
								parent->_left = cur->_right;
							}
							else//同理为父节点的右则将右半边给父
							{
								parent->_right = cur->_right;
							}
						}

						delete cur;
					}
					else if (cur->_right == nullptr)//右为空的情况
					{
						//同理左为空
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}

						delete cur;
					}
					else//左右都不为空
					{//可以选择找该节点左子树的最大节点(最右节点)或者右子树的最小节点(最左节点)
						//这里找右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subleft = cur->_right;
						while (subleft->_left)
						{
							parent = subleft;
							subleft = subleft->_left;
						}

						swap(cur->_key, subleft->_key);
						//由于找到的是最左,则默认左为空,所以只需将右链接给父节点
						if (subleft == parent->_left)
						{
							parent->_left = subleft->_right;
						}
						else
						{
							parent->_right = subleft->_right;
						}

						delete subleft;

					}

					return true;


				}
			}
			return false;
		}

		void InOrder()//中序遍历即排升序
		{
			_InOrder(_root);
			cout << endl;
		}

		bool FindR(const K& key)//递归找
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key)//递归插入
		{
			return _InsertR(_root, key);
		}

		bool EraseR(const K& key)//递归删
		{
			return _EraseR(_root, key);
		}

		BSTree() = default;// C++11

		~BSTree()
		{
			Destroy(_root);
		}

		BSTree(const BSTree<K>& t)
		{
			_root = Copy(t._root);
		}

		// t1 = t3
		BSTree<K>& operator=(BSTree<K> t)
		{
			swap(_root, t._root);
			return *this;
		}

	private:

		Node* Copy(Node* root)
		{
			if (root == nullptr)
				return nullptr;

			Node* newRoot = new Node(root->_key);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);

			return newRoot;
		}

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

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

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;

			if (root->_key < key)
			{
				return _EraseR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _EraseR(root->_left, key);
			}
			else//找到了开始删除
			{
				//实际上的操作同非递归差不多,这里巧妙的对root运用了引用
				if (root->_left == nullptr)
				{
					Node* del = root;
					root = root->_right;
					delete del;
					
					return true;
				}
				else if (root->_right == nullptr)
				{
					Node* del = root;
					root = root->_left;
					delete del;

					return true;
				}
				else//找右子树的最大
				{
					Node* subleft = root->_right;
					while (subleft->_left)
					{
						subleft = subleft->_left;

					}
					swap(root->_key, subleft->_key);

					// 转换成在子树去递归删除
					return _EraseR(root->_right, key);
				}
			}
		}

		bool _InsertR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}

			if (root->_key < key)
				return _InsertR(root->_right, key);
			else if (root->_key > key)
				return _InsertR(root->_left, key);
			else
				return false;
		}

		bool _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}

			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return true;
			}
		}

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

			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}

		Node* _root = nullptr;
	};
}



namespace kv
{
	template<class K, class V>
	struct BSTreeNode
	{
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;
		K _key;
		V _value;

		BSTreeNode(const K& key, const V& value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		{}
	};

	template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;
	public:
		bool Insert(const K& key, const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key, value);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				parent = cur;

				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(key, value);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}

			return true;
		}

		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return cur;
				}
			}

			return nullptr;
		}

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					// 准备删除  20:15继续
					if (cur->_left == nullptr)
					{//左为空
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}
					}
					else if (cur->_right == nullptr)
					{//右为空
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
					}
					else
					{//左右都不为空

						// 右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subLeft = cur->_right;
						while (subLeft->_left)
						{
							parent = subLeft;
							subLeft = subLeft->_left;
						}

						swap(cur->_key, subLeft->_key);

						if (subLeft == parent->_left)
							parent->_left = subLeft->_right;
						else
							parent->_right = subLeft->_right;
					}

					return true;
				}
			}

			return false;
		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;

			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};

}

                        感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                         给个三连再走嘛~  

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

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

相关文章

《微信小程序从入门到精通》---笔记1

小程序&#xff0c;我又来学习啦&#xff01;请多关照~ 项目驱动 小程序开发建议使用flex布局在小程序中&#xff0c;页面渲染和业务逻辑是分开的&#xff0c;分别运行在不同的线程中。Mini Program于2017年1月7号正式上线小程序的有点&#xff1a;跨平台、开发门槛低、开发周…

基于战争策略算法优化概率神经网络PNN的分类预测 - 附代码

基于战争策略算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于战争策略算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于战争策略优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

SSL握手失败的解决方案

一、SSL握手失败的原因&#xff1a; 1&#xff0c;证书过期&#xff1a;SSL证书有一个有效期限&#xff0c;如果证书过期&#xff0c;就会导致SSL握手失败。 2&#xff0c;证书不被信任&#xff1a;如果网站的SSL证书不被浏览器或操作系统信任&#xff0c;也会导致SSL握手失败…

(Matalb时序预测)GA-BP遗传算法优化BP神经网络的多维时序回归预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码 四、本文代码数据说明手册分享&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matalb平台编译&am…

C#,《小白学程序》第四课:数学计算,总和与平均值

程序是 数据 计算 显示。 1 文本格式 /// <summary> /// 《小白学程序》第四课&#xff1a;数学计算 /// 这节课超级简单&#xff0c;就是计算成绩的平均值&#xff08;平均分&#xff09; /// 这个是老师们经常做的一件事。 /// </summary> /// <param name&…

C#,《小白学程序》第六课:队列(Queue)其二,队列的应用,编写《实时叫号系统》

医院里面常见的《叫号系统》怎么实现的&#xff1f; 1 文本格式 /// <summary> /// 下面定义一个新的队列&#xff0c;用于演示《实时叫号系统》 /// </summary> Queue<Classmate> q2 new Queue<Classmate>(); /// <summary> /// 《小白学程序…

超赞 | 7组优秀的金融APP界面设计案例分享!

随着各大银行陆续推出手机银行APP&#xff0c;金融APP在众多领域也开始崭露头角。然而&#xff0c;从用户体验的角度来看&#xff0c;金融APP设计与其他类型的APP设计有其独特之处。由于金融APP与人们的钱包息息相关&#xff0c;因此&#xff0c;其安全性、界面体验和操作反馈等…

DataFunSummit:2023年现代数据栈技术峰会-核心PPT资料下载

一、峰会简介 现代数据栈&#xff08;Modern Data Stack&#xff09;是一种集合了多种技术和工具的软件基础设施&#xff0c;旨在更好地管理和处理数据&#xff0c;并为企业提供数据驱动的洞察和决策。包含以下几个组件&#xff1a;数据采集、数据处理、数据存储、数据查询和分…

OpenCV快速入门:特征点检测与匹配

文章目录 前言一、角点检测1.1 角点特征1.1.1 角点特征概念1.1.2 角点的特点1.1.3 关键点绘制代码实现1.1.4 函数解析 1.2 Harris角点检测1.2.1 Harris角点检测原理1.2.2 Harris角点检测公式1.2.3 代码实现1.2.4 函数解析 1.3 Shi-Tomasi角点检测1.3.1 Shi-Tomasi角点检测原理1…

Qt项目打包发布超详细教程

https://blog.csdn.net/qq_45491628/article/details/129091320

Hibernate的三种状态

1.瞬时状态(Transient) 通过new创建对象后&#xff0c;对象并没有立刻持久化&#xff0c;他并未对数据库中的数据有任何的关联&#xff0c;此时java对象的状态为瞬时状态&#xff0c;Session对于瞬时状态的java对象是一无所知的&#xff0c;当对象不再被其他对象引用时&#xf…

AIGC 3D即将爆发,混合显示成为产业数字化的生产力平台

2023年&#xff0c;大语言模型与生成式AI浪潮席卷全球&#xff0c;以文字和2D图像生成为代表的AIGC正在全面刷新产业数字化。而容易为市场所忽略的是&#xff0c;3D图像生成正在成为下一个AIGC风口&#xff0c;AIGC 3D宇宙即将爆发。所谓AIGC 3D宇宙&#xff0c;即由文本生成3D…

【数据结构】二叉排序树(c风格、结合c++引用)

目录 1 基本概念 结构体定义 各种接口 2 二叉排序树的构建和中序遍历 递归版单次插入 非递归版单次插入 3 二叉排序树的查找 非递归版本 递归版本 4 二叉排序树的删除&#xff08;难点&#xff09; 1 基本概念 普通二叉排序树是一种简单的数据结构&#xff0c;节点的值…

【TL431+场效应管组成过压保护电路】2022-3-22

缘由这个稳压三极管是构成的电路是起到保护的作用吗&#xff1f;-硬件开发-CSDN问答

微服务实战系列之Nginx

前言 Nginx&#xff1f;写了那么多文章&#xff0c;为什么今天才轮到它的表演&#xff1f;那是因为它实在太重要了&#xff0c;值得大书特书&#xff0c;特别对待。 当我们遇到单点瓶颈&#xff0c;第一个idea是&#xff1f;Nginx&#xff1b; 当我们需要反向代理&#xff0c;…

弹窗msvcp140_1.dll丢失的解决方法,超简单的方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是缺少某个文件的错误。最近&#xff0c;我在使用某些软件时&#xff0c;遇到了一个名为“msvcp140_1.dll”的错误提示。这个错误通常出现在运行某些程序时&#xff0c;由于缺少了msvcp140…

burp抓取雷电模拟器的数据包

文章目录 一、从burp中导出证书二、雷电模拟器的相关设置三、将burp的证书添加到模拟器的系统证书下四、安装ProxyDroid 所需软件 雷电模拟器版本&#xff1a;4.0.83Burp Suite Community Edition v2023.10.3.6ProxyDroid 起因&#xff1a;常规方法&#xff08;wifi处添加代理…

生态对对碰|华为OceanStor闪存存储与OceanBase完成兼容性互认证!

近日&#xff0c;北京奥星贝斯科技有限公司 OceanBase 数据库与华为技术有限公司 OceanStor Dorado 全闪存存储系统、OceanStor 混合闪存存储系统完成兼容性互认证。 OceanBase 数据库挂载 OceanStor 闪存存储做为数据盘和日志盘&#xff0c;在 OceanStor 闪存存储系统卓越性能…

“三个绝技“让项目经理轻松做好进度管理

大家好&#xff0c;我是老原。 我离开腾讯之后&#xff0c;曾经加入一家互联网创业公司。 要知道&#xff0c;当你在一个大公司的平台上做事做习惯之后&#xff0c;觉得一些流程都应该是严谨的、完备的、按计划进行的。 但是当时&#xff0c;经常出现一个致命问题——进度拖…

html幸运大转盘抽奖(附源码)

文章目录 1.设计来源1.1 幸运大转盘 风格11.2 幸运大转盘 风格21.3 幸运大转盘 风格31.4 幸运大转盘 奖品效果1.5 幸运大转盘 活动未开始1.6 幸运大转盘 活动已结束1.7 幸运大转盘 图片源素材 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&a…