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

STL容器-- list的模拟实现(附源码)

STL容器-- list的模拟实现(附源码)

List的实现主要考察我们对list这一容器的理解,和代码的编写能力,通过上节对list容器的使用,我们对list容器已经有了一些基本的了解·,接下来就让我们来实现一些list容器常见的功能函数来加深我们对c++工程的理解:

在这里插入图片描述

一、基本框架的搭建

首先我们需要将基本的框架搭建好, 从之前我们学数据结构时,对list的一些认识并结合c++ stl标准可以得出:

  • 定义节点的构造
  • 明确指针的指向
  • list的封装
    根据c++中的标准我们可以得知,list时一个双向迭代器, 所以对应的, 我们需要定义的双向循环链表:

1.1节点的构造

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

在定义一个节点的时候,我们先让这个节点的_next and _prev指针为空

1.2 list的封装

    
template <class T>
struct ListNode
{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}
};template<class T>
class list
{
public:typedef ListNode<T> node;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}// functon define:}private:node* _head;
};

同时为了防止访问冲突,我们可以将我们自己实现的类,放在我们自己定义的命名域中:

namespace zdl
{template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val):_data(val),_next(nullptr),_prev(nullptr){}};template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}};template<class T>class list{public:typedef ListNode<T> node;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}// functon define:}private:node* _head;};
}

这样list的基本框架就搭建好了!!

二、节点的尾插和头插

2.1 节点的头插 (push_back)

在这里插入图片描述

通过前面数据结构的学习。我们已经清楚了链表的结构,在进行数据尾插时, 就只是在改变指针的指向罢了:

void push_back(const T& val){node* creat = new node(val);node* tail = _head->_prev;tail->_next = creat;creat->_prev = tail;creat->_next = _head;_head->_prev = creat; }

2.2 节点的头插(push_front)

节点的头插和尾插十分的相似,
这里我们就直接展示一下代码:

void push_front(const T& val){node* fnode = new node(val);fnode->_next = _head->_next;fnode->_prev = _head;_head->_next->_prev = fnode;_head->_next = fnode;}

2.3 数据插入验证

为了方便起见, 我这里再再这个类里面定义一个打印链表的函数:

 void Print_list(){node* cur = _head->_next;while (cur != _head){cout << cur->_data << " ";cur = cur->_next;}cout << endl;}

完成了list容器的头插和尾插操作接下来我们可以来验证一下,我们的函数实现是否有问题:

#include"list.h"int main()
{zdl::list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_front(3);l1.Print_list();return 0;
}

通过运行可知, 这里的函数没有问题:

在这里插入图片描述

三、list迭代器的实现

list迭代器的功能和vetor的功能有很多相似的地方,但是二者在底层实现时,使用的不同的方法:
基于,list迭代器的特殊性质,我们会采用类封装的方式来满足list_iterator的特殊性质:

3.1迭代器基本功能的实现和封装处理

