当前位置: 首页 > news >正文

C++第十二弹 -- STL之list模拟实现

文章索引

  • 前言
  • 模拟实现list
    • 1. ListNode节点类
    • 2. list的迭代器封装
    • 3. 反向迭代器
    • 4. list类的模拟实现
    • 测试代码
  • list的反向迭代器
  • 总结

前言

通过模拟实现可以让我们更加深刻的理解C++底层STL的实现逻辑, 本篇就对list的底层进行模拟实现.

博客主页: 酷酷学!!! 点击关注 共同进步!!!


正文开始

模拟实现list

要模拟实现list, 必须要熟悉list的底层结构以及其接口的含义, 通过上一篇的学习, 这些内容基本掌握之后, 现在我们来模拟实现list.

1. ListNode节点类

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>namespace my
{//list的节点类template<class T>struct ListNode{ListNode(const T& val = T()): _prev(nullptr), _next(nullptr), _val(val){}ListNode<T>* _prev;ListNode<T>* _next;T _val;};

2. list的迭代器封装

list的迭代器
迭代器有两种实现方式, 具体应根据容器底层数据结构的实现:
1.原生态指针, 比如:vector
2.将原生态指针进行封装, 因迭代器使用形式与指针完全相同,
因此在自定义的类中必须实现以下方法:1.指针可以解引用,迭代器的类中必须重载operator*()2.指针可以通过->访问其所指空间成员,迭代器类中必须重载operator->()3.指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前或者向后移动,所以需要重载,如果是forward_list就不需要重载--4.迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
	template<class T,class Ref,class Ptr>class ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;//Ref 和 Ptr类型需要重新定义下,实现反向迭代器时需要用到public:typedef Ref Ref;typedef Ptr Ptr;//构造ListIterator(Node* node = nullptr): _node(node){}//具有指针类似行为Ref operator*(){return _node->_val;}Ptr operator->(){return &(operator*());}//迭代器支持移动Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self temp(*this);_node = _node->_next;return temp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self temp(*this);_node = _node->_prev;return temp;}//迭代器支持比较bool operator!=(const Self& l) const{return _node != l._node;}bool operator==(const Self & l) const{return _node == l._node;}Node* _node;};

3. 反向迭代器

	//反向迭代器,迭代器复用template<class Iterator>class ReverseListIterator{//注意:此处typename的作用是明确的告诉编译器,Ref是Iterator类中的一个类型,//而不是静态成员变量,否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员//变量,因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;//构造ReverseListIterator(Iterator it): _it(it){}//具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}//迭代器支持移动Self& operator++(){--_it;return *this;}Self& operator++(int){Self temp(*this);--_it;return *this;}Self& operator--(){++_it;return *this;}Self& operator--(int){Self temp(*this);++_it;return temp;}//迭代器支持比较bool operator!=(const Self& l) const{return _it != l._it;}bool operator==(const Self& l) const{return _it == l._it;}Iterator _it;};

4. list类的模拟实现

	template<class T>class list{typedef ListNode<T> Node;public://正向迭代器typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, T*> const_iterator;//反向迭代器typedef ReverseListIterator<iterator> reverse_iterator;typedef ReverseListIterator<const_iterator> const_reverse_iterator;//List的构造list(){CreateHead();}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i){push_back(value);}}template<class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}}list(const list<T>& l){CreateHead();//用l中的元素构造临时的temp,然后与当前对象交换list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(list<T> l){this->swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}//list的迭代器iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin() const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}//List的容器相关size_t size() const{Node* cur = _head->_next;size_t count = 0;while (cur != _head){++count;cur = cur->_next;}return count;}bool empty() const{return _head->_next = _head;}void resize(size_t newsize, const T* data = T()){size_t oldsize = size();if (newsize <= oldsize){//将有效元素减少到newsizewhile (newsize < oldsize){pop_back();--oldsize;}}else{while (oldsize < newsize){push_back(data);++oldsize;}}}//list的元素访问操作//注意:List不支持operator[]T& front(){return _head->_next->_val;}const T& front() const{return _head->_next->_val;}T& back(){return _head->_prev->_val;}const T& back() const {return _head->_prev->_val;}//list的插入和删除void push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}//在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* pNewNode = new Node(val);Node* pCur = pos._node;//先将新节点插入pNewNode->_prev = pCur->_prev;pNewNode->_next = pCur;pNewNode->_prev->_next = pNewNode;pCur->_prev = pNewNode;return iterator(pNewNode);}//删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){//找到待删除的节点Node* pDel = pos._node;Node* pRet = pDel->_next;//将该节点从链表中拆下来并删除pDel->_prev->_next = pDel->_next;pDel->_next->_prev = pDel->_prev;delete pDel;return iterator(pRet);}void clear(){Node* cur = _head->_next;//采用头删除删除while (cur != _head){Node* next = cur->_next;delete cur;cur = next;}_head->_next = _head->_prev = _head;}void swap(my::list<T>& l){std::swap(_head, l._head);}private:void CreateHead(){_head = new Node;_head->_prev = _head;_head->_next = _head;}Node* _head;};	
}

测试代码

对构造函数进行测试

//对模拟实现的list进行测试
//正向打印链表
template<class T>
void PrintList(const my::list<T>& l)
{auto it = l.begin();while (it != l.end()){cout << *it << " ";++it;}cout << endl;
}//测试list的构造
void Testmylist1()
{my::list<int> l1;my::list<int> l2(10, 5);PrintList(l2);int array[] = { 1,2,3,4,5,6,7,8,9,0 };my::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));PrintList(l3);my::list<int> l4(l3);PrintList(l4);l1 = l4;PrintList(l1);
}

