C++_list简单源码剖析:list模拟实现

文章目录

    • 🚀1. ListNode模板
    • 🚀2. List_iterator模板(重要)
      • 🌱2.1 List_iterator的构造函数
      • 🌱2.2 List_iterator的关于ListNode的行为
    • 🚀3. Reverse_list_iterator模板(拓展)
    • 🚀4. List模板(核心)
      • 🌱4.1 List构造函数
      • 🌱4.2 List迭代器
      • 🌱4.3 List内容相关函数
      • 🌱4.4 List获取头尾元素
      • 🌱4.5 List内存修改

大家好!本文会用C++模拟一个基本的list类,帮助我们更好的理解list的内置函数的实现与规则。在这里插入图片描述

list是带头双向循环链表,在C语言实现一个链表时,我们通常会实现两个结构体,List 与 ListNode,也就是封装了List的本体与List的节点,在C++模拟实现list也是如此,我们需要实现List与ListNode两个模板。

🚀1. ListNode模板

回忆C语言的链表节点封装,大致其实现为:

struct listnode
{listnode* next;listnode* prev;int val;
};

由此,ListNode的内容是比较简单,我们先行封装ListNode,以模板的形式实现,其成员变量只有一个val与两个指针:指针一个指向前节点,一个指向后节点,val就是存储的数据

template<class T>
struct ListNode
{ListNode<T>* _prev;ListNode<T>* _next;T _val;//构造函数ListNode(const T& val = T()) :_prev(nullptr),_next(nullptr),_val(val){};
};

备注:

  1. 关于使用struct的原因:在C++中,如果一个类的成员变量全都是需要公开被访问的,我们通常使用struct不用class。我们封装ListNode,实际上是在List类中进行操作的,为了List能更方便的实现ListNode访问上下节点的操作,ListNode的成员必须的public的。
    : struct默认的所有成员是public,class默认的所有成员是private。
  2. 关于 const T& val = T()在 C++_vector简单源码剖析:vector模拟实现 中⚡️内置类型也有构造函数 这里有说明,其实就是为了当T是内置类型(int , double)的时候,能顺利初始化val

🚀2. List_iterator模板(重要)

Listiterator就是list的迭代器,提问🎤:在list类的封装中,能不能直接这么定义迭代器?->

template<class T>
class List
{
public:typedef ListNode<T> Node;typedef Node* iterator;
}

📜答案:不能,为什么🤔?在 C++_vector简单源码剖析:vector模拟实现 中,实现vector的迭代器似乎就是这样实现的,为什么到了list就不行了?
💡解释:在这里插入图片描述
那要如何实现?既然默认的++或者–并不是我们所需要的,那么我们就要自己定义这些行为,这里就需要封装一个Listiterator模板,用一个类来封装ListNode与它的一些行为

//List的迭代器模板
template<class T, class str, class ptr>
struct Listiterator
{typedef ListNode<T> Node;typedef Listiterator<T, str, ptr> Self;Node* _node;//迭代器的构造函数Listiterator(Node* pNode = nullptr);Listiterator(const Self& l);// ListNode的一些行为//前置++重载,当前节点到下一个节点Self operator++();//后置++重载,当前节点到下一个节点Self operator++(int);//前置--重载,当前节点到上一个节点Self operator--();//后置--重载,当前节点到上一个节点Self& operator--(int);//解引用重载str operator*();//->重载ptr operator->();//!=重载bool operator!=(const Self& l);//==重载bool operator==(const Self& l);
};

📈备注:

  1. 在List模板中会实例化两个版本的迭代器,一个iterator,一个const_iterator, str会传入 T& 与 const T&,ptr会传入T与const T * 。
  2. Listiterator的内容只有一个成员变量ListNode和它的一些行为,这样的过程叫做封装

🌱2.1 List_iterator的构造函数

typedef ListNode<T> Node;
typedef Listiterator<T, str, ptr> Self;Node* _node;
//迭代器的构造函数
Listiterator(Node* pNode = nullptr){_node = pNode;
}
Listiterator(const Self& l) {_node = l._node;
}