template<class T>struct list_iterator{typedef ListNode<T> node;typedef list_iterator<T> self;node* _nd;list_iterator(node* nd):_nd(nd){}// zdl:: 实现迭代器的基本功能:// 解引用数值T& operator*(){return _nd->_data;}// zdl:: 前置++ / --self& operator++(){_nd = _nd->_next;return *this;}self& operator--(){_nd = _nd->_prev;return *this;}// zdl:: 后置 ++ / --self operator++(int){self tmp = _nd;_nd = _nd->_next;return tmp;}self operator--(int){self tmp = _nd;_nd = _nd->_prev;return tmp;}// zdl:: != 运算bool operator!=(const self& s){return _nd != s._nd;}};

实现了list_iterator的功能后,我们就只需要将他封装道list类中就可以正常使用了:
使用typedef 封装迭器
在这里插入图片描述
基本的逻辑都是十分的简单的接下来我们来简单的验证一代码是否可行:
在这里插入图片描述

3.2 对结构体(类)的解引用

->运算符的重载

大家现在可以想象一下这样的场景,假设我现在在llist中存储的不是基础类型的元素,而是类等较为复杂的对象时,我们应当怎么正常的使用这个类对象的成员呢?
这时,我们就可以考虑对->运算符重载, 通过返回对象的地址,来访问成员变量和成员函数等
下面我们就来举个例子:
假设我现在我要在list中存储pos类:

struct pos
{int row;int col;//构造函数pos(const int& x = 0, const int& y = 0):row(x),col(y){}//成员函数void pos_show(){printf("(%d, %d) ",row, col);}
};

我们就只需要重载->运算符:

T* operator->()
{return &_nd->_data;
}

运行后可以得到:
在这里插入图片描述
但是大家可能会觉得很奇怪,通过->重载,返回的只是_data的地址,为什么能直接访问到元素呢?不应该使用it->->解引用两次才行啊?
这个其实就只是c++便准下为我们提供的特殊语法, 通过这样的规定使我们能够直接访问到元素, 当然c++也是支持这样的写法的:
在这里插入图片描述
但是不支持这样的写法:
在这里插入图片描述

3.3const迭代器的实现与模板参数的巧用

前面我们已经实现了,可读可写的迭代器,现在我们就来实现一下只读迭代器:
const iterator,
其实从功能上看,这个迭代器与原来的迭代器十分的相似,只是不能对指向对象的值进行修改,因此我们就只需要对* 和 ->运算符重载的时候稍加修改就可以得到我们想要的结果,即再创建一个类:
在这里插入图片描述
其他的共同功能粗需要改动,只需要改动下面两个重载函数:

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

紧接着我们还需要在llist类中实现const对象专用的begin()、end()
在这里插入图片描述
在这里插入图片描述

接下来我们来验证一下效果:
在这里插入图片描述
现在consr iterator也实现好了,但是这里依然还存在问题,这样我们将相当于为迭代器实现了两个类,这两个类的攻击能还高度重合,这并没有,体现出模板函数的简洁性,因此我们还可以通过其他的方式来优化我们现在的代码。
通过对源码的分析,参照我们或许可以从中得到一些启发, 从源码中可知我们可以得知,通过对模板参数的巧用就可以的实现代码的简化:

在这里插入图片描述
接下来我们就只需要将代码稍加改动就可以实现我们的目的:
在这里插入图片描述
在这里插入图片描述
接下来,我们再次运行看看是否可以达到简化代码的效果:
在这里插入图片描述
可以发现现在的代码依然有效,代码简化成功!!

四、丰富构造函数、list增删查改的实现

现在我们已经完成了list的简单构造函数,现在我们就可以参照 c++ library完成其他的构造函数:

4.1 list(size_t n, const T& x = T())

我们要实现的这个函数和标准库中的一样,并且直接复用我峨嵋你已经实现的函数就好了:

list(size_t n, const T& x = T())
{for (int i = 0; i < n; i++){push_back(x);}
}

直接来演示一下的效果:
在这里插入图片描述

4.2 拷贝构造

我们就只需要将被拷贝链表的元素一个一个的拷贝进链表就行了:

list(const list<T>& l1)
{empty_init();for (auto& e : l1) push_back(e);
}

我们来测试一下效果:
在这里插入图片描述

4.3 插入函数的实现(insert)

想要在这个双向链表中插入节点,我们就需要

  • 待插入的值

  • 待插入位置

所以,insert函数定义为: void insert(iterator pos, const T& val = T())

iterator insert(iterator pos, const T& val = T())
{node* cur = pos._nd;node* prev = pos._nd->_prev;node* insrt = new node(val);prev->_next = insrt;insrt->_prev = prev;insrt->_next = cur;cur->_prev = insrt;return iterator(cur->_prev);}

这个函数也十分的简单如果,有的uu还没有接触过链表,或者是已经忘了链表的增删查改,可以移步去看看我之前的博客:链表的介绍

4.4链表的删除(earse)

关于erase和函数的定义,我们就只需要拿到需要删除的位置就可以了, 所以定义为:void erase(iterator pos)

iterator erase(iterator pos)
{assert(pos != end()); //! 注意不能够将哨兵位删除!!node* cur = pos._nd;node* prev = cur->_prev;prev->_next = cur->_next;cur->_next->_prev = prev;delete cur;return iterator(prev->_next);}

现在我们就直接来测试一下这个函数是否可以满足我们的要求:
在这里插入图片描述
由此可知我们实现的都没有问题。

4.5链表元素的查找(find)

定义find函数时,我们就只需要给函数一个特定的需要查找到的值,然后使这个函数返回这个元素的位置(迭代器

iterator find(const T& val)
{auto it = begin();while (it != end() && *it != val){it++;}if (*it == val) return it;return nullptr;}

在这里插入图片描述

4.6 头删和尾删操作

前面我们已经实现了earse 现在我们就只需要对这个和拿书尽心你给复用就好了:

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

接下来我们就直接来演示这个函数是否有用:

在这里插入图片描述

五、析构函数与clear函数

最后我们就来实现一下list的析构函数,我们还是继续函数的复用:

// zdl:: 析构类函数的实现:~list(){// ! 不仅要将所有的数值删除还需要将哨兵位也清除!clear();delete _head;_head = nullptr;            }void clear(){// !! 不能删除哨兵位,就只是将所有的数值清空。auto it = begin();while (it != end()) it = erase(it);}

现在我们就将已有的链表清空试试:
在这里插入图片描述

六、代码展示

list.h

#pragma once #include<iostream>
#include<cassert>
using  namespace std;
namespace zdl
{template <class T>struct ListNode{T _data;ListNode<T>* _next;ListNode<T>* _prev;// 节点的构造函数ListNode(const T& val = T()):_data(val),_next(nullptr),_prev(nullptr){}};template<class T, class Ref, class Ptr>struct list_iterator{typedef ListNode<T> node;typedef list_iterator<T, Ref, Ptr> self;node* _nd;list_iterator(node* nd):_nd(nd){}// zdl:: 实现迭代器的基本功能:// 解引用数值Ref operator*(){return _nd->_data;}Ptr operator->(){return &_nd->_data;}// zdl:: 前置++ / --self& operator++(){_nd = _nd->_next;return *this;}self& operator--(){_nd = _nd->_prev;return *this;}self& operator+(size_t n){while (n--){_nd = _nd->_next;}return *this;}self& operator-(size_t n){while (n--){_nd = _nd->_prev;}return *this;}// zdl:: 后置 ++ / --self operator++(int){self tmp = _nd;_nd = _nd->_next;return tmp;}self operator--(int){self tmp = _nd;_nd = _nd->_prev;return tmp;}// zdl:: != 运算bool operator!=(const self& s){return _nd != s._nd;}};template<class T>class list{public:typedef ListNode<T> node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;void empty_init(){// zdl :: 在初始化一个空链表时, 先定义一个哨兵位_head = new node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}list(const list<T>& l1){empty_init();for (auto& e : l1) push_back(e);}list(size_t n, const T& x = T()){empty_init();for (size_t i = 0; i < n; i++){push_back(x);}}void push_back(const T& val){node* creat = new node(val);node* tail = _head->_prev;tail->_next = creat;creat->_prev = tail;creat->_next = _head;_head->_prev = creat; }void push_front(const T& val){node* fnode = new node(val);fnode->_next = _head->_next;fnode->_prev = _head;_head->_next->_prev = fnode;_head->_next = fnode;}void Print_list(){node* cur = _head->_next;while (cur != _head){cout << cur->_data << " ";cur = cur->_next;}cout << endl;}// zdl:: 增删查改的实现iterator insert(iterator pos, const T& val = T()){node* cur = pos._nd;node* prev = pos._nd->_prev;node* insrt = new node(val);prev->_next = insrt;insrt->_prev = prev;insrt->_next = cur;cur->_prev = insrt;return iterator(cur->_prev);}iterator erase(iterator pos){assert(pos != end()); //! 注意不能够将哨兵位删除!!node* cur = pos._nd;node* prev = cur->_prev;prev->_next = cur->_next;cur->_next->_prev = prev;delete cur;return iterator(prev->_next);}iterator find(const T& val){auto it = begin();while (it != end() && *it != val){it++;}if (*it == val) return it;return nullptr;}void pop_front(){erase(begin());}void pop_back(){erase(--end());}// zdl:: 析构类函数的实现:~list(){// ! 不仅要将所有的数值删除还需要将哨兵位也清除!clear();delete _head;_head = nullptr;            }void clear(){// !! 不能删除哨兵位,就只是将所有的数值清空。auto it = begin();while (it != end()) it = erase(it);}
// zdl:: 使用类来模拟迭代器的行为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);}private:node* _head;};
}

test.cpp


#include"list.h"
#include<list>
struct pos
{int row;int col;//构造函数pos(const int& x = 0, const int& y = 0):row(x),col(y){}//成员函数void pos_show(){printf("(%d, %d) ",row, col);}
};
int main()
{// zdl::list<pos> l1;// pos p[] = {{1, 2}, {3, 4}, {5, 6}};// for (int i = 0; i < 3; i++) l1.push_back(p[i]);// auto it = l1.begin();// while (it != l1.end())// {//     it->pos_show();//     it++;//     cout << endl;// }// cout << endl;// zdl::list<int> l2(5, 4);// for (auto&i : l2) cout << i << " ";// cout << endl;// zdl::list<int> l4(3, 3);// l4.Print_list();// l4.insert(l4.begin() + 2, 2);// l4.Print_list();// l4.erase(l4.begin() + 2);// l4.Print_list();// zdl::list<int>l5;// for (int i = 1; i <= 10; i++) l5.push_back(i);// cout << "原数组:" << endl;// l5.Print_list();// // zdl:: 现在我们要借助 find + erase函数来删除元素:5// l5.erase(l5.find(5));// cout << "删除后:" << endl;// l5.Print_list();//  zdl:: 进行头删和尾删// cout << "进行尾删和头删后:" << endl;// l5.pop_back();// l5.pop_front();// l5.Print_list();// cout << "现在将所有的元素都删除!" << endl;// l5.clear();// l5.Print_list();zdl::list<int> l1(10, 10);cout <<"l1:" << endl;l1.Print_list();zdl::list<int> l2(l1);cout << "l2:" << endl;l2.Print_list();return 0;
}

好,常用的接口我们就实现了,list学习到此告一段落,再见!!

相关文章:

STL容器-- list的模拟实现(附源码)

STL容器-- list的模拟实现&#xff08;附源码&#xff09; List的实现主要考察我们对list这一容器的理解&#xff0c;和代码的编写能力&#xff0c;通过上节对list容器的使用&#xff0c;我们对list容器已经有了一些基本的了解&#xff0c;接下来就让我们来实现一些list容器常见…...

python——句柄

一、概念 句柄指的是操作系统为了标识和访问对象而提供的一个标识符&#xff0c;在操作系统中&#xff0c;每个对象都有一个唯一的句柄&#xff0c;通过句柄可以访问对象的属性和方法。例如文件、进程、窗口等都有句柄。在编程中&#xff0c;可以通过句柄来操作这些对象&#x…...

KubeSphere 与 Pig 微服务平台的整合与优化:全流程容器化部署实践

一、前言 近年来,为了满足越来越复杂的业务需求,我们从传统单体架构系统升级为微服务架构,就是把一个大型应用程序分割成可以独立部署的小型服务,每个服务之间都是松耦合的,通过 RPC 或者是 Rest 协议来进行通信,可以按照业务领域来划分成独立的单元。但是微服务系统相对…...

ESP8266-01S、手机、STM32连接

1、ESP8266-01S的工作原理 1.1、AP和STA ESP8266-01S为WIFI的透传模块&#xff0c;主要模式如下图&#xff1a; 上节说到&#xff0c;我们需要用到AT固件进行局域网应用&#xff08;ESP8266连接的STM32和手机进行连接&#xff09;。 ESP8266为一个WiFi透传模块&#xff0c;和…...

Web开发 -前端部分-CSS-2

一 长度单位 代码实现&#xff1a; <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…...

【QT用户登录与界面跳转】

【QT用户登录与界面跳转】 1.前言2. 项目设置3.设计登录界面3.1 login.pro参数3.2 界面设置3.2.1 登录界面3.2.2 串口主界面 4. 实现登录逻辑5.串口界面6.测试功能7.总结 1.前言 在Qt应用程序开发中&#xff0c;实现用户登录及界面跳转功能是构建交互式应用的重要步骤之一。下…...

记录一次关于spring映射postgresql的jsonb类型的转化器事故,并使用hutool的JSONArray完成映射

事件的起因是这样的&#xff0c;那次事故发生的起因是因为WebFlux和postgreSQL去重新做鱼皮的鱼图图项目&#xff08;鱼图图作业&#xff09;。 在做到picture表的时候&#xff0c;发现postgreSQL中有个jsonb的类型可以更好的支持json数组。 出于锻炼新技术的目的&#xff0c;…...

基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day2

为了使 2048 游戏的设计更加美观和用户友好&#xff0c;我们可以进行以下几项优化&#xff1a; 改善颜色方案&#xff1a;使用更温馨的颜色组合。添加动画效果&#xff1a;为方块的移动和合并添加渐变效果。优化分数显示&#xff1a;在分数增加时使用动画效果。 以下是改进后…...

Django框架:python web开发

1.环境搭建&#xff1a; &#xff08;a&#xff09;开发环境&#xff1a;pycharm &#xff08;b&#xff09;虚拟环境&#xff08;可有可无&#xff0c;优点&#xff1a;使用虚拟环境可以把使用的包自动生成一个文件&#xff0c;其他人需要使用时可以直接选择导入包&#xff…...

MySQL、HBase、ES的特点和区别

MySQL&#xff1a;关系型数据库&#xff0c;主要面向OLTP&#xff0c;支持事务&#xff0c;支持二级索引&#xff0c;支持sql&#xff0c;支持主从、Group Replication架构模型&#xff08;本文全部以Innodb为例&#xff0c;不涉及别的存储引擎&#xff09;。 HBase&#xff1…...

联发科MTK6762/MT6762安卓核心板_4G智能模块应用

MT6762安卓核心板是一款工业级高性能、可运行 android9.0 操作系统的 4G智能模块。MT6762平台打造具备 AI 体验、先进双摄像头拍摄效果且具备丰富连接功能的智能手机主板。 MT6762安卓核心板 是一款髙性能低功耗的 4G 全网通安卓智能模块。此模块支持 2G/3G/4G 移动&#xff0c…...

Windows7系统下载安装Source Code Pro字库

Source Code Pro字库介绍 Source Code Pro是由Adobe推出的一款专为代码展示和编写设计的开源等宽字体‌。它不仅在编程社区中广受好评&#xff0c;还被广泛应用于各种编辑器环境中&#xff0c;以提升代码的可读性和编程体验‌。 Source Code Pro的设计充分考虑了编程符号的呈…...

Navicat 17 功能简介 | 商业智能 BI

Navicat 17 功能简介 | 商业智能BI 随着 17 版本的发布&#xff0c;Navicat 也带来了众多的新特性&#xff0c;包括兼容更多数据库、全新的模型设计、可视化智能 BI、智能数据分析、可视化查询解释、高质量数据字典、增强用户体验、扩展 MongoDB 功能、轻松固定查询结果、便捷U…...

C# winodw TableLayoutPanel 料盒生产状态UI自动生成

料盒生产状态UI自动生成&#xff0c;效果如下 以前公司项目的这些都是手动拖控件做的。每个设备的料盒数量不一样&#xff0c;层数不一样时都要发好几个小时去改相关细节和代码。上次改了一次。这个又来了。上次就有想法做成根据参数自动生成。但项目时间有限有没有去深入思路和…...

提示词的艺术----AI Prompt撰写指南(个人用)

提示词的艺术 写在前面 制定提示词就像是和朋友聊天一样&#xff0c;要求我们能够清楚地表达问题。通过这个过程&#xff0c;一方面要不断练习提高自己地表达能力&#xff0c;另一方面还要锻炼自己使用更准确精炼的语言提出问题的能力。 什么样的提示词有用&#xff1f; 有…...

哪些前端打印插件可以实现监听用户选择了打印还是取消

在前端实现监听用户是否选择了打印还是取消的功能&#xff0c;确实是一个挑战&#xff0c;因为浏览器的打印行为是通过原生对话框处理的&#xff0c;而这些对话框的行为无法直接被 JavaScript 控制或监听。不过&#xff0c;有一些插件和方法可以帮助你更接近这个目标&#xff1…...

【PyCharm】连接Jupyter Notebook

【PyCharm】相关链接 【PyCharm】连接 Git【PyCharm】连接Jupyter Notebook【PyCharm】快捷键使用【PyCharm】远程连接Linux服务器【PyCharm】设置为中文界面 【PyCharm】连接Jupyter Notebook PyCharm连接Jupyter Notebook的过程可以根据不同的需求分为 本地连接 和 远程连…...

【Linux系统编程】—— 深入理解Linux中的环境变量与程序地址空间

文章目录 环境变量常见的环境变量查看环境变量环境变量的修改与使用环境变量的组织⽅式环境变量的命令通过代码如何获取环境变量环境变量的继承 前言&#xff1a;在Linux系统中&#xff0c;环境变量和程序地址空间是系统管理和进程运行的重要组成部分。本文将详细探讨环境变量的…...

Spark常见面试题-部分待更新

1. 简述hadoop 和 spark 的不同点&#xff08;为什么spark更快&#xff09; Hadoop是一个分布式管理、存储、计算的生态系统&#xff0c;包括HDFS&#xff08;分布式文件系统&#xff09;、MapReduce&#xff08;计算引擎&#xff09;和YARN&#xff08;资源调度器&#xff09;…...

Android BitmapShader实现狙击瞄具十字交叉线准星,Kotlin

Android BitmapShader实现狙击瞄具十字交叉线准星&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...