在这里插入图片描述

对头/尾插入删除进行测试

//PushBack()/PopBack()/PushFront()/PopFront()
void Testmylist2()
{//测试pushBack和PopBackmy::list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);PrintList(l);l.pop_back();l.pop_back();PrintList(l);l.pop_back();cout << l.size() << endl;//测试pushFront与popFrontl.push_front(1);l.push_front(2);l.push_front(3);PrintList(l);l.pop_front();l.pop_front();PrintList(l);l.pop_front();cout << l.size() << endl;
}

在这里插入图片描述

测试指定位置插入删除

//测试insert和erase
void Testmylist3()
{int array[] = { 1,2,3,4,5 };my::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto pos = l.begin();l.insert(l.begin(), 0);PrintList(l);++pos;l.insert(pos, 2);PrintList(l);l.erase(l.begin());l.erase(pos);PrintList(l);//pos指向的节点已经被删除,pos迭代器失效cout << *pos << endl;auto it = l.begin();while (it != l.end()){it = l.erase(it);}cout << l.size() << endl;
}

在这里插入图片描述

测试反向迭代器

//测试反向迭代器
void Testmylist4()
{int array[] = { 1,2,3,4,5 };my::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;const my::list<int> cl(l);auto crit = l.rbegin();while (crit != l.rend()){cout << *crit <<" ";++crit;}cout << endl;
}

在这里插入图片描述

list的反向迭代器

我们知道, 反向迭代器的++就是正向迭代器的- -, 反向迭代器的- -就是正向迭代器的++, 因此反向迭代器的实现可以借助正向迭代器, 即: 返现迭代器内部可以包含一个正向迭代器, 对正向迭代器的接口进行包装即可.

	//反向迭代器,迭代器复用template<class Iterator>class ReverseListIterator{//注意:此处typename的作用是明确的告诉编译器,Ref是Iterator类中的一个类型,//而不是静态成员变量,否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员//变量,因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;//构造ReverseListIterator(Iterator it): _it(it){}//具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}//迭代器支持移动Self& operator++(){--_it;return *this;}Self& operator++(int){Self temp(*this);--_it;return *this;}Self& operator--(){++_it;return *this;}Self& operator--(int){Self temp(*this);++_it;return temp;}//迭代器支持比较bool operator!=(const Self& l) const{return _it != l._it;}bool operator==(const Self& l) const{return _it == l._it;}Iterator _it;};

总结

通过以上的实现,可以模拟出一个类似于list的数据结构,并且可以对其中的元素进行添加、删除、查找、等操作。这样就可以在不使用C++内置的list时,使用自己实现的List类来进行相同的操作。

感谢您的点赞与收藏!!!

相关文章:

C++第十二弹 -- STL之list模拟实现

文章索引 前言模拟实现list1. ListNode节点类2. list的迭代器封装3. 反向迭代器4. list类的模拟实现测试代码 list的反向迭代器总结 前言 通过模拟实现可以让我们更加深刻的理解C底层STL的实现逻辑, 本篇就对list的底层进行模拟实现. 博客主页: 酷酷学!!! 点击关注 共同进步!…...

