15. 【C++】详解搜索二叉树 | KV模型

news2024/11/13 9:37:35

目录

1.定义

初始化

插入

查找

删除

完整代码

2.运用

K 模型和 KV 模型详解

K 模型

KV 模型

代码解释


为了更好地理解 map 和 set 的特性,和后面讲解查找效率极高的平衡搜索二叉树,和红黑树去实现模拟,所以决定在这里对搜索二叉树进行一个讲解~

1.定义

二叉搜索树(Search Binary Tree)

每一颗子树都满足,左子树上所有节点的值都小于根节点的值,右子树都大于

所以就能得到性质:左子树的值 << 右子树的值

它也称二叉排序树或二叉查找树,最多找高度次 O(N)

二叉搜索树蜕化为单边树(或类似单边),其平均比较次数为:O(N)

搜索二叉树由于控制不了极端情况,与 O(logN) 失之交臂了,但后面讲到的平衡二叉搜索树可以做到。

初始化

template<class K>
struct BSTreeNode
{//全部都共有开放的,就直接定struct
	BSTreeNode<K>* _left;//左结构体指针
	BSTreeNode<K>* _right;
	K _key;

	BSTreeNode(const K& key)
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}
};
//定义一个树
template<class K>
class BATree{
   typedef BSTreeNode<K> Node;
private:
	Node* _root = nullptr;    // 这里我们构造函数都没必要写,它自己生成的就够用了
};

插入

思路:

  1. 检查是否有根结点 _root,如果没有我们就 new 一个结点出来作为根结点。
  2. 插入就需要找到插入位置,我们定义一个 cur 变量,从根节点开始,
    根据搜索二叉树 性质,将 cur 结点的 key 与插入的值 key 进行大小比较
  3. 仅仅 new 上一个新结点给 cur 是完成不了插入操作的!需要 cur 跟上一层(cur 的父亲)相链接才行!为了能找到上一层,所以我们还需要额外定义一个 parent 变量来记录 cur 的父结点

在我们更换 cur 结点时记录父结点的位置 parent=cur 即可。

parent 意义:确认位置,实现插入

     4.比较确定 cur 应该链接父亲的左边,还是链接父亲的右边,插入即可

//插入
	bool Insert(const K& key)
	{
        //没有根节点就new一个
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		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
			{
				return false;
			}//不断比较,搜索找到了之后
		}
       //new了一个新节点,和parent的key比较,确定插入的左右
		cur = new Node(key);
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}//将新节点插入到二叉树里面啦

		return true;
	}

再写一个中序遍历来测试一下插入的效果:

void InOrder(Node* root) {
    if (root == nullptr) {
        return;
    }
 
    InOrder(root->_left);            // 左
    cout << root->_key << " ";       // 值
    InOrder(root->_right);           // 右
}

//测试
void TestBSTree() {
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a) {
		t.Insert(e);
	}
	t.InOrder();  ❌ 没法传根
}

此时会出现一个问题,因为根是私有的,我们没办法把根传过去,我们可以采取 getroot,这里的话,我们将其设为内部函数即可

	void InOrder() {
		_InOrder(_root);
	}
 
private:
    // 改为内部函数
	void _InOrder(Node* root) {
		if (root == nullptr) {
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
 
	Node* _root = nullptr;
};

完整测试代码:

#include <iostream>
using namespace std;

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:
    BSTree() : _root(nullptr) {}

    bool Insert(const K& key) {
        if (_root == nullptr) {
            _root = new Node(key);
            return true;
        }

        Node* parent = nullptr;
        Node* cur = _root;
        //设置结构体形的cur节点,并进行初始化
        while (cur) {
            if (cur->_key < key) {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                parent = cur;
                cur = cur->_left;
            }
            else {
                return false;  // Key already exists
            }
        }
        cur = new Node(key);
        if (parent->_key < key) {
            parent->_right = cur;
        }
        else {
            parent->_left = cur;
        }

        return true;
    }

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

private:
    void _InOrder(Node* root) {
        if (root == nullptr) {
            return;
        }
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }

    Node* _root;
};

