list容器(详解)

list的介绍及使用(了解,后边细讲)

1.1 list的介绍(双向循环链表)

https://cplusplus.com/reference/list/list/?kw=list(list文档介绍)

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

1.2 list的使用(可以对照模拟实现看,重要的都有,后边模拟实现都会讲)

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口

1.2.1 list的构造

1.2.2 list iterator的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

【注意】

1. beginend为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

1.2.3 list capacity

1.2.4 list element access

1.2.5 list modifiers

list中还有一些操作,需要用到时大家可参阅list的文档说明。

 list的迭代器失效

        注意,insert不会失效,迭代器依旧指向原来位置,erase会失效(删除后返回下一个地址),跟vector的迭代器失效类比,都是因为没有接收删除后的迭代器。insert不会失效,因为插入后返回新的节点地址,本身就指向新节点,不会失效

错误代码:

void TestListIterator1()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
 l.erase(it); 
 ++it;
 }
}

改正后:

// 改正
void TestListIterator()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 l.erase(it++); // it = l.erase(it);两种写法都对
 }
}

 list的反向迭代器

  ReverseIterator.h

template<class Iterator,class Ref,class Ptr>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator, Ref, Ptr> Self;
	Iterator cur;
	ReverseIterator(Iterator it)
		:cur(it)
	{ }
	Self& operator++()
	{
		--cur;
		return *this;
	}
	Ref operator*()
	{
		Iterator tmp = cur;
		--tmp;
		return *tmp;
	}
	Ptr operator->()
	{
		return &(operator*());
	}
	bool operator!=(const Self& s)
	{
		return cur != s.cur;
	}
};

List.h

在list类内部多了一些改动,将反向迭代器的类重命名,并且新加两个成员函数

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1


#include<iostream>
#include<list>

using namespace std;

#include"List.h"

int main()
{
	jzy::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	jzy::list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	return 0;
}

可以看到反向迭代器起了作用,下面我来讲解反向迭代器的原理

反向迭代器可以理解成封装了正向迭代器,正向迭代器又封装了原生指针,反向迭代器++等价于正向迭代器--,反向迭代器解引用相当于正向迭代器--再解引用

因为反向迭代器的开始是正向迭代器结束位置,结束是正向的开始,所以反向迭代器要先--在解引用才是正确的值

反向迭代器的->也就是*拿到存放的值再取地址,和之前讲的是一个道理


		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		//typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

反向迭代器在list类那里要多加一些东西,重命名反向迭代器这个类,当是普通反向迭代器的时候实例化iterator,T&,T*,当是const反向迭代器的时候,实例化参数是const_iterator,const T&,const T*

总体来讲,可以把反向迭代器看成适配器,当实例化参数是普通迭代器,会按照普通迭代器的行为进行操作,当参数是const时,会调用const的操作

list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

list模拟实现讲解(超详细)

定义结点结构体,结构体成员是前仆后继指针和元素data,还要写一个构造函数用来初始化结点

迭代器封装为一个类,类定义的对象存放每个节点的地址,也就是_node,相当于迭代器指针被封装成了一个类里存放,typedef是将类型重命名,将长的类型重命名为短的,记住类名不是类型,类名<类型>才是类型

这里模版有三个参数,第一个T是实例化类型,第二个和第三个参数是为了*和->,const类型会匹配T,constT& ,constT* ,正常类型会匹配T,T&,T*

这里将原生指针封装了一层包装在一个类里边,类定义的对象会通过操作指针前后移动来操作结点,解引用拿到对应结点的值,或者->拿到对应的地址

迭代器构造函数,当返回值是iterator类型时,会构造一个临时对象来操作

迭代器++,--,和日期类的原理类似,++it是当前指针往后走一步,this是it的地址,然后返回++之后的值,后置++,参数多传一个int就行,构造一个局部对象,指针向后走一步,返回走之前的值,迭代器--和++同理,无非是向前走