📈备注:构造一个迭代器,让其成员ListNode = 传入的ListNode

🌱2.2 List_iterator的关于ListNode的行为

	typedef ListNode<T> Node;typedef Listiterator<T, str, ptr> Self;Node* _node;
//前置++重载,当前节点到下一个节点
Self operator++()
{_node = _node->_next;return *this;
};
//后置++重载,当前节点到下一个节点
Self operator++(int) {Node* tmp = _node;_node = _node->_next;return tmp;
};
//前置--重载,当前节点到上一个节点
Self operator--()
{_node = _node->_prev;return *this;
};
//后置--重载,当前节点到上一个节点
Self& operator--(int) {Node* tmp = _node;_node = _node->_prev;return tmp;
};
//解引用重载
str operator*()
{return _node->_val;
};
//->重载
ptr operator->()
{return &*this;
};
//!=重载
bool operator!=(const Self& l) {return l._node !=_node;
};
//==重载
bool operator==(const Self& l) {return l._node == _node;
};

📈备注:++让封装的ListNode指向下一个节点,–指向上一个节点, * 解引用得到当前节点的值,->通过this指针使用成员,比较相不相等就是比较是不是同个节点。

🚀3. Reverse_list_iterator模板(拓展)

Reverse_list_iterator就是反向迭代器。

//反向迭代器
template<class T, class str, class ptr>
struct Reverse_list_iterator
{typedef ListNode<T> Node;typedef Reverse_list_iterator<T, str, ptr> Self;Node* _node;//构造函数Reverse_list_iterator(Node* tmp):_node(tmp) {};//前置++重载Self operator++(){_node = _node->_prev;return *this;};//后置++重载Self operator++(int) {Node* tmp = _node;_node = _node->_prev;return tmp;};//前置--重载,Self operator--(){_node = _node->_next;return *this;};//后置--重载Self& operator--(int) {Node* tmp = _node;_node = _node->_next;return tmp;};//解引用重载str operator*(){return (_node->_prev)->_val;};//->重载shptr operator->(){return &*this;};//!=重载bool operator!=(const Self& l) {return l._node != _node;};//==重载bool operator==(const Self& l) {return l._node == _node;};};

📉省流:与正常迭代器不同的地方就是 ++ , – ,和解引用 * , * 解引用获得的是上一个节点的值。

🚀4. List模板(核心)

List模板有很多的成员函数,我们先大致浏览一下它的成员:

	template<class T>class List{public:typedef ListNode<T> Node;//迭代器命名typedef Listiterator<T, T&, T*> iterator;typedef Listiterator<T, const T&, const T*> const_iterator;typedef Reverse_list_iterator<T, T&, T*> reverse_list_iterator;typedef Reverse_list_iterator<T, const  T&, const  T*> const_reverse_list_iterator;//1.  List的构造//默认构造List();//传值构造List(int n, const T& value = T());//迭代器构造template <class Iterator>List(Iterator first, Iterator last);//拷贝构造List(const List<T>& l);//赋值重载List<T>& operator=(List<T> l);//析构函数~List();//2. 迭代器iterator begin() ;iterator end();const_iterator begin() const;const_iterator end() const;reverse_list_iterator rbegin();reverse_list_iterator rend();const_reverse_list_iterator rbegin() const;const_reverse_list_iterator rend() const;//3. 内容相关size_t size()const;bool empty()const;//4. 获取头尾元素T& front();const T& front()const;T& back();const T& back()const;//5. 内存修改void push_back(const T& val);void pop_back();void push_front(const T& val);void pop_front();// 在pos位置前插入值为val的节点//不存在迭代器失效iterator insert(iterator pos, const T& val);// 删除pos位置的节点,返回该节点的下一个位置//存在迭代器失效iterator erase(iterator pos);void clear();void swap(List<T>& l);private: Node* _pHead;void createhead(){_pHead = new Node;_pHead->_prev = _pHead;_pHead->_next = _pHead;}};
}

🌱4.1 List构造函数

//创造head节点
void createhead()
{_pHead = new Node;_pHead->_prev = _pHead;_pHead->_next = _pHead;
}
//默认构造
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();auto start = first;while (start != last){push_back(*start);start++;};
};
//拷贝构造
List(const List<T>& l)
{createhead();for (auto e : l){push_back(e);}
};//赋值重载
List<T>& operator=(List<T> l)
{swap(_pHead, l._pHead);return *this;
}
//析构函数
~List()
{clear();delete _pHead;
}