// 测试函数
void TestBSTree() {
    BSTree<int> t;
    int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
    for (auto e : a) {
        t.Insert(e);
    }
    t.InOrder();
}

int main() {
    TestBSTree();
    return 0;
}

打印:

查找

从根开始,如果要查找的值大于 cur 目前的值,则让 cur 往右走,反之往左走。

当查找得值与 cur 的值相等时则说明找到了,返回 true。

当 cur 触及到空(while 循环结束)则说明找不到,返回 false

//查找
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;
        //为空了还没找到就退出
	}

删除

搜索二叉树删除的实现是有难度的,删除的实现就需要一些技巧了,断然删除会毁树。

我们可以以下面这棵树为例

分别一次删除 7,14,3,8

7 和 14 属于直接删除的场景

3,8 属于需要替换法进行删除的场景

总结:

没有孩子,或者一个孩子都好删(直接删,托孤即可)

两个孩子以上就要采取替换法(左子树的最大节点,或者右子树的最小节点)

1.该结点无左孩子

  1. 若该结点为 root,直接让 root 等于它的右孩子结点。(一定要先判断)

画忘了,画成右为空了qwq,大家同理的理解一下

 // 左为空
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{//如果是根节点,parent就变为空了
						_root = cur->_right;
					}
					else
  1. 判断 cur 是在父节点的左还是右支,判断后将其指向parent->right/left = cur->right ,直接将右边连过去,实现重新连接的延续
  2. 最后删除 cur 结点
if (cur->_left == nullptr) {//该结点无左孩子
    /* 判断要删除的结点是否为根结点 */
    if (cur == _root) {
        _root = cur->_right;
    }
    else {
        if (cur == father->_right) {
            //判断他是上一个节点的左节点还是右节点
            father->_right = cur->_right;
        }
        else {
            father->_left = cur->_right;
        }
    }
    delete cur;
    cur = nullptr;
}

左右都不为空--替换法

else
{
	//查找到左边的最右节点
	//右边的最左节点
	//交换
	//删除

	// 找替代节点
	Node* parent = cur;
    //不能设置为nullptr,循环可能不进去了
	//之后要对父节点进行处理
	Node* leftMax = cur->_left;
    //设置最大节点
	while (leftMax->_right)
	{
		parent = leftMax;
		leftMax = leftMax->_right;
        //即最右节点
	}
    //交换key
	swap(cur->_key, leftMax->_key);

删除的判断

//将parent置空处理,断联
	if (parent->_left == leftMax)
	{
		parent->_left = leftMax->_left;
	}
	else
	{
		parent->_right = leftMax->_left;
	}
//删除cur的处理
	cur = leftMax;
}

				delete cur;
				return true;
			}
		}

		return false;

完整代码

#pragma once

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:
	BSTree()
		:_root(nullptr)
	{}

	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		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
			{
				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 (parent->_right == cur)
						{
							parent->_right = cur->_right;
						}
						else
						{
							parent->_left = cur->_right;
						}
					}
				}// 右为空
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_right == cur)
						{
							parent->_right = cur->_left;
						}
						else
						{
							parent->_left = cur->_left;
						}
					}					
				} // 左右都不为空 
				else
				{
					// 找替代节点
					Node* parent = cur;
					Node* leftMax = cur->_left;
					while (leftMax->_right)
					{
						parent = leftMax;
						leftMax = leftMax->_right;
					}

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

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

					cur = leftMax;
				}

				delete cur;
				return true;
			}
		}

		return false;
	}

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

	void _InOrder(Node* root)
	{
		if (root == NULL)
		{
			return;
		}
//递归实现中序遍历的打印
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
private:
	Node* _root;
};

测试:

void TestBSTree1()
{
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	BSTree<int> t;
	for (auto e : a)
	{
		t.Insert(e);
	}

	t.InOrder();

	t.Erase(4);
	t.InOrder();

	t.Erase(6);
	t.InOrder();

	t.Erase(7);
	t.InOrder();

	t.Erase(3);
	t.InOrder();

	for (auto e : a)
	{
		t.Erase(e);//插入
	}
	t.InOrder();
}

运行:

2.运用

K 模型和 KV 模型详解

K 模型

K 模型指的是只有 key 作为关键码的结构,在这种结构中只存储 key。K 模型常用于需要搜索具体值的场景,比如拼写检查、数字搜索等。

示例代码:K 模型的二叉搜索树

以下是一个实现 K 模型的二叉搜索树(BST)的完整代码示例:

#include <iostream>
using namespace std;

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:
    BSTree() : _root(nullptr) {}

    bool Insert(const K& key) {
        if (_root == nullptr) {
            _root = new Node(key);
            return true;
        }

        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 {
                return false;  // Key already exists
            }
        }

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

        return true;
    }

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

private:
    void _InOrder(Node* root) {
        if (root == nullptr) {
            return;
        }
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }

    Node* _root;
};

// 测试函数
void TestBSTree() {
    BSTree<int> t;
    int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
    for (auto e : a) {
        t.Insert(e);
    }
    t.InOrder();
}

int main() {
    TestBSTree();
    return 0;
}
KV 模型

KV 模型表示每一个关键码 (key) 都有与之对应的值 (value),即 <Key, Value> 的键值对。这种结构常用于字典、映射、统计等场景。

示例代码:KV 模型的二叉搜索树

以下是一个实现 KV 模型的二叉搜索树的完整代码示例:

#include <iostream>
#include <string>
using namespace std;

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:
    BSTree() : _root(nullptr) {}

    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) {
            if (cur->_key < key) {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                parent = cur;
                cur = cur->_left;
            }
            else {
                cur->_value = value;  // Update value if key already exists
                return true;
            }
        }

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

        return true;
    }

    bool Find(const K& key, V& value) {
        Node* cur = _root;
        while (cur) {
            if (cur->_key < key) {
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                cur = cur->_left;
            }
            else {
                value = cur->_value;
                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 << "> ";
        _InOrder(root->_right);
    }

    Node* _root;
};

// 测试函数
void TestKVTree() {
    BSTree<string, string> dict;
    dict.Insert("apple", "苹果");
    dict.Insert("banana", "香蕉");
    dict.Insert("cherry", "樱桃");

    string value;
    if (dict.Find("banana", value)) {
        cout << "banana: " << value << endl;
    }

    dict.InOrder();
}

int main() {
    TestKVTree();
    return 0;
}

代码解释

  1. 节点结构定义
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)
    {}
};
    • 这是一个模板结构,表示二叉搜索树的节点。每个节点包含一个键值对 (key, value) 以及指向左子节点和右子节点的指针。
  1. 二叉搜索树类定义
template<class K, class V>
class BSTree {
    typedef BSTreeNode<K, V> Node;

public:
    BSTree() : _root(nullptr) {}
    • 这是一个模板类,表示二叉搜索树。包含根节点指针 _root 以及插入、查找和中序遍历的方法。
  1. 插入方法
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) {
        if (cur->_key < key) {
            parent = cur;
            cur = cur->_right;
        }
        else if (cur->_key > key) {
            parent = cur;
            cur = cur->_left;
        }
        else {
            cur->_value = value;  // Update value if key already exists
            return true;
        }
    }

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

    return true;
}
    • 插入方法用于将新的键值对插入到树中。通过比较键值确定新节点应该插入的位置。如果键已存在,则更新其对应的值。
  1. 查找方法
bool Find(const K& key, V& value) {
    Node* cur = _root;
    while (cur) {
        if (cur->_key < key) {
            cur = cur->_right;
        }
        else if (cur->_key > key) {
            cur = cur->_left;
        }
        else {
            value = cur->_value;
            return true;
        }
    }
    return false;
}
    • 查找方法用于查找指定键的值。如果找到该键,则返回对应的值。
  1. 中序遍历方法
