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

news2025/1/20 7:25:53

文章目录

    • 🚀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;
	};
	//->重载sh
	ptr 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.coloradmin.cn/o/1719548.html

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

相关文章

stack和queue(1)

一、stack的简单介绍和使用 1.1 stack的介绍 1.stack是一种容器适配器&#xff0c;专门用在具有先进后出&#xff0c;后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入和弹出操作。 2.stack是作为容器适配器被实现的&#xff0c;容器适配器即是…

复习leetcode第二题:两数相加

本文会给出笔者自己的解答&#xff08;代码较为冗余&#xff0c;其实就是屎山代码&#xff09;以及优秀代码的解析 下图是题目 解法1&#xff08;笔者所使用的办法&#xff09;&#xff1a; 解题思路&#xff1a; 以下思路是基于示例1&#xff08;上图&#xff09;思考的 步骤…

前端Vue小兔鲜儿电商项目实战Day05

一、登录 - 整体认识和路由配置 1. 整体认识 登录页面的主要功能就是表单校验和登录退出业务 ①src/views/Login/index.vue <script setup></script><template><div><header class"login-header"><div class"container m-…

【React】封装一个好用方便的消息框(Hooks Bootstrap 实践)

引言 以 Bootstrap 为例&#xff0c;使用模态框编写一个简单的消息框&#xff1a; import { useState } from "react"; import { Modal } from "react-bootstrap"; import Button from "react-bootstrap/Button"; import bootstrap/dist/css/b…

根据状态转移图实现时序电路 (三段式状态机)

看图编程 * ** 代码 module seq_circuit(input C ,input clk ,input rst_n,output wire Y ); reg [1:0] current_stage ; reg [1:0] next_stage ; reg Y_reg; //输出//第一段 &#xff1a; 初始化当前状态和…

TensorFlow Playground神经网络演示工具使用方法详解

在现代机器学习领域,神经网络无疑是一个重要的研究方向。然而,对于许多初学者来说,神经网络的概念和实际操作可能显得相当复杂。幸运的是,TensorFlow Playground 提供了一个交互式的在线工具,使得我们可以直观地理解和实验神经网络的基本原理。在这篇博客中,我们将详细介…

Spring Boot 项目中使用 JSP

文章目录 Spring Boot 项目中使用 JSP项目结构引入依赖包编写页面和后台运行方式一&#xff1a;Maven 命令运行方式二&#xff1a;在 IDEA 中运行方式三&#xff1a;打 war 包部署运行 Spring Boot 项目中使用 JSP 在 Spring Boot 项目中不是不可以使用 JSP 。想在 Spring Boo…

Fully Convolutional Networks for Semantic Segmentation--论文笔记

论文笔记 资料 1.代码地址 2.论文地址 https://arxiv.org/abs/1411.4038 3.数据集地址 论文摘要的翻译 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们表明&#xff0c;卷积网络本身&#xff0c;经过端到端&#xff0c;像素对像素的训练&#xff0c;在…

【NPS】微软NPS配置802.1x,验证域账号,动态分配VLAN(有线网络篇)

上两篇中介绍了如何配置NPS和在WLC上如何配置802.1X来实现验证域账号和动态分配VLAN&#xff0c;802.1x协议作为一种成熟的身份验证框架&#xff0c;不仅适用于无线网络&#xff0c;同样也适用于有线网络环境。这里我们将介绍如何在有线网络中部署802.1x认证&#xff0c;以验证…

IDEA调试前端html报错

IDEA调试前端html报错 报错如下&#xff1a; Waiting for connection to localhost:59004. Please ensure that the browser was started successfully with remote debugging port opened. Port cannot be opened if Chrome having the same User Data Directory is already …

代码随想录算法训练营第三十二 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 讲解链接&#xff1a;https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html 简单思路&#xff1a;逐个计算连续两天的股票差值&#xff0c;sum初始为零&…

今日学会的,刘姥姥进大观园

Git - First-Time Git Setup 下载了Git&#xff0c;会用Git了&#xff1f; 还有这个&#xff1a;学习 HTML5 Canvas 这一篇文章就够了 | 菜鸟教程 (runoob.com) JavaScript 用法 | 菜鸟教程 (runoob.com) 看到这个真的是受益匪浅&#xff0c;我终于懂了一直有的疑惑。 3D可…

生产问题(十六)数据丢失-mysql binlog排查

一、引言 最近作者遇到一个线上问题&#xff0c;是mysql 的数据丢失了&#xff0c;这里记录一下排查过程和binlog的分析。 二、问题 问题出现的表象是应用系统大量报错&#xff0c;各种空指针之类的&#xff0c;这种一看就不可能是代码发布的问题&#xff0c;原因一定在框架、…

springboot+vue 社区养老服务系统

Springbootvue社区居家养老服务系统&#xff0c;数据库mysql&#xff0c;mybatis框架&#xff0c;有可视化页面。 功能&#xff1a; 用户管理 养老服务管理 护理人员管理 服务类型管理 健康状况管理 社区管理 服务区管理 娱乐资讯管理 咨询分类管理 反馈建议 系统简历管理 轮播…

华为telnet的两种认证方式

华为telnet的两种认证方式 实验拓扑&#xff1a; 实验要求&#xff1a; 1.采用普通密码认证实现telnet 远程登录机房设备R3 2.采用AAA认证服务方式实现telnet 远程登录机房设备R3 实验步骤&#xff1a; 1.完成基本配置&#xff08;设备接口配置IP&#xff0c;此步骤略过&#…

2024上海中小学生古诗文大会方案已发布,家长孩子最关心10个问题

昨天&#xff08;2024年5月30日&#xff09;下午15点&#xff0c;上海中小学生古诗文大会组委会通过两个公众号发布了《2024上海中小学生古诗文大会系列活动方案出炉》的推文&#xff08;下称《方案》&#xff09;。如我之前的分析和预测&#xff0c;5月份会发布今年的中小学生…

【如何用爬虫玩转石墨文档?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

机器人动力学模型与MATLAB仿真

机器人刚体动力学由以下方程控制&#xff01;&#xff01;&#xff01; startup_rvc mdl_puma560 p560.dyn 提前计算出来这些“disturbance”&#xff0c;然后在控制环路中将它“抵消”&#xff08;有时候也叫前馈控制&#xff09; 求出所需要的力矩&#xff0c;其中M项代表克服…

判断自守数-第13届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第75讲。 判断自守数&#…

【Qt秘籍】[006]-Qt 的 Hello World程序-编程第一步

"Hello,World!" 中文意思是“你好&#xff0c;世界”。 因为 The C Programming Language 中使用它做为第一个演示程序&#xff0c;后来很多程序员在学习编程或进行设备调试时延续了这一习惯。 下面&#xff0c;我们也将演示Qt中的"Hello World!" 我们先创…