【数据结构】搜索二叉树

news2024/11/16 2:10:17

二叉搜索树

二叉树的博客

在之前的数据结构的文章中已经基本对二叉树有一定的了解,二叉搜索树也是一种数据结构,下面将对二叉搜索树进行讲解。

二叉搜索树的概念

        二叉搜索树又称为二叉排序树,它或者是一棵空树,或者是具有下面性质的二叉树:

  • 若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值。
  • 若它的右子树不为空,则右子树上的所有节点的值都大于根节点的值。
  • 它的左右子树也分别为二叉搜索树。

二叉搜索树的特点是搜索数据比较快,最多高度次就可以找到所值,其高度最大就是O(N)

二叉搜索树的实现过程

基本框架

  • 需要有一个struct的类(struct的类默认公开)来包含一个节点的所有特性,包括其可以指向左子树、右子树以及其包含的数据。
  • 然后使用class的类来对这棵二叉搜索树进行封装。
template<class K>
struct BSTreeNode
{
	BSTreeNode(const K& key)
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}

	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;
};

template<class K>
struct BSTree
{
	typedef BSTreeNode<K> Node;
public:

private:
	Node* _root;
};

初始化二叉树:

	//初始化节点
	BSTree()
		:_root(nullptr)
	{}

二叉搜索树的插入

插入过程:

  • 当树为空的时候,直接新增节点,赋值给root指针。
  • 树不为空,按二叉搜索树的性质查找插入位置,插入新节点。
//插入数据
bool insert(const K& key)
{
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}
	Node* cur = _root;
	Node* parent = nullptr;
	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 (cur->_key > parent->_key)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	return true;
}

搜索二叉树的打印(使用中序遍历)

        在这段代码中,使用_root作为参数传递给_InOrder函数,而不是直接在_InOrder函数中使用__root,主要是为了增加代码的灵活性和可复用性。

这样做的好处是,_InOrder函数可以处理不同的二叉树,而不仅仅局限于某个特定的二叉树对象。通过将二叉树的根节点作为参数传递给_InOrder函数,就可以对任意给定的二叉树进行中序遍历。

如果直接在_InOrder函数中使用_root,那么_InOrder函数就只能操作类内部固定的_root成员变量所代表的二叉树。而通过参数传递的方式,可以在需要的时候将不同的二叉树根节点传递给_InOrder函数,使其能够对各种不同的二叉树进行操作,提高了函数的通用性。

	//二叉树的升序打印
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

二查搜索树的查找

  1. 从根开始查找,如果比根小走左路,比根大走右路。
  2. 最多查找高度次,如果没找到则不存在。

二叉搜索树的删除(难点)

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

  1. 要删除的节点无孩子节点。
  2. 要删除的节点只有左孩子节点。
  3. 要删除的节点只有右孩子节点。
  4. 要删除的节点有左、右孩子节点。

总结下来,实际中真正要删除的情况只有三种:

  1.  删除该节点且使被删除节点的双亲结点指向被删除节点的左孩子节点——直接删除。
  2. 删除该节点且使被删除节点的双亲结点指向被删除节点的右孩子节点——直接删除。
  3. 在它的右子树中寻找中序下的第一个节点(数值最小)或者在它的左子树中寻找中序前的最后一个节点(数值最大),用它的值填补到被删除节点中,再来处理该节点的删除问题【替换法】。 

再进行缩减就是:

  1. 没有孩子或者只有一个孩子,进行托孤。
  2. 有俩个孩子进行替换。

	//搜索二叉树的删除
	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
				}
				else if(cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}
				}
				else
				{
					//替换法
					Node* LeftMax = _root->_left;
					Node* parent = _root;
					while (LeftMax->_right)
					{
						parent = LeftMax;
						LeftMax = LeftMax->_right;
					}
					swap(LeftMax->_key, cur->_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;
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

递归查找

	//查找
	bool FindR(const K& key)
	{
		return _FindR(_root, key);
	}
private:
	bool _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

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

递归插入

	//插入
	bool InsertR(const K& key)
	{
		return _InsertR(_root, key);
	}
private:
	bool _InsertR(Node*& root, const K& key)
	{
		if (root == nullptr)
		{
			root = new Node(key);
			return true;
		}

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

递归删除

	//删除
	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}
private:
	bool _EraseR(Node*& root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_key > key)
		{
			return _EraseR(root->_left, key);
		}
		else if(root->_key < key)
		{
			return _EraseR(root->_right, key);
		}
		else
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				Node* MaxLeft = root->_left;
				while (MaxLeft->_right)
				{
					MaxLeft = MaxLeft->_right;
				}
				swap(root->_key, MaxLeft->_key);

				return _EraseR(root->_left, key);
			}
			delete del;
			return true;
		}
	}