void InOrder() {
    _InOrder(_root);
    cout << endl;
}

private:
void _InOrder(Node* root) {
    if (root == nullptr) {
        return;
    }
    _InOrder(root->_left);
    cout << "<" << root->_key << ", " << root->_value << "> ";
    _InOrder(root->_right);
}
    • 中序遍历方法用于遍历树并输出键值对。递归地遍历左子树、访问根节点、然后遍历右子树。
  1. 测试函数
void TestKVTree() {
    BSTree<string, string> dict;
    dict.Insert("apple", "苹果");
    dict.Insert("banana", "香蕉");
    dict.Insert("cherry", "樱桃");

    string value;
    if (dict.Find("banana", value)) {
        cout << "banana: " << value << endl;
    }

    dict.InOrder();
}

int main() {
    TestKVTree();
    return

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

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

相关文章

基于asp.net小区物业信息管理系统设计与实现

博主介绍&#xff1a;专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…

【机器学习】使用Python的dlib库实现人脸识别技术

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、传统人脸识别技术1. 基于几何特征的方法2. 基于模板匹配的方法3. 基于统计学习的方法 三、深度学习在脸识别中的应用1. 卷积神经网络&#xff08;CNN&#xff09;2. FaceNet和ArcFace 四、使用Python和dlib库实…

辅助类BigDecima/BigInteger

** 大数据的运算** 编号1方法解释1add2subtract-3multiply*4divide/

p19 C语言操作符详解

算术操作符 1.除了%操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。 2.对于/操作符如果两个操作数都为整数&#xff0c;执行整数除法。而只要有浮点数值型的就是浮点除法。 3.%操作符的两个操作数必须为 整数。返回的是整除之后的余数。 #include<std…

通信流程:https【SSL/TLS】,git仓库【https/SSH】,蓝牙【面对面快传/AirDrop】

目录 HTTPS HTTP&#xff08;80端口&#xff09; SSL/TLS协议&#xff08;传输层&#xff0c;443端口&#xff09; 密文传输&#xff1a;SSL的后续版本TLS TLS1.2握手 1.摘要算法(散列函数 Hash Function)&#xff1a;验证信息的完整性&#xff0c;不可逆 第三方认证 引…

GO:Socket编程

目录 一、TCP/IP协议族和四层模型概述 1.1 互联网协议族&#xff08;TCP/IP&#xff09; 1.2 TCP/IP四层模型 1. 网络访问层&#xff08;Network Access Layer&#xff09; 2. 网络层&#xff08;Internet Layer&#xff09; 3. 传输层&#xff08;Transport Layer&#…

kotlin compose 实现应用内多语言切换(不重新打开App)

1. 示例图 2.具体实现 如何实现上述示例,且不需要重新打开App ①自定义 MainApplication 实现 Application ,定义两个变量: class MainApplication : Application() { object GlobalDpData { var language: String = "" var defaultLanguage: Strin…

你不是拖延,是没找对感觉!

在这个快节奏的时代&#xff0c;学习效率成为了我们每个人都渴望提升的关键能力。如何通过训练潜意识、深化知识印象、调整学习模式、找到适合自己的学习方法&#xff0c;以及利用倒计时硬逼法来提高执行力&#xff1f; 1. 训练潜意识&#xff1a;形成习惯 习惯的力量是巨大的…

使用python的pillow库生成图像验证码

一、pillow库 Pillow库&#xff1a;是一个功能强大的Python图像处理库&#xff0c;它提供了丰富的图像处理功能&#xff0c;使得用户能够方便地使用Python对图像进行各种操作。 二、图像验证码的分析 首先需要一个图像&#xff0c;图像上需要绘制验证码&#xff0c;还需要任意多…

博客最细 STM32CubeProgrammer 软件使用教程 二(学不会举报我)

前言&#xff1a;编写不易&#xff0c;仅供学习&#xff0c;参考&#xff0c;请勿转载 前言&#xff1a;本篇教程是 STM32CubeProgrammer 软件使用教程二&#xff0c;通过本篇你可以学习到&#xff0c;使用STM32CubeProgrammer读取 flash RAM&#xff0c;开启读写保护&#x…

科普文:TaobaoVM信息收集

网上关于TaobaoVM的信息很少&#xff0c;只有一个简介&#xff0c;就没有其他信息。毕竟这是别人企业自己的jvm&#xff0c;不可能公开。 Taobao VM 由AliJVM团队发布。阿里&#xff0c;国内使用Java最强大的公司&#xff0c;覆盖云计算、金融、物流、电商等众多领域&#xf…

Python和C++行人轨迹预推算和空间机器人多传感融合双图算法模型

&#x1f3af;要点 &#x1f3af;双图神经网络模型&#xff1a;最大后验推理和线性纠错码解码器 | &#x1f3af;重复结构和过约束问题超图推理模型 | &#x1f3af;无向图模型变量概率计算、和积消息传播图结构计算、隐马尔可夫模型图结构计算、矩阵图结构计算、图结构学习 |…

数据库MySQL学习第一天|了解数据库、数据类型、存储引擎、sql语言

文章目录 了解数据库什么是数据库数据库分类MySQL概念 数据类型整数类型小数类型日期类型文本,二进制类型 存储引擎种类引擎选择 sql主键和外键主键设计原则选取策略 外键索引 表与表的关联在语法上关联关系sql约束sql注入聚合函数常见查询关键字 了解数据库 什么是数据库 概…

网络安全协议系列

目录 一、安全协议的引入 1.TCP/IP协议族中普通协议的安全缺陷 1.信息泄露 2.信息篡改 3.身份伪装 4.行为否认 2.网络安全需求 二、网络安全协议的定义 三、构建网络安全协议所需的组件 1.加密与解密 2.消息摘要 3.消息验证码 4.数字签名 5.密钥管理 1.建立共享…

关于C#多个文本框输入的问题

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

堆排序基本思想以及代码实现

1、基本思想 堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(n*logn)&#xff0c;它也是不稳定排序。 堆是具有以下性质的完全二叉树&#xff1a;每个结点的值都大于或…

Vue3路由如何携带 # 路由模式选择

vue3中创建路由的时候&#xff0c;有两种可选模型 hash模式、HTML5模式、服务端渲染模式 createWebHashHistory&#xff08;hash模式&#xff09; const router createRouter({// hash模式&#xff0c;带 # 号history: createWebHashHistory(), //函数可携带参数&#xff0c;…

C++11 容器emplace方法刨析

如果是直接插入对象 push_back()和emplace_back()没有区别但如果直接传入构造函数所需参数&#xff0c;emplace_back()会直接在容器底层构造对象&#xff0c;省去了调用拷贝构造或者移动构造的过程 class Test { public:Test(int a){cout<<"Test(int)"<<…

使用Web控制端和轻量级客户端构建的开放Web应用防火墙(OpenWAF)

目录 1. 简介2. 项目结构3. Web控制端3.1. 功能概述3.2. 审计&#xff08;攻击&#xff09;日志查看3.3. 多个WAF的集中监控和操作3.4. 使用socket进行封装3.5. 日志的高效存储和检索&#xff08;Redis&#xff09; 4. 轻量级客户端4.1. 功能概述4.2. 对Web程序的防护4.3. 网络…

36.UART(通用异步收发传输器)-RS232(3)

&#xff08;1&#xff09;串口发送模块visio视图&#xff1a; &#xff08;2&#xff09;串口发送模块Verilog代码: /* 常见波特率&#xff1a; 4800、9600、14400、115200 在系统时钟为50MHz时&#xff0c;对应计数为&#xff1a; (1/4800) * 10^9 /20 -1 10416 …