operator*是(*it)相当于拿到对应的值,我们就把it当成指针,*it当成解引用地址即可,这里是把指针封装到类里边,和前边string和vector的指针有所区分;->箭头相当于拿到存放对象的地址,当在list内部存放结构体时会用到

最简单的两个运算符重载,当判断不等于的时候会用到

list类要把上边两个类typedef后的类型写上去,方便等会用

迭代器的重载,当我们用begin()或者end()的时候,会调用这四个重载,普通对象调用普通迭代器,返回普通可修改指向对象的迭代器(这个对象可以用类名(),也可以直接返回Node*的结点指针(单参数的构造函数支持隐式类型转换),这两个写法都会生成一个临时对象,然后进行使用),const类型调用const迭代器,返回const不可修改指向对象的迭代器(慢慢理解这部分,其实没有想象的那么难)

list类的私有成员是_head,充当一个指针用来声明第一个哨兵位头结点

默认构造是初始化一个哨兵位头结点,结点内部存放前仆后继指针和data值(是某个类型的默认构造),然后让_head指向第一个哨兵位结点,并且_next和_prev都指向自己,完成哨兵位结点的初始化

析构函数先用clear清理,删除除了哨兵位结点的剩余存放有效数据的结点(释放了空间),最后释放哨兵位结点空间,_head置空就OK

拷贝构造,先初始化一个哨兵位结点,然后将要构造的对象内容依次给给e,尾插到新对象后边

赋值拷贝,先拷贝构造一个lt,将lt和新对象交换,lt是局部对象,出作用域会调用析构函数,新对象引用返回,完成赋值拷贝

insert插入,参数是迭代器指针(生成临时对象+2次拷贝构造)和要插入的值,cur指向要插入位置,prev存放要插入位置前边的指针,new一个新节点是要插入的新结点

三个指针相对位置是这样的,一般都是在某个位置之前插入,所以是这样的关系,然后按顺序链接这三个位置,前一个位置的后继指针和后一个位置的前驱指针都指向中间位置,最后返回插入节点的迭代器(单参数构造函数支持隐式类型转换)

删除很简单,不能删除哨兵位结点,找到要删除节点,记录要删除结点的前一个和后一个,链接两边的节点,最后释放要删除节点的空间,返回下一个节点的迭代器(会隐式类型转换成iterator类型的对象)

尾插,可以自己重新写逻辑,也可以复用insert逻辑,将第一个参数换成最后一个位置的迭代器,相当于在哨兵位节点之前插入,效果是一样的

头插,尾插,尾删是一样的,复用insert,erase逻辑就行

这部分在c语言实现数据结构链表那里讲的很详细了,想看的可以看看

代码样例讲解

这是一个很基础的尾插和打印对象逻辑,可以用第一个迭代器打印,也可以用第二个,范围for打印(范围for底层就是迭代器,无脑替换成迭代器进行打印),可以看到*it和it++,都是我们封装成类的功劳,原理很简单前面讲过

测试插入删除逻辑,可以看到不管是头插,头删,尾插,尾删都很清晰明了,clear是直接删除有效结点只剩哨兵位,所以打印不出来

可以看到,拷贝构造和赋值拷贝都完成了使命,前边讲的很详细,这里不再赘述

这里主要测试普通迭代器和const迭代器,各自调用各自,const迭代器不可修改对象,普通迭代器可以修改对象

最后一个样例,插入AA类对象,*it是拿到存放的结构体变量,.操作符访问结构体成员,拿到1:1,打印第二行是编译器会将*it转换成it.operator*(),效果是一样的

->箭头访问操作符会特殊处理一个箭头可以当做两个->->,并且编译器会转换成it.operator->()->_a1去访问,会特殊处理,这里当成特殊处理就好

list的模拟实现(代码)

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

test.cpp


#include<iostream>
#include<list>
#include<vector>
#include<algorithm>
using namespace std;

#include"List.h"