二叉树完整代码展示

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

template<class K>
struct BSTreeNode
{
	BSTreeNode(const K& key)
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}

	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;
};

template<class K>
struct BSTree
{
	typedef BSTreeNode<K> Node;
public:
	//初始化节点
	BSTree()
		:_root(nullptr)
	{}
	//插入数据
	bool insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		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 (cur->_key > parent->_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->_left;
			}
			else if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else
			{
				return true;
			}
		}
		return false;
	}

	//搜索二叉树的删除
	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
				}
				else if(cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}
				}
				else
				{
					//替换法
					Node* LeftMax = _root->_left;
					Node* parent = _root;
					while (LeftMax->_right)
					{
						parent = LeftMax;
						LeftMax = LeftMax->_right;
					}
					swap(LeftMax->_key, cur->_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;
	}
	//查找
	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);
	}
private:
	bool _EraseR(Node*& root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_key > key)
		{
			return _EraseR(root->_left, key);
		}
		else if(root->_key < key)
		{
			return _EraseR(root->_right, key);
		}
		else
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				Node* MaxLeft = root->_left;
				while (MaxLeft->_right)
				{
					MaxLeft = MaxLeft->_right;
				}
				swap(root->_key, MaxLeft->_key);

				return _EraseR(root->_left, key);
			}
			delete del;
			return true;
		}
	}

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

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

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

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

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

二叉树的应用

1.K模型:K模型即只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值。K模型可以快速判断在不在的场景,之前模拟实现的就是K模型。

  • 应用1:门禁系统。
  • 应用2:小区车辆出入系统(是否允许进入)。
  • 应用3:判断单词是否正确。

2.KV模型:每一个关键码key,都会对应一个value的值,即< key,value >。KV模型可以通过一个值快速找到另外一个值。

  • 应用1:手机号码查询快递。
  • 应用2:商城车辆出入系统(记录实际)。
  • 应用3:高铁实名制车票系统。
  • 应用4:英汉词典的中英文对应关系。

KV模型代码展示:

#include<iostream>

using namespace std;

namespace key_value
{
	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)
		{}

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

		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key, const V& value)
		{
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}

	private:
		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
			{
				Node* del = root;

				// 1、左为空
				// 2、右为空
				// 3、左右都不为空
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				else
				{
					Node* leftMax = root->_left;
					while (leftMax->_right)
					{
						leftMax = leftMax->_right;
					}

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

					return _EraseR(root->_left, key);
				}

				delete del;
				return true;
			}
		}

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

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

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

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

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

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

	void TestBSTree1()
	{
		//BSTree<string, Date> carTree;
		BSTree<string, string> dict;
		dict.InsertR("insert", "插入");
		dict.InsertR("sort", "排序");
		dict.InsertR("right", "右边");
		dict.InsertR("date", "日期");

		string str;
		while (cin >> str)
		{
			BSTreeNode<string, string>* ret = dict.FindR(str);
			if (ret)
			{
				cout << ret->_value << endl;
			}
			else
			{
				cout << "无此单词" << endl;
			}
		}
	}

	void TestBSTree2()
	{
		// 统计水果出现的次数
		string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
		BSTree<string, int> countTree;
		for (auto& str : arr)
		{
			auto ret = countTree.FindR(str);
			if (ret == nullptr)
			{
				countTree.InsertR(str, 1);
			}
			else
			{
				ret->_value++;
			}
		}

		countTree.InOrder();
	}
}

二叉树的性能分析