Destiny of Gods首轮测试正式开启,参与玩家数量突破10万

天神风云&#xff0c;波澜再兴&#xff0c;GameFi链游聚合平台Destiny of Gods首款同名数字卡牌回合制游戏首轮测试定档8月20日20:00&#xff08;GMT8&#xff09;&#xff0c;现已正式开启&#xff01; 这是一个由人、游灵和神灵共存的世界&#xff0c;历经蛮荒时期的纷争与信…...

QT聊天室基于Tcp

server.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),server(new QTcpServer(this)) // 给服务器指针对象实例化空间{ui->setupUi(this); }Widget::~Widget() {delete ui; }…...

公开课观后感:密歇根大学python for everyone

从2024年1月17日到2024年8月20日&#xff0c;终于将密歇根大学的python for everyone的python公开课跟完。站在一月份规划的时刻来看&#xff0c;比我想象中花费的时间更多&#xff0c;我当时肯定没有想到要花上整整七个月的时间才能将这个公开课的内容看完&#xff0c;毕竟这个…...

goweb框架-gin

文章目录 Gin框架概览Gin框架的特点Gin框架的安装和基本使用安装基本使用 路由系统路由的基本概念Gin框架路由的特点 Radix Tree&#xff08;基数树&#xff09;基数树的定义和原理基数树在Gin框架中的应用节省空间的优化动态路由和通配符处理 路由树的构建注册路由的过程路由树…...

2024年接口测试高频面试题及答案

1. 什么是接口测试&#xff1f; •接口测试就是通过测试不同情况下的入参与之相应的出参信息来判断接口是否符合或满足相应的功能性、安全性要求 •测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系 2. 为什么要做接口…...

ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(8)

接前一篇文章:ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(7) 前边几回分析了笔者在MQTT测试时所遇到的问题: 最终定位到了是由于components\components\tcp_transport\transport_ssl.c的base_poll_write函数中调用的select函数超时返回…...

Linux: 忘记密码的解决方法,passwd

https://www.redhat.com/sysadmin/recover-root-passwd 这里的方法很简单&#xff0c;就是通过console进去&#xff0c;添加一个启动参数&#xff0c;加载sysroot&#xff0c;然后用passwd命令修改密码。这个是RHEL7适用。 https://access.redhat.com/solutions/1192 这个是提…...

36. 有效的数独【 力扣(LeetCode) 】

一、题目描述 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图…...

机器学习中的没有免费午餐定理

嘿&#xff0c;各位机器学习的爱好者们&#xff01;今天&#xff0c;让我们一起深入探讨机器学习中那个神秘而又重要的概念——没有免费午餐定理。 一、定理引入&#xff1a;探索算法森林的钥匙 在广阔无垠的机器学习领域中&#xff0c;免费午餐定理就如同一把神奇的钥匙&…...

高级java每日一道面试题-2024年8月21日-框架篇[Spring篇]-使用IOC容器应该注意哪些?

如果有遗漏,评论区告诉我进行补充 面试官: 使用IOC容器应该注意哪些? 我回答: 1. 理解IOC的基本概念 控制反转&#xff1a;在传统的编程模式中&#xff0c;程序会主动控制依赖关系的创建和管理。而在IoC容器中&#xff0c;这种控制权被反转给了容器本身。程序员只需要声明…...

LLM训练推理相关概念

1. 有监督微调&#xff08;Supervised Fine-Tuning&#xff09;与指令微调&#xff08;Instruction Fine-Tuning&#xff09;对模型参数的影响 **有监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;和指令微调&#xff08;Instruction Fine-Tuning, Instruct-Tun…...

IP in IP 协议

IP in IP 是一种多重IP协议&#xff0c;即&#xff1a;客户机可以发送一个IP协议内部在嵌套一个IP协议到某个特定的主机上&#xff0c;在由具体的主机作为路由进行转发的协议。 例如&#xff1a; IP in IP帧协议结构为&#xff0c;第一层为发送到IP in IP 路由主机的报文&…...

DAY2: HTTP请求报文和响应报文是怎样的,有哪些常见的字段?| HTTP有哪些请求方式?| GET请求和POST请求的区别

目录 HTTP请求报文和响应报文是怎样的&#xff0c;有哪些常见的字段&#xff1f; 请求报文 响应报文 HTTP有哪些请求方式&#xff1f; GET请求和POST请求的区别 HTTP请求报文和响应报文是怎样的&#xff0c;有哪些常见的字段&#xff1f; HTTP报文分为请求报文和响应报文…...

线性代数:每日一题1/特征值与相似对角化

设A, B 为二阶矩阵&#xff0c;且 AB BA , 则“A有两个不相等的特征值”是“B可对角化"的&#xff08;&#xff09; A. 充分必要条件 B. 充分不必要条件 C.必要不充分条件 D.既不充分也不必要条件 知识点&#xff1a; 特征向量与特征值的关系 相似矩阵的定义和性质 n阶…...

Android UI:PopupWindow:API

文章目录 类操作 对PopupWindow的操作 创建PopupWindow对象的操作添加并显示PopupWindow的操作移除PopupWindow的操作更新PopupWindow的操作显示内容的相关操作 布局的相关操作进入退出动画的相关操作 Transition设置进入动画的相关操作Transition设置退出动画的相关操作XML设置…...

什么是DevUI?

DevUI是面向企业中后台产品的开源前端解决方案&#xff0c;其设计价值观基于"高效、开放、可信、乐趣"四种自然与人文相结合的理念&#xff0c;旨在为设计师、前端开发者提供标准的设计体系&#xff0c;并满足各类落地场景&#xff0c;是一款企业级开箱即用的产品。 …...

DAY53

作业&#xff1a; 运行1个服务器和2个客户端 实现效果&#xff1a; 服务器和2个客户端互相聊天&#xff0c;服务器和客户端都需要使用select模型去实现 服务器要监视2个客户端是否连接&#xff0c;2个客户端是否发来消息以及服务器自己的标准输入流 客户端要监视服务器是否发来…...

python中len是什么

Python len() 方法返回字符串长度。 len()方法语法&#xff1a; len( str ) 返回值&#xff1a; 返回字符串长度。 以下实例展示了len()的使用方法&#xff1a; #!/usr/bin/python str "this is string example....wow!!!"; print "字符串长度: ", len…...

推荐一个开源的kafka可视化客户端GUI工具(Kafka King)

大佬的博客地址&#xff1a; https://blog.ysboke.cn/posts/tools/kafka-king Github地址&#xff1a; https://github.com/Bronya0/Kafka-King Kafka-King功能清单 查看集群节点列表&#xff08;完成&#xff09;支持PLAINTEXT、SASL PLAINTEXT用户名密码认证&#xff08;完…...

day 10 贪心算法

455. 分发饼干 饼干从大的开始利用&#xff0c;优先满足胃口大的&#xff1b; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(),g.end());sort(s.begin(),s.end());int res0;int indexs.size()-1;for…...

网络安全审计技术原理与应用

网络安全审计概述 概念 定义:对网络信息系统的安全相关活动信息进行获取、记录、存储、分析和利用的工作 作用:建立“事后”安全保障措施,保存网络安全事件及行为信息,为网络安全事件分析提供线索及证据,以便发现潜在网络安全威胁行为,开展网络安全风险分析及管理 常…...

计算机网络之TCP序号,确认序号和报文传输时间

开篇提示 本篇适合于了解基础知识&#xff0c;进行扩展提高的使用&#xff0c;附带考研习题以及解析。 TCP序号和确认序号的区别 TCP首部中有序号和确认序号&#xff0c;他们都是4个字节&#xff08;4B&#xff09;&#xff0c;且在数据传输中有很重要的意义&#xff0c;那么两…...

HTML优化方法

HTML编码规范 代码格式化与缩进 1.缩进规则 ​ 推荐使用空格缩进而不是Tab&#xff0c;因为不同环境下空格的效果更加一致。常见缩进量为2个或4个空格 2.标签对齐 ​ 在嵌套的HTML结构中&#xff0c;子标签应当缩进&#xff0c;以清晰地展示层级关系。 3.属性的排列 ​ …...

Codeforces Round 961 D. Cases 【SOS DP、思维】

D. Cases 题意 有一个长度为 n n n 且仅由前 c c c 个大写字母组成的字符串&#xff0c;问最少选取多少种字母为每个单词的结尾&#xff0c;使得每个单词长度不超过 k k k 思路 首先注意到最后一个字母一定要选择&#xff0c;接下来我们给出一个断言&#xff1a;如果一个…...

VirtualBox上的Oracle Linux虚拟机安装Docker全流程

1.安装docker依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 2.安装docker仓库 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 生成docker的yum源配置到在 /etc/yum.repos.d/docker-ce.repo 3.安装D…...

LNMP安装部署

目录 一、Nginx安装部署 1.安装包下载 2.下载相关依赖工具 3. 创建运行用户 4.编译安装 5.优化路径 6.将nginx添加至系统服务 7.文件赋权 二、MySQL部署安装 1.解压 2.安装相关工具 3.创建运行用户 4.编译安装 5.修改配置文件 6.更改mysql安装目录和配置文件的属…...

django之自定义序列化器用法

在Django中&#xff0c;自定义序列化器方法通常用于处理复杂的数据转换逻辑&#xff0c;特别是在使用Django REST framework&#xff08;DRF&#xff09;时。自定义序列化器方法可以帮助你在序列化和反序列化过程中执行特定的逻辑&#xff0c;比如格式化日期、计算字段值、或者…...

20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并挂载1TB的exFAT格式的TF卡

fdisk -l df -h df -t df -T mount 20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并挂载1TB的exFAT格式的TF卡 2024/8/21 18:06 【切记&#xff0c;对于Rockchip原厂的Buildroot&#xff0c;如果你没有针对性的适配DTS&#xff1a;修改其中的GPIO口供电&#xff0c…...

多模态学习Multimodal Learning:人工智能中的多模态原理与技术介绍初步了解

多模态学习&#xff08;Multimodal Learning&#xff09;是机器学习中的一个前沿领域&#xff0c;旨在综合处理和理解来自不同模态的数据。模态可以包括文本、图像、音频、视频等。随着数据多样性和复杂性增加&#xff0c;多模态学习在自然语言处理、计算机视觉、语音识别等领域…...

网站建设策划书风险控制/最好的网站优化公司

1.创建虚拟环境conda create -n pytorch python3.7注:-n是name的意思,后面指定虚拟环境的版本为3.72.进入环境conda activate pytorch注:conda可以省略3.安装pytorch打开官网:https://pytorch.org/选择相应的版本,如果你的电脑没有英伟达显卡,cuda选择none注意4.配置conda源找到…...

网站吸流量/站长工具网站测速

在当前的大环境里&#xff0c;实体店产品同质化非常严重。经过一条商业街&#xff0c;我们会明显发现&#xff0c;同行业的几家店铺不管是产品类型、装修风格还是产品价格都十分相似&#xff0c;给人的感觉就是把相同的产品放在不同的店里。 这个时候&#xff0c;优秀的营销策…...

云端网站建设/湘潭网络推广

在JS中&#xff0c;为我们提供了三个包装类&#xff0c;通过这三个包装类&#xff0c;可以将基本数据类型的数据转换为对象 String() 可以将基本数据类型的字符串转换为String对象 Number() 可以将基本数据类型的数字转换为Number对象 Bolean() 可以将基本数据类型的布尔值转换…...

自己怎么建h5商城网站/网站按天扣费优化推广

训练大纲(第121天)大家如果想快速有效的学习&#xff0c;思想核心是“以建立知识体系为核心”&#xff0c;具体方法是“守破离”。确保老师课堂上做的操作&#xff0c;反复练习直到熟练。第241次(httpPool&Hystrix)学习主题&#xff1a;httpPool&Hystrix学习目标&#…...

如何用自己电脑做网站测试/it培训机构哪个好一点

期刊投稿指南期刊/投稿/论文/职场关注强 烈 建 议 大 家 星 标 我 们茫 茫 文 海 ☆ 不 离 不 弃试完这些英文论文写作辅助神器&#xff0c;你会发现新大陆der~来源&#xff1a;学术大爆炸鸣谢作者有时候做研究并不痛苦痛苦的是——写&#xff01;论&#xff01;文&#xff01;…...

小企业做网站有用吗/最新足球赛事

一、搜索引擎基础介绍二、常见搜索引擎框架介绍与比较三、参考文章一、搜索引擎基础介绍1. 什么是搜索引擎搜索引擎&#xff0c;通常指的是收集了万维网上几千万到几十亿个网页并对网页中的每一个词(即关键词)进行索引&#xff0c;建立索引数据库的全文搜索引擎。当用户查找某个…...