namespace jzy
{
	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it += 10;

			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list2()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);


		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.push_back(5);
		lt.push_front(0);

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.pop_back();
		lt.pop_front();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.clear();

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		lt.push_back(10);
		lt.push_back(20);

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list3()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int> copy(lt);
		for (auto e : copy)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int> lt1;
		lt1.push_back(10);
		lt1.push_back(20);
		lt1.push_back(30);
		lt1.push_back(40);

		lt = lt1;
		for (auto e : copy)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it += 10;

			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list4()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		print_list(lt);


		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			*it += 10;

			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	struct AA
	{
		int _a1;
		int _a2;

		AA(int a1 = 1, int a2 = 1)
			:_a1(a1)
			, _a2(a2)
		{
		}
	};

	void test_list5()
	{
		list<AA> lt;
		AA aa1;
		lt.push_back(aa1);

		lt.push_back(AA());

		AA aa2(2, 2);
		lt.push_back(aa2);

		lt.push_back(AA(2, 2));

		list<AA>::iterator it = lt.begin();

		
			cout << (*it)._a1 << ":" << (*it)._a2 << endl;
			cout << it.operator*()._a1 << ":" << it.operator*()._a2 << endl;

			cout << it->_a1 << ":" << it->_a2 << endl;
			cout << it.operator->()->_a1 << ":" << it.operator->()->_a2 << endl;
	

	
		cout << endl;
	}


	
}


	int main()
	{
		jzy::test_list1();
		

		return 0;
	}

list.h

#pragma once
#include<assert.h>

namespace jzy
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;
		T _data;

		ListNode(const T& x = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{
		}
	};

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef ListNode<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;

		__list_iterator(Node* x)
			:_node(x)
		{
		}

		// ++it
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		// it++
		self operator++(int)
		{
			
			self tmp(*this);

			_node = _node->_next;

			return tmp;
		}

		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		self operator--(int)
		{
			self tmp(*this);

			_node = _node->_prev;

			return tmp;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		bool operator!=(const self& s)
		{
			return _node != s._node;
		}

		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//template<class T>
	//struct __list_const_iterator
	//{
	//	typedef ListNode<T> Node;
	//	typedef __list_const_iterator<T> self;
	//	Node* _node;

	//	__list_const_iterator(Node* x)
	//		:_node(x)
	//	{}

	//	// ++it
	//	self& operator++()
	//	{
	//		_node = _node->_next;
	//		return *this;
	//	}

	//	// it++
	//	self operator++(int)
	//	{
	//		self tmp(*this);

	//		_node = _node->_next;

	//		return tmp;
	//	}

	//	self& operator--()
	//	{
	//		_node = _node->_prev;
	//		return *this;
	//	}

	//	self operator--(int)
	//	{
	//		self tmp(*this);

	//		_node = _node->_prev;

	//		return tmp;
	//	}

	//	const T& operator*()
	//	{
	//		return _node->_data;
	//	}

	//	bool operator!=(const self& s)
	//	{
	//		return _node != s._node;
	//	}

	//	bool operator==(const self& s)
	//	{
	//		return _node == s._node;
	//	}
	//};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

	


		iterator begin()
		{
			//return iterator(_head->_next);
			return _head->_next;
		}

		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return _head;
		}

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		list()
		{
			empty_init();
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

		
		list(const list<T>& lt)
		{
			empty_init();

			for (const auto& e : lt)
			{
				push_back(e);
			}
		}

		// lt1 = lt2;
		// list<T>& operator=(const list<T>& lt)
		/*list<T>& operator=(list<T>& lt)
		{
			if (this != &lt)
			{
				clear();
				for (const auto& e : lt)
				{
					push_back(e);
				}
			}
			return *this;
		}*/

		void swap(list<T>& tmp)
		{
			std::swap(_head, tmp._head);
		}

		//list& operator=(list lt)
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		void push_back(const T& x)
		{
			/*Node* newnode = new Node(x);
			Node* tail = _head->_prev;

			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;*/

			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		// vector insert会导致迭代器失效
		// list会不会?不会
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

			// prev newnode cur
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			//return iterator(newnode);
			return newnode;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;

			delete cur;

			return next;
		}

	private:
		Node* _head;
	};
}