插入和删除都必须先查找,查找效率代表了二叉搜索树的各个操作的性能。

        对于n个节点的二叉搜索树,若是每一个元素查找的概率相等,则二叉搜索树平均查找长度是节点在二叉搜索树的深度的函数,即节点越深,则比较的次数越多。

        但是如果同一组数据的插入次序不同,可能得到不同结构的二叉搜索树。

最优的情况是:二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:logN

最差的情况是:二叉搜索树退化成单支树(或者类似单支),其平均的比较次数为N。

        使用有序数组进行二分查找的时候,其缺点是插入与删除效率不高;

        使用搜索二叉树进行二分查找的时候,其可以很好地利用其特性进行查找、插入、删除、排序等操作,但是搜索二叉树的唯一缺点就是下限无保障(一条光杆树)。

        所以在后续的C++文章中会介绍AVL树、红黑树、B树来解决这个问题。

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

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

相关文章

汇凯金业:区块链技术包括哪些技术

区块链&#xff0c;作为一项颠覆性的技术&#xff0c;其应用场景日益广泛。然而&#xff0c;很多人对于区块链技术的组成部分却知之甚少。本文将深入探讨区块链技术所包含的各种技术组件&#xff0c;揭示其背后的工作原理&#xff0c;帮助读者更全面地理解区块链。 区块链技术…

最优化大模型效果之 RAG(一):Naive RAG

Hi&#xff0c;我是 Hyde&#xff0c;今天的话题是 RAG&#xff08;Retrieval-Augmented Generation&#xff09;&#xff0c;一种用于优化大模型效果的方法&#xff0c;翻译成中文就是检索增强生成。 在之前的文章《最优化大模型效果的方向和思考》中&#xff0c;我们提到当前…

Google Test 学习笔记(简称GTest)

文章目录 一、介绍1.1 介绍1.2 教程 二、使用2.1 基本使用2.1.1 安装GTest &#xff08;下载和编译&#xff09;2.1.2 编写测试2.1.3 运行测试2.1.4 高级特性2.1.5 调试和分析 2.2 源码自带测试用例2.3 TEST 使用2.3.1 TestCase的介绍2.3.2 TEST宏demo1demo2 2.3.3 TEST_F宏2.3…

2-45 基于matlab的递归最小二乘法(RLS)对声音信号去噪

基于matlab的递归最小二乘法&#xff08;RLS&#xff09;对声音信号去噪,并对消噪前后的信号进行FFT分析&#xff0c;对比消噪前后的效果。可替换自己的声音信号进行分析。程序已调通&#xff0c;可直接运行。 2-45 递归最小二乘法&#xff08;RLS&#xff09; FFT分析 - 小红书…

聘请TPM管理咨询公司如何赢得员工认可?

聘请TPM管理咨询公司是一个重要的决策&#xff0c;它不仅能提升企业的运营效率和质量管理水平&#xff0c;而且需要得到员工的广泛认可才能确保改革的顺利实施。然而&#xff0c;赢得员工的认可并非易事&#xff0c;需要公司管理层和咨询公司共同努力&#xff0c;采取一系列措施…

崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB》&#xff08;作者&#xff1a;小草&#xff09;&#xff0c;满满…