📈备注:

  1. 默认构造支持创建空List
  2. 传值构造支持创建长度为n,值为value的List
  3. 迭代器构造支持通过传入迭代器进行初始化的List.
  4. 拷贝构造和赋值重载支持传入一个List进行初始化
  5. 析构函数要先clear,这个clear就是清除所有节点的函数,后面会实现

🌱4.2 List迭代器

一般迭代器:

typedef ListNode<T> Node;
typedef Listiterator<T, T&, T*> iterator;
typedef Listiterator<T, const T&, const T*> const_iterator;iterator begin() {return iterator(_pHead->_next);
};
iterator end()
{return iterator(_pHead);
};
const_iterator begin() const
{return const_iterator(_pHead->_next);
};
const_iterator end() const
{return const_iterator(_pHead);
};

📈备注:begin()返回头节点,end()返回尾节点的下一个节点(就是head节点)

反向迭代器:

typedef ListNode<T> Node;
typedef Reverse_list_iterator<T, T&, T*> reverse_list_iterator;
typedef Reverse_list_iterator<T, const  T&, const  T*> const_reverse_list_iterator;reverse_list_iterator rbegin(){return reverse_list_iterator(_pHead);
};
reverse_list_iterator rend()
{return reverse_list_iterator(_pHead->_next);
};
const_reverse_list_iterator rbegin() const
{return const_reverse_list_iterator(_pHead);
};
const_reverse_list_iterator rend() const
{return const_reverse_list_iterator(_pHead->_next);
};

📈备注:begin()返回头节点前一个节点(就是head节点),end()返回尾节点

🌱4.3 List内容相关函数

size_t size()const
{size_t size = 0;auto it = begin();while (it != end()){size++;it++;}return size;
}
bool empty()const
{return size() == 0;
}

📈备注:size与empty函数慎用,时间复杂度为O(n)。

🌱4.4 List获取头尾元素

T& front()
{return (_pHead->_next)->_val;
}
const T& front()const
{return (_pHead->_next)->_val;
}
T& back()
{return (_pHead->_prev)->_val;
}
const T& back()const
{return (_pHead->_prev)->_val;
}

📈备注:注意要多实现一个const版本的。

🌱4.5 List内存修改

//5. 内存修改
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* tmp = new Node(val);Node* cur = pos._node;Node* prev = cur->_prev;tmp->_next = cur;tmp->_prev = prev;cur->_prev = tmp;prev->_next = tmp;return  iterator(tmp);
};// 删除pos位置的节点,返回该节点的下一个位置
//存在迭代器失效
iterator erase(iterator pos)
{Node* Prew = pos._node->_prev;Node* Next = pos._node->_next;delete pos._node;Prew->_next = Next;Next->_prev = Prew;return Next;
};void clear() { iterator start = begin();while (start != end()){start = erase(start);}_pHead->_next = _pHead;_pHead->_prev = _pHead;
}
void swap(List<T>& l)
{Node tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;
}

📈备注:insert传入的迭代器不会失效,但是erase传入的迭代器会失效,erase返回删除节点的下一个节点的有效迭代器。其他是内存修改函数都是通过复用insert与erase实现的。

由此全部完成,附上总代码图:

#pragma once
namespace bit
{//ListNode节点template<class T>struct ListNode{ListNode<T>* _prev;ListNode<T>* _next;T _val;ListNode(const T& val = T()) :_prev(nullptr),_next(nullptr),_val(val){};};//List的迭代器模板template<class T, class str, class ptr>struct Listiterator{typedef ListNode<T> Node;typedef Listiterator<T, str, ptr> Self;Node* _node;//迭代器的构造函数Listiterator(Node* pNode = nullptr){_node = pNode;}Listiterator(const Self& l) {_node = l._node;}//前置++重载,当前节点到下一个节点Self operator++(){_node = _node->_next;return *this;};//后置++重载,当前节点到下一个节点Self operator++(int) {Node* tmp = _node;_node = _node->_next;return tmp;};//前置--重载,当前节点到上一个节点Self operator--(){_node = _node->_prev;return *this;};//后置--重载,当前节点到上一个节点Self& operator--(int) {Node* tmp = _node;_node = _node->_prev;return tmp;};//解引用重载str operator*(){return _node->_val;};//->重载ptr operator->(){return &*this;};//!=重载bool operator!=(const Self& l) {return l._node !=_node;};//==重载bool operator==(const Self& l) {return l._node == _node;};};//反向迭代器template<class T, class str, class ptr>struct Reverse_list_iterator{typedef ListNode<T> Node;typedef Reverse_list_iterator<T, str, ptr> Self;Node* _node;//构造函数Reverse_list_iterator(Node* tmp):_node(tmp) {};//前置++重载Self operator++(){_node = _node->_prev;return *this;};//后置++重载Self operator++(int) {Node* tmp = _node;_node = _node->_prev;return tmp;};//前置--重载,Self operator--(){_node = _node->_next;return *this;};//后置--重载Self& operator--(int) {Node* tmp = _node;_node = _node->_next;return tmp;};//解引用重载str operator*(){return (_node->_prev)->_val;};//->重载ptr operator->(){return &*this;};//!=重载bool operator!=(const Self& l) {return l._node != _node;};//==重载bool operator==(const Self& l) {return l._node == _node;};};//list模板template<class T>class List{public:typedef ListNode<T> Node;//迭代器命名typedef Listiterator<T, T&, T*> iterator;typedef Listiterator<T, const T&, const T*> const_iterator;typedef Reverse_list_iterator<T, T&, T*> reverse_list_iterator;typedef Reverse_list_iterator<T, const  T&, const  T*> const_reverse_list_iterator;//1.  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();auto start = first;while (start != last){push_back(*start);start++;};};//拷贝构造List(const List<T>& l){createhead();for (auto e : l){push_back(e);}};//赋值重载List<T>& operator=(List<T> l){swap(_pHead, l._pHead);return *this;}//析构函数~List(){clear();delete _pHead;}//2. 迭代器iterator begin() {return iterator(_pHead->_next);};iterator end(){return iterator(_pHead);};const_iterator begin() const{return const_iterator(_pHead->_next);};const_iterator end() const{return const_iterator(_pHead);};reverse_list_iterator rbegin(){return reverse_list_iterator(_pHead);};reverse_list_iterator rend(){return reverse_list_iterator(_pHead->_next);};const_reverse_list_iterator rbegin() const{return const_reverse_list_iterator(_pHead);};const_reverse_list_iterator rend() const{return const_reverse_list_iterator(_pHead->_next);};//3. 内容相关size_t size()const{size_t size = 0;auto it = begin();while (it != end()){size++;it++;}return size;}bool empty()const{return size() == 0;}//4. 获取头尾元素T& front(){return (_pHead->_next)->_val;}const T& front()const{return (_pHead->_next)->_val;}T& back(){return (_pHead->_prev)->_val;}const T& back()const{return (_pHead->_prev)->_val;}//5. 内存修改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* tmp = new Node(val);Node* cur = pos._node;Node* prev = cur->_prev;tmp->_next = cur;tmp->_prev = prev;cur->_prev = tmp;prev->_next = tmp;return  iterator(tmp);};// 删除pos位置的节点,返回该节点的下一个位置//存在迭代器失效iterator erase(iterator pos){Node* Prew = pos._node->_prev;Node* Next = pos._node->_next;delete pos._node;Prew->_next = Next;Next->_prev = Prew;return Next;};void clear() { iterator start = begin();while (start != end()){start = erase(start);}_pHead->_next = _pHead;_pHead->_prev = _pHead;}void swap(List<T>& l){Node tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;}private: Node* _pHead;void createhead(){_pHead = new Node;_pHead->_prev = _pHead;_pHead->_next = _pHead;}};
}

本文就到这里,感谢你看到这里❤️❤️!
我知道一些人看文章喜欢静静看,不评论🤔,但是他会点赞😍,这样的人,帅气低调有内涵😎,美丽大方很优雅😊,明人不说暗话,要你手上的一个点赞😘!

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

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

相关文章

【计算机毕设】基于SpringBoot的房产销售系统设计与实现 - 源码免费(私信领取)

免费领取源码 &#xff5c; 项目完整可运行 &#xff5c; v&#xff1a;chengn7890 诚招源码校园代理&#xff01; 1. 研究目的 随着房地产市场的发展和互联网技术的进步&#xff0c;传统的房产销售模式逐渐向线上转移。设计并实现一个基于Spring Boot的房产销售系统&#xff0…

SpringCloud学习笔记(一)

SpringCloud、SpringCloud Alibaba 前置知识&#xff1a; 核心新组件&#xff1a; 所用版本&#xff1a; 学习方法&#xff1a; 1.看理论&#xff1a;官网 2.看源码&#xff1a;github 一、微服务理论知识 二、关于SpringCloud各种组件的停更/升级/替换 主业务逻辑是&#x…

尝试用智谱机器人+知识库,制作pytorch测试用例生成器

尝试用智谱机器人知识库,制作pytorch测试用例生成器 1 保存pytorch算子文档到txt2 创建知识库3 创建聊天机器人4 测试效果5 分享 背景:是否能将API的接口文档和sample放到RAG知识库,让LLM编写API相关的程序呢 小结:当前的实验效果并不理想,可以生成代码,但几乎都存在BUG 1 保存…

星闪在智能汽车端的应用

随着智能汽车、智能终端、智能家居和智能制造等多产业的快速发展&#xff0c;多应用领域对无线短距通信技术在低延时、高可靠、低功耗等方面提出共性要求&#xff0c;现有主流无线短距通信技术的先天局限和技术潜力无法满足新应用的技术要求&#xff0c;针对解决行业技术痛点的…

StrApi基本使用

1.创建项目(这里只使用默认的sqllite) 点击链接进入官网查看先决条件,看看自己的node,python等是否符合版本要求 运行以下命令进行创建项目(网慢导致下载失败的话可以尝试使用手机热点给电脑使用,我就是这样解决的,也可以看我csdn的资源这里进行下载) yarn create strapi-ap…

5.25.1 用于组织病理学图像分类的深度注意力特征学习

提出了一种基于深度学习的组织病理学图像分类新方法。我们的方法建立在标准卷积神经网络 (CNN) 的基础上,并结合了两个独立的注意力模块,以实现更有效的特征学习。 具体而言,注意力模块沿不同维度推断注意力图,这有助于将 CNN 聚焦于关键图像区域,并突出显示判别性特征通…

基于Python的校园预约打印网站的实现

基于Python的校园预约打印网站的实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 注册 新用户首先要进行注册信息填写&#xff0c;填写完成以后进行登录即可使用此网站 打印社 分别有…

同元软控受邀出席2024工业软件创新发展学术会议

5月24日至26日&#xff0c;以“工业软件与新质生产力”为主题的2024工业软件创新发展学术会议在武汉顺利召开。会议由《软件导刊》编辑部主办&#xff0c;复杂关键软件环境全国重点实验室、武汉人工智能研究院、武汉轻工大学电气与电子工程学院承办&#xff0c;百度公司等单位协…

RandLA-Net 训练自定义数据集

https://arxiv.org/abs/1911.11236 搭建训练环境 git clone https://github.com/QingyongHu/RandLA-Net.git搭建 python 环境 , 这里我用的 3.9conda create -n randlanet python3.9 source activate randlanet pip install tensorflow2.15.0 -i https://pypi.tuna.tsinghua.e…

数据结构与算法 :数据结构绪论,时间和空间复杂度 推导大O阶

各位少年 大家好 我是博主那一脸阳光&#xff0c;今天开始给大家分享数据结构&#xff0c;由于我个人当初学的时候是自学&#xff0c;并没有看培训机构的视频 所以接下来我分享的数据结构的内容&#xff0c;源头来自一本书叫做大话数据结构。顺便一提为了方面大家理解&#xff…

unicloud 云对象

背景和优势 20年前&#xff0c;restful接口开发开始流行&#xff0c;服务器编写接口&#xff0c;客户端调用接口&#xff0c;传输json。 现在&#xff0c;替代restful的新模式来了。 云对象&#xff0c;服务器编写API&#xff0c;客户端调用API&#xff0c;不再开发传输json…

二叉树—堆(C语言实现)

一、树的概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是有n&#xff08;n > 0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一颗倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下。 ● 有一个特殊的结点…

结构设计模式 - 代理设计模式 - JAVA

代理设计模式 一. 介绍二. 代码示例2.1 定义 CommandExecutor 类2.2 定义 CommandExecutorProxy代理类2.3 模拟客户端2.4 测试结果 三. 结论 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子…

虚幻引擎5 Gameplay框架(四)

Gameplay重要类及重要功能使用方法&#xff08;三&#xff09; 虚幻的委托机制 虚幻委托之间的区别序列化就是是否可以在蓝图中执行 多播与单播的创建 制作功能&#xff1a;使用多播与单播将血条与血量进行实时更新首先新建一个单播与一个多播委托 实例化这两个委托的标签…

神经网络---卷积神经网络CNN

一、从前馈神经网络到CNN 前馈神经网络&#xff08;Feedforward Neural Networks&#xff09;是最基础的神经网络模型&#xff0c;也被称为多层感知机&#xff08;MLP&#xff09;。 它由多个神经元组成&#xff0c;每个神经元与前一层的所有神经元相连&#xff0c;形成一个“…

Ubuntu24.04 LTS安装中文输入法

前言 最近&#xff0c;windows玩没了&#xff0c;一怒之下决定换一个操作系统&#xff0c;当然就是最新的Ubuntu24.04 LTS.&#xff0c;其中魔法和咒语&#xff08;汉语&#xff09;是inux遇到的第一大难关&#xff0c;我权限不够教不了魔法&#xff0c;但我可以教你咒语(๑•…

大模型之路,从菜鸟到模型大师只需要一步

前言&#xff1a; 在这个数据爆炸的时代&#xff0c;大模型技术正以前所未有的速度发展。从自然语言处理到计算机视觉&#xff0c;从智能推荐到自动驾驶&#xff0c;大模型正逐渐渗透到我们生活的方方面面。那么&#xff0c;如何从菜鸟成长为模型大师呢&#xff1f;本文将为你…

1.8k Star!RAGApp:在任何企业中使用 Agentic RAG 的最简单方法!

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 1.8k Star&#xff01;RAGApp&#xff1a;在任何企业中使用 Agentic RAG 的最简单方法&#xff01; &#x1f31f;在任何企业中使用 Agent…

9.Halcon3D点云力矩求解-平面拟合用法

1.实现效果 我们在使用3d相机对产品进行扫描生成点云的时候,由于安装问题,所以我们不可能保证每次产品扫描出来都在坐标系中位置和姿态非常标准。 上述算法描述的就是在某一个维度或者某几个维度上将点云数据和坐标系对齐; 至于怎么对齐,如何实现就是今天的内容。 本人能…

如何评价GPT-4o?GPT-4o和ChatGPT4.0的区别是啥呢?

如何评价GPT-4o? GPT-4o代表了人工智能领域的一个重要里程碑&#xff0c;它不仅继承了GPT-4的强大智能&#xff0c;还在多模态交互方面取得了显著进步。以下是几个方面的分析&#xff1a; 技术特点 多模态交互能力&#xff1a;GPT-4o支持文本、音频和图像的任意组合输入与输出…