注意list的const迭代器可以实现为一个类,也可以实现为模版参数实例化后的结果,一般实现为后者,会少写很多冗余代码

以上就是我对list容器内容的讲解,很详细,欢迎大神交流!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RGB565转BITMAP[C#---2]

这是楼主在开发C#上位机的时候遇到的另一个问题&#xff0c;怎么把RGB565转为BITMAP&#xff0c;在CSDN上搜索&#xff0c;要么是安卓平台的&#xff0c;要么是2011年的古早代码&#xff08;还没排版&#xff09;&#xff0c;还是靠自己和DEEPSEEK的智慧解决了(●’◡’●) 当然…

pytorch实现门控循环单元 (GRU)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 特性GRULSTM计算效率更快&#xff0c;参数更少相对较慢&#xff0c;参数更多结构复杂度只有两个门&#xff08;更新门和重置门&#xff09;三个门&#xff08;输入门、遗忘门、输出门&#xff09;处理长时依赖一般适…

【赵渝强老师】Spark RDD的依赖关系和任务阶段

Spark RDD彼此之间会存在一定的依赖关系。依赖关系有两种不同的类型&#xff1a;窄依赖和宽依赖。 窄依赖&#xff1a;如果父RDD的每一个分区最多只被一个子RDD的分区使用&#xff0c;这样的依赖关系就是窄依赖&#xff1b;宽依赖&#xff1a;如果父RDD的每一个分区被多个子RD…

为何在Kubernetes容器中以root身份运行存在风险?

作者:马辛瓦西奥内克(Marcin Wasiucionek) 引言 在Kubernetes安全领域,一个常见的建议是让容器以非root用户身份运行。但是,在容器中以root身份运行,实际会带来哪些安全隐患呢?在Docker镜像和Kubernetes配置中,这一最佳实践常常被重点强调。在Kubernetes清单文件中,…

Docker 安装详细教程(适用于CentOS 7 系统)

目录 步骤如下&#xff1a; 1. 卸载旧版 Docker 2. 配置 Docker 的 YUM 仓库 3. 安装 Docker 4. 启动 Docker 并验证安装 5. 配置 Docker 镜像加速 总结 前言 Docker 分为 CE 和 EE 两大版本。CE即社区版&#xff08;免费&#xff0c;支持周期7个月&#xff09;&#xf…

[MRCTF2020]Ez_bypass1(md5绕过)

[MRCTF2020]Ez_bypass1(md5绕过) ​​ 这道题就是要绕过md5强类型比较&#xff0c;但是本身又不相等&#xff1a; md5无法处理数组&#xff0c;如果传入的是数组进行md5加密&#xff0c;会直接放回NULL&#xff0c;两个NuLL相比较会等于true&#xff1b; 所以?id[]1&gg…

Deep Crossing:深度交叉网络在推荐系统中的应用

实验和完整代码 完整代码实现和jupyter运行&#xff1a;https://github.com/Myolive-Lin/RecSys--deep-learning-recommendation-system/tree/main 引言 在机器学习和深度学习领域&#xff0c;特征工程一直是一个关键步骤&#xff0c;尤其是对于大规模的推荐系统和广告点击率预…

C++多线程编程——基于策略模式、单例模式和简单工厂模式的可扩展智能析构线程

1. thread对象的析构问题 在 C 多线程标准库中&#xff0c;创建 thread 对象后&#xff0c;必须在对象析构前决定是 detach 还是 join。若在 thread 对象销毁时仍未做出决策&#xff0c;程序将会终止。 然而&#xff0c;在创建 thread 对象后、调用 join 前的代码中&#xff…

Rust中使用ORM框架diesel报错问题

1 起初环境没有问题&#xff1a;在Rust开发的时候起初使用的是mingw64平台加stable-x86_64-pc-windows-gnu编译链&#xff0c;当使用到diesel时会报错&#xff0c;如下&#xff1a; x86_64-w64-mingw32/bin/ld.exe: cannot find -lmysql具体信息很长这是主要信息是rust找不到链…

Fastdds学习分享_xtpes_发布订阅模式及rpc模式

在之前的博客中我们介绍了dds的大致功能&#xff0c;与组成结构。本篇博文主要介绍的是xtypes.分为理论和实际运用两部分.理论主要用于梳理hzy大佬的知识&#xff0c;对于某些一带而过的部分作出更为详细的阐释&#xff0c;并在之后通过实际案例便于理解。案例分为普通发布订阅…

Windows:AList+RaiDrive挂载阿里云盘至本地磁盘

零、前言 电脑存储的文件多了&#xff0c;出现存储空间不够用的情况。又没前买新的硬盘或者笔记本电脑没有额外的插槽提供给新的硬盘。遇到这种情况&#xff0c;我想到可以使用网盘&#xff0c;但单纯的网盘又要上传下载&#xff0c;极其麻烦。看到WPS云盘可以直接挂载本地&…

Unity游戏(Assault空对地打击)开发(3) 摄像机的控制

详细步骤 打开My Assets或者Package Manager。 选择Unity Registry。 搜索Cinemachine&#xff0c;找到 Cinemachine包&#xff0c;点击 Install按钮进行安装。 关闭窗口&#xff0c;新建一个FreeLook Camera&#xff0c;如下。 接着新建一个对象Pos&#xff0c;拖到Player下面…

保姆级教程Docker部署Zookeeper官方镜像

目录 1、安装Docker及可视化工具 2、创建挂载目录 3、运行Zookeeper容器 4、Compose运行Zookeeper容器 5、查看Zookeeper运行状态 6、验证Zookeeper是否正常运行 1、安装Docker及可视化工具 Docker及可视化工具的安装可参考&#xff1a;Ubuntu上安装 Docker及可视化管理…

力扣73矩阵置零

给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 输入&#xff1a;matrix [[0,1,2,0],[3,4,5,2],[…

【ArcGIS_Python】使用arcpy脚本将shape数据转换为三维白膜数据

说明&#xff1a; 该专栏之前的文章中python脚本使用的是ArcMap10.6自带的arcpy&#xff08;好几年前的文章&#xff09;&#xff0c;从本篇开始使用的是ArcGIS Pro 3.3版本自带的arcpy&#xff0c;需要注意不同版本对应的arcpy函数是存在差异的 数据准备&#xff1a;准备一个…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.19 线性代数核武器:BLAS/LAPACK深度集成

2.19 线性代数核武器&#xff1a;BLAS/LAPACK深度集成 目录 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…

记8(高级API实现手写数字识别

目录 1、Keras&#xff1a;2、Sequential模型&#xff1a;2.1、建立Sequential模型&#xff1a;modeltf.keras.Sequential()2.2、添加层&#xff1a;model.add(tf.keras.layers.层)2.3、查看摘要&#xff1a;model.summary()2.4、配置训练方法&#xff1a;model.compile(loss,o…

RK3568中使用QT opencv(显示基础图像)

文章目录 一、查看对应的开发环境是否有opencv的库二、QT使用opencv一、查看对应的开发环境是否有opencv的库 在开发板中的/usr/lib目录下查看是否有opencv的库: 这里使用的是正点原子的ubuntu虚拟机,在他的虚拟机里面已经安装好了opencv的库。 二、QT使用opencv 在QT pr…

el-table表格点击单元格实现编辑

使用 el-table 和 el-table-column 创建表格。在单元格的默认插槽中&#xff0c;使用 div 显示文本内容&#xff0c;单击时触发编辑功能。使用 el-input 组件在单元格中显示编辑框。data() 方法中定义了 tableData&#xff0c;tabClickIndex: null,tabClickLabel: ,用于判断是否…

idea隐藏无关文件

idea隐藏无关文件 如果你想隐藏某些特定类型的文件&#xff08;例如 .log 文件或 .tmp 文件&#xff09;&#xff0c;可以通过以下步骤设置&#xff1a; 打开设置 在菜单栏中选择 File > Settings&#xff08;Windows/Linux&#xff09;或 IntelliJ IDEA > Preference…