C++ | Leetcode C++题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; class Solution { public:int hIndex(vector<int>& citations) {int n citations.size();int left 0, right n - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > n - mid) {right m…

C++ primer plus 第16章string 类和标准模板库, 函数符概念

C primer plus 第16章string 类和标准模板库, 函数符概念 C primer plus 第16章string 类和标准模板库, 函数符概念 文章目录 C primer plus 第16章string 类和标准模板库, 函数符概念16.5.1 函数符概念程序清单16.15 functor.cpp 16.5.1 函数符概念 正如 STL定义了容器和迭代…

【AOP实战】掌握Spring Boot AOP:重构代码,提升效率

文章目录 Spring Boot AOP - 面向切面编程AOP到底有什么不同AOP中的编程术语和常用注解定义切面环绕通知通知方法传参总结 Spring Boot AOP - 面向切面编程 AOP&#xff0c;即面向切面编程&#xff0c;其核心思想就是把业务分为核心业务和非核心业务两大部分。例如一个论坛系统…

ESP32和mDNS学习

目录 mDNS的作用mDNS涉及到的标准文件组播地址IPv4 多播地址IPv6 多播地址预先定义好的组播地址 mDNS调试工具例程mDNS如何开发和使用注册服务查询服务 mDNS的作用 mDNS 是一种组播 UDP 服务&#xff0c;用来提供本地网络服务和主机发现。 你要和设备通信&#xff0c;需要记住…

PHP基础语法-Part1

脚本格式 PHP脚本以<?php开头&#xff0c;以?>结尾&#xff1b; PHP语句以分号结尾&#xff08;;&#xff09; PHP是解释型语言&#xff1b; 输入和输出 获取用户的输入&#xff1a; $input readline("input:"); echo $input; echo "input:";…

EEtrade:区块链是什么

区块链&#xff0c;这个近年来频繁出现在我们视野中的术语&#xff0c;已经从一个技术小众圈的词汇&#xff0c;逐渐演变为全球关注的焦点。从比特币的诞生&#xff0c;到如今在金融、供应链、物联网等领域的广泛应用&#xff0c;区块链技术正在深刻地改变着我们的生活。那么&a…

将YOLOv8模型从PyTorch的.pt格式转换为TensorRT的.engine格式

TensorRT是由NVIDIA开发的一款高级软件开发套件(SDK)&#xff0c;专为高速深度学习推理而设计。它非常适合目标检测等实时应用。该工具包可针对NVIDIA GPU优化深度学习模型&#xff0c;从而实现更快、更高效的运行。TensorRT模型经过TensorRT优化&#xff0c;包括层融合(layer …

ARCGIS PRO DSK GraphicsLayer创建文本要素

一、判断GraphicsLayer层【地块注记】是否存在&#xff0c;如果不存在则新建、如果存在则删除所有要素 Dim GraphicsLayer pmap.GetLayersAsFlattenedList().OfType(Of ArcGIS.Desktop.Mapping.GraphicsLayer).FirstOrDefault() 获取当前map对象中的GetLayer图层 Await Queue…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十六章 设备驱动IO控制

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

云计算安全扩展要求解读

云计算简介&#xff1a; 一种全新网络服务方式&#xff0c;将传统的以桌面为核 心的任务处理转变为以网络为核心的任务处理&#xff0c; 利用互联网实现自己想要完成的一切处理任务&#xff0c; 使网络成为传递服务、计算力和信息的综合媒 介&#xff0c;真正实现按需计算、多…

揭秘Django与Neo4j:构建智能知识图谱的终极指南

揭秘Django与Neo4j:构建智能知识图谱的终极指南 前言 图是一种用于对象之间的成对关系进行建模的数学结构。 它由两个主要元素组成:节点和关系。 节点:节点可以看作是传统数据库中的记录。每个节点代表一个对象或实体,例如一个人或一个地方。节点按标签分类,这有助于根…

自研点直播转码核心

1. 背景 视频转码是将视频文件经过解封装、解码、滤镜处理、编码、封装从而转换为另一个视频文件的过程&#xff0c;B站每天都有大量的视频原片上传后经过转码系统转换为多个不同分辨率。转换后的视频在画质接近原片的前提下会拥有更低的码率&#xff0c;因此会提高网络传输时的…

3.3-LSTM的改进

文章目录 1改进点1.1多层化1.2 dropout1.2.1具体概念1.2.2应该插入到LSTM模型的哪里 1.3权重共享 2改进之后的LSTMLM的代码实现2.1初始化2.2前向计算2.3反向传播 3相应的学习代码的实现4总结 1改进点 1.1多层化 加深神经网络的层数往往能够学习更复杂的模式&#xff1b;因此这…

定制化爬虫管理:为企业量身打造的数据抓取方案

在数据驱动的时代&#xff0c;企业如何高效、安全地获取互联网上的宝贵信息&#xff1f;定制化爬虫管理服务应运而生&#xff0c;成为解锁专属数据宝藏的金钥匙。本文将深入探讨定制化爬虫管理如何为企业量身打造数据抓取方案&#xff0c;揭秘其在海量信息中精准捕获价值数据的…