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

C++初阶-list类的模拟实现

list类的模拟实现

  • 一、基本框架
    • 1.1 节点类
    • 1.2 迭代器类
    • 1.3 list类
  • 二、构造函数和析构函数
    • 2.1 构造函数
    • 2.2 析构函数
  • 三、operator=的重载和拷贝构造
    • 3.1 operator=的重载
    • 3.2 拷贝构造
  • 四、迭代器的实现
    • 4.1 迭代器类中的各种操作
    • 4.1 list类中的迭代器
  • 五、list的增容和删除
    • 5.1 尾插尾删
    • 5.2 头插头删
    • 5.3 任意位置的插入和删除
  • 六、完整代码
    • 6.1 list.h
    • 6.2 test.cpp

一、基本框架

list的底层和vector和string不同,实现也有所差别,特别是在迭代器的设计上,本文讲介绍list的简单模拟实现。
list底层是一个带头双向循环链表,在节点上变化不大。
list整体由三个类组成
1.节点类(封装一个节点)
2.迭代器类
3.list类

1.1 节点类

list节点类是一个模板类以适合于任何类型的ist对象,封装了一个节点需要的基本成员
成员变量
前驱指针 _prev
后继指针 _next
数据存储_data

成员函数
只有一个构造函数,用于初始化节点data数据和置空指针,构造函数的x参数是缺省参数,适应不同场景。
注意节点类不需要拷贝构造和析构函数,对于节点的拷贝构造在list中只需要浅拷贝即可,节点的释放也不在节点类中进行!

template<class T>
struct list_node
{list_node<T>* _next;list_node<T>* _prev;T _data;
};

1.2 迭代器类

  迭代器类也是封装节点,但是迭代器类不会构造节点,只会利用现有节点构造一个迭代器,在迭代器内部通过各种运算符重载对节点的状态做修改!
  其次,会涉及返回节点指针或数据data的引用,所以需要在构造对象时将list数据类型的指针和引用类型传给迭代器对象!
  迭代器在不访问data的情况下返回的都是迭代器,将声明本迭代器类型self,在函数操作完成时返回self(迭代器)即可!

//1、迭代器要么就是原生指针
//2、迭代器要么就是自定义类型对原生指针的封装,模拟指针的行为
template<class T,class Ref,class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T,Ref,Ptr> self;node* _node;
};

迭代器对象不会凭空创造节点,只会利用现有的节点(迭代器节点类型与list节点类型相同),所以不需要拷贝构造和析构函数,浅拷贝足以!

1.3 list类

list类中包含一个头节点和迭代器以及各种操作函数!

template<class T>
class list
{typedef list_node<T> node;
public:typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*>const_iterator;
private:node* _head;
};

二、构造函数和析构函数

2.1 构造函数

节点类的构造
将节点进行初始化

template<class T>
struct list_node
{list_node<T>* _next;list_node<T>* _prev;T _data;list_node(const T& x=T()):_next(nullptr),_prev(nullptr),_data(x){}
};

迭代器的构造
成员变量只有结点node,对结点进行初始化

template<class T,class Ref,class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T,Ref,Ptr> self;node* _node;__list_iterator(node* n):_node(n){}
};

list类的构造
因为是带头的链表,所以在实例化时必须事先申请一个头结点,所以所有的构造函数都会在操作前申请一个头结点,为了避免代码的冗余,我们将头节点的创建封装为一个函数,在构造函数初始化时调用创建头结点。
当我们需要构造空链表时,直接调用empty_init();函数即可
迭代器区间构造也是调用push_back进行尾插

template<class T>
class list
{typedef list_node<T> node;public:typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;void empty_init(){_head = new node;_head->_next = _head;_head->_prev = _head;}list(){/*_head = new node;_head->_next = _head;_head->_prev = _head;*/empty_init();}template <class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}private:node* _head;
};

2.2 析构函数

析构函数需要释放所有结点以及头结点,在释放前需要判断当前链表是否为空,如果为空直接置空头节点

~list()
{clear();delete _head;_head = nullptr;
}	void clear()
{iterator it = begin();while (it != end()){//it = erase(it);erase(it++);}
}

三、operator=的重载和拷贝构造

3.1 operator=的重载

对于赋值重载,与拷贝构造相似,但是赋值重载在传递参数时使用传值传参,这样就自动帮我们构造了一个临时对象,我们只需要swap一下临时对象的头节点即可,将我们现在的链表交给临时对象销毁,这样就完成了赋值。有时可能需要连等,所以需要返回对象的引用。

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

3.2 拷贝构造

拷贝构造最好采用现代写法,构造临时对象使用swap交换,在此之前,因为是构造函数所以需要创造头结点,调用empty_init()函数,再进行拷贝

//lt2(lt1) 拷贝构造传统写法
/*list(const list<T>& lt)
{empty_init();for (auto e : lt){push_back(e);}
}*/void swap(list<T>& tmp)
{std::swap(_head, tmp._head);
}//现代写法
list(const list<T>& lt)
{empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);
}

四、迭代器的实现

4.1 迭代器类中的各种操作

const类型的对象只能使用const类型的迭代器,那么const类型的迭代器如何实现呢、需要再重新封装吗,像上面那样。可以,但是没有必要,因为那样代码的冗余度就会很高,我们只需要给模板增加两个参数就可以了。即template<class T,class Ref,class Ptr>
在这里插入图片描述

//1、迭代器要么就是原生指针
//2、迭代器要么就是自定义类型对原生指针的封装,模拟指针的行为
template<class T,class Ref,class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T,Ref,Ptr> self;node* _node;__list_iterator(node* n):_node(n){}Ref& operator*(){return _node->_data;}Ptr operator->()    //it->_a1  it->->_a1  本来应该是两个->,但是为了增强可读性,省略了一个->{return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}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;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}
};

4.1 list类中的迭代器

	template<class T>class list{typedef list_node<T> node;public:typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;//typedef __list_const_iterator<T> const_iterator;iterator begin(){//iterator it(_head->_next);//return it;return iterator(_head->_next);}const_iterator begin() const{//iterator it(_head->_next);//return it;return const_iterator(_head->_next);}iterator end(){//iterator it(_head);//return it;return iterator(_head);}const_iterator end() const{//iterator it(_head);//return it;return const_iterator(_head);}

五、list的增容和删除

5.1 尾插尾删

尾插结点需要修改_head和tail的连接关系,链入新节点
1.根据参数创建一个新节点new_node
2.记录原尾结点tail
3.修改_head和tail之间的链接关系,再其中链入new_node
在这里插入图片描述

直接复用insert即可

void push_back(const T& x=T())
{/*node* tail = _head->_prev;node* new_node = new node(x);tail->_next = new_node;new_node->_prev = tail;new_node->_next = _head;_head->_prev = new_node;*/insert(end(), x);
}

直接复用erase即可

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

5.2 头插头删

直接复用insert即可

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

直接复用erase即可

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

5.3 任意位置的插入和删除

任意位置插入是在pos迭代器位置前插入一个结点,并返回这个结点的迭代器!
1.检查pos迭代器中结点但是否正常
2.获取pos位置的当前结点pos._node,获取pos位置的前驱结点cur->_prev
3.根据参数申请一个新节点new_node
4.将新节点new_node链入pos结点与pos前驱结点之间
5.链入成功后返回新插入结点的迭代器

在这里插入图片描述

iterator insert(iterator pos, const T& x)
{assert(pos._node);node* cur = pos._node;node* prev = cur->_prev;node* new_node = new node(x);prev->_next = new_node;new_node->_prev = prev;new_node->_next = cur;cur->_prev = new_node;return iterator(new_node);
}

在这里插入图片描述
任意位置删除时删除pos迭代器位置的结点,并返回删除结点的下一个结点的迭代器
1.检查链表是否为空且pos迭代器中结点是否正常
2.获取pos结点的前驱结点pos._node->_prev
3.获取pos结点的后继结点pos._node->_next
4.链接pos._node->_prev和pos._node->_next结点,剥离pos结点
5.删除pos结点
6.返回pos._node->_next结点的迭代器(即pos的下一个结点的迭代器)

iterator erase(iterator pos)
{assert(pos != end());node* prev = pos._node->_prev;node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;return iterator(next);
}

六、完整代码

6.1 list.h

#pragma once
#include<assert.h>namespace zl
{template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _data;list_node(const T& x=T()):_next(nullptr),_prev(nullptr),_data(x){}};//1、迭代器要么就是原生指针//2、迭代器要么就是自定义类型对原生指针的封装,模拟指针的行为template<class T,class Ref,class Ptr>struct __list_iterator{typedef list_node<T> node;typedef __list_iterator<T,Ref,Ptr> self;node* _node;__list_iterator(node* n):_node(n){}Ref& operator*(){return _node->_data;}Ptr operator->()    //it->_a1  it->->_a1  本来应该是两个->,但是为了增强可读性,省略了一个->{return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}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;}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 list_node<T> node;typedef __list_const_iterator<T> self;node* _node;__list_const_iterator(node* n):_node(n){}const T& operator*(){return _node->_data;}self& operator++(){_node = _node->_next;return *this;}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;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};*/template<class T>class list{typedef list_node<T> node;public:typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;//typedef __list_const_iterator<T> const_iterator;iterator begin(){//iterator it(_head->_next);//return it;return iterator(_head->_next);}const_iterator begin() const{//iterator it(_head->_next);//return it;return const_iterator(_head->_next);}iterator end(){//iterator it(_head);//return it;return iterator(_head);}const_iterator end() const{//iterator it(_head);//return it;return const_iterator(_head);}void empty_init(){_head = new node;_head->_next = _head;_head->_prev = _head;}list(){/*_head = new node;_head->_next = _head;_head->_prev = _head;*/empty_init();}template <class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}//lt2(lt1) 拷贝构造传统写法/*list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}*/void swap(list<T>& tmp){std::swap(_head, tmp._head);}//现代写法list(const list<T>& lt){empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);}//lt1=lt3list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){//it = erase(it);erase(it++);}}void push_back(const T& x=T()){/*node* tail = _head->_prev;node* new_node = new node(x);tail->_next = new_node;new_node->_prev = tail;new_node->_next = _head;_head->_prev = new_node;*/insert(end(), x);}void push_front(const T& x = T()){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos, const T& x){node* cur = pos._node;node* prev = cur->_prev;node* new_node = new node(x);prev->_next = new_node;new_node->_prev = prev;new_node->_next = cur;cur->_prev = new_node;}iterator erase(iterator pos){assert(pos != end());node* prev = pos._node->_prev;node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;return iterator(next);}private:node* _head;};void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){//(*it) *= 2;cout << *it << " ";++it;}cout << endl;}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()){cout << *it << " ";++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;print_list(lt);}struct AA{int _a1;int _a2;AA(int a1=0,int a2=0):_a1(a1),_a2(a2){}};void test_list2(){list<AA> lt;lt.push_back(AA(1, 1));lt.push_back(AA(2, 2));lt.push_back(AA(3, 3));//AA* ptrlist<AA>::iterator it = lt.begin();while (it != lt.end()){//cout << (*it)._a1 << (*it)._a2 << endl;cout << it->_a1 << it->_a2 << endl;//cout << it.operator->()->_a1 << ":" << it.operator->()->_a1 << endl;++it;}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;auto pos = lt.begin();++pos;lt.insert(pos, 20);for (auto e : lt){cout << e << " ";}cout << endl;lt.push_back(100);lt.push_front(1000);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_back();lt.pop_front();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);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);lt.push_back(30);lt.push_back(40);for (auto e : lt){cout << e << " ";}cout << endl;}void test_list5(){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> lt2(lt);for (auto e : lt2){cout << e << " ";}cout << endl;list<int> lt3;lt3.push_back(10);lt3.push_back(20);lt3.push_back(30);lt3.push_back(40);lt3.push_back(50);for (auto e : lt3){cout << e << " ";}cout << endl;lt = lt3;for (auto e : lt){cout << e << " ";}cout << endl;}
}

6.2 test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<list>
using namespace std;
#include "list.h"int main()
{//zl::test_list1();//zl::test_list2();//zl::test_list3();//zl::test_list4();zl::test_list5();//std::vector<int>::iterator it;//cout << typeid(it).name() << endl;return 0;
}

相关文章:

C++初阶-list类的模拟实现

list类的模拟实现 一、基本框架1.1 节点类1.2 迭代器类1.3 list类 二、构造函数和析构函数2.1 构造函数2.2 析构函数 三、operator的重载和拷贝构造3.1 operator的重载3.2 拷贝构造 四、迭代器的实现4.1 迭代器类中的各种操作4.1 list类中的迭代器 五、list的增容和删除5.1 尾插…...

RecyclerView中的设计模式解读

一.观察者模式&#xff1a;&#xff08;待完善&#xff0c;这个写的不咋地&#xff0c;没理解透彻&#xff09; 1.观察者模式的概念&#xff1a; &#xff08;1&#xff09;消息传递方向&#xff1a;被观察者->观察者 &#xff08;2&#xff09;代码实现&#xff1a; 首…...

ACwing算法备战蓝桥杯——Day30——树状数组

定义&#xff1a; 树状数组是一种数据结构&#xff0c;能将对一个区间内数据进行修改和求前缀和的这两种操作的最坏时间复杂度降低到O(logn); 实现所需变量 变量名变量数据类型作用数组a[]int存储一段区间数组tr[]int表示树状数组 主要操作 函数名函数参数组要作用lowbit()int…...

elementui + vue2实现表格行的上下移动

场景&#xff1a; 如上&#xff0c;要实现表格行的上下移动 实现&#xff1a; <el-dialogappend-to-bodytitle"条件编辑":visible.sync"dialogVisible"width"60%"><el-table :data"data1" border style"width: 100%&q…...

2、快速搞定Kafka术语

快速搞定Kafka术语 Kafka 服务端3层消息架构 Kafka 客户端Broker 如何持久化数据小结 Kafka 服务端 3层消息架构 第 1 层是主题层&#xff0c;每个主题可以配置 M 个分区&#xff0c;而每个分区又可以配置 N 个副本。第 2 层是分区层&#xff0c;每个分区的 N 个副本中只能有…...

CSS新手入门笔记整理:CSS3选择器

属性选择器 属性选择器&#xff0c;指的是通过“元素的属性”来选择元素的一种方式。 语法 元素[attr^"xxx"]{} 元素[attr$"xxx"]{} 元素[attr*"xxx"]{} 选择器 说明 E[attr^"xxx"] 选择元素E&#xff0c;其中E元素的attr属性是…...

D34|不同路径

62.不同路径 初始思路&#xff1a; 1&#xff09;确定dp数组以及下标的含义&#xff1a; dp[i][i]存放到第i1行和第i1列的方法数 2&#xff09;确定递推公式&#xff1a; dp[i][i] dp[i -1][i] dp[i][i-1] 3&#xff09;dp数组如何初始化 第0行是1&#xff1b; 第0列是1&a…...

【运维】Kafka高可用: KRaft(不依赖zookeeper)集群搭建

文章目录 一. kafka kraft 集群介绍1. KRaft架构2. Controller 服务器3. Process Roles4. Quorum Voters5. kraft的工作原理 ing 二. 集群安装1. 安装1.1. 配置1.2. 格式化 2. 启动测试2.1. 启功节点服务2.2. 测试 本文主要介绍了 kafka raft集群架构&#xff1a; 与旧架构的不…...

Python 自动化之批量处理文件(一)

批量新建目录、文档Pro版本 文章目录 批量新建目录、文档Pro版本前言一、做成什么样子二、基本思路1.引入库2.基本架构 三、用户输入模块四、数据处理模块1.excel表格数据获取2.批量数据的生成 总结 前言 我来写一个不一样的批量新建吧。在工作中&#xff0c;有些同学应该会遇…...

力扣72. 编辑距离

动态规划 思路&#xff1a; 假设 dp[i][j] 是 word1 前 i 个字母到 word2 前 j 个字母的编辑距离&#xff1b;那么状态 dp[i][j] 状态的上一个状态有&#xff1a; dp[i - 1][j]&#xff0c;word1 前 i - 1 个字母到 word2 前 j 个字母的编辑距离&#xff0c;此状态再插入一个字…...

Unity中 URP Shader 的纹理与采样器的分离定义

文章目录 前言一、URP Shader 纹理采样的实现1、在属性面板定义一个2D变量用于接收纹理2、申明纹理3、申明采样器4、进行纹理采样 二、申明纹理 和 申明采样器内部干了什么1、申明纹理2、申明采样器 三、采样器设置采样器的传入格式1、纹理设置中&#xff0c;可以看见我们的采样…...

Electron学习第一天 ,启动项目

之前在安装官网的步骤操作&#xff0c;结果报错&#xff0c;找了好多办法&#xff0c;最后这种办法成功启动项目&#xff0c;并且没有报错&#xff0c;特此记录 特别提醒&#xff0c;最好安装淘宝镜像&#xff0c;npm 太慢&#xff0c;会导致报错问题&#xff0c;解决起来个人觉…...

WebService技术--随笔1

1.WebService 发展史 创建阶段&#xff08;1990 年代末至 2000 年代初&#xff09;&#xff1a;在这个阶段&#xff0c;XML-RPC 和 SOAP 协议被引入&#xff0c;为跨平台和跨语言的应用程序集成提供了基础。XML-RPC 提供了一种基于 XML 的远程过程调用机制&#xff0c;而 SOAP…...

如何使用Docker将.Net6项目部署到Linux服务器(一)

目录 一 配置服务器环境 1.1 配置yum 1.1.1 更新yum包 1.1.2 yum命令 1.2 配置docker …...

第4章-第3节-Java中跟数组相关的几个算法以及综合应用

在写这篇博文之前&#xff0c;先大概说明一下&#xff0c;就是很常见的数组算法如求最大值、一维数组的遍历等&#xff0c;这里就不去专门说明了&#xff0c;只说一些有代表性的&#xff0c;然后就是冒泡排序算法很容易查阅到&#xff0c;这里也不专门说明了&#xff0c;只说明…...

AlexNet(pytorch)

AlexNet是2012年ISLVRC 2012&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;竞赛的冠军网络&#xff0c;分类准确率由传统的 70%提升到 80% 该网络的亮点在于&#xff1a; &#xff08;1&#xff09;首次利用 GPU 进行网络加速训练。 &#xff…...

【单调栈 】LeetCode321:拼接最大数

作者推荐 【动态规划】【广度优先搜索】LeetCode:2617 网格图中最少访问的格子数 本文涉及的知识点 单调栈 题目 给定长度分别为 m 和 n 的两个数组&#xff0c;其元素由 0-9 构成&#xff0c;表示两个自然数各位上的数字。现在从这两个数组中选出 k (k < m n) 个数字…...

TikTok与虚拟现实的完美交融:全新娱乐时代的开启

TikTok&#xff0c;这个风靡全球的短视频平台&#xff0c;与虚拟现实&#xff08;VR&#xff09;技术的深度结合&#xff0c;为用户呈现了一场全新的娱乐盛宴。虚拟现实技术为TikTok带来了更丰富、更沉浸的用户体验&#xff0c;标志着全新娱乐时代的开启。本文将深入探讨TikTok…...

PXI/PCIe/VPX机箱 ARM|x86 + FPGA测试测量板卡解决方案

PXI便携式测控系统是一种基于PXI总线的便携式测试测控系统&#xff0c;它填补了现有台式及机架式仪器在外场测控和便携测控应用上的空白&#xff0c;在军工国防、航空航天、兵器电子、船舶舰载等各个领域的外场测控场合和科学试验研究场合都有广泛的应用。由于PXI便携式测控系统…...

ES6 面试题 | 12.精选 ES6 面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

【linux】Debian不能运行sudo的解决

一、问题&#xff1a; sudo: 没有找到有效的 sudoers 资源&#xff0c;退出 sudo: 初始化审计插件 sudoers_audit 出错 二、可用的方法&#xff1a; 出现 "sudo: 没有找到有效的 sudoers 资源&#xff0c;退出" 和 "sudo: 初始化审计插件 sudoers_audit 出错&q…...

讲解ThinkPHP的链式操作

数据库提供的链式操作方法&#xff0c;可以有效的提高数据存取的代码清晰度和开发效率&#xff0c;并且支持所有的CURD操作。 使用也比较简单&#xff0c;假如我们现在要查询一个User表的满足状态为1的前10条记录&#xff0c;并希望按照用户的创建时间排序 Db::table(think_u…...

Java技术栈 —— 微服务框架Spring Cloud —— Ruoyi-Cloud 学习(二)

RuoYi项目开发过程 一、登录功能(鉴权模块)1.1 后端部分1.1.1 什么是JWT?1.1.2 什么是Base64?为什么需要它&#xff1f;1.1.3 SpringBoot注解解析1.1.4 依赖注入和控制反转1.1.5 什么是Restful?1.1.6 Log4j 2、Logpack、SLF4j日志框架1.1.7 如何将项目打包成指定bytecode字节…...

如何进行软件测试和测试驱动开发(TDD)?

1. 软件测试概述 1.1 什么是软件测试&#xff1f; 软件测试是一种评估系统的过程&#xff0c;目的是发现潜在的错误或缺陷。通过对软件进行测试&#xff0c;开发者和测试人员可以确定软件是否符合预期的需求、功能是否正常运行&#xff0c;以及系统是否足够稳定和可靠。 1.2…...

linux 开机启动流程

1.打开电源 2.BIOS 有时间和启动方式 3.启动Systemd 其pid为1 4.挂载引导分区 /boot 5.启动各种服务 如rc.local...

Mybatis 动态SQL的插入操作

需求 : 根据用户的输入情况进行插入 动态SQL:根据需求动态拼接SQL 用户往表中插入数据,有的数据可能不想插入,比如不想让别人知道自己的性别,性别就为空 insert into userinfo(username,password,age,gender,phone) values(?,?,?,?,?); insert into userinfo(username,…...

共建开源新里程:北京航空航天大学OpenHarmony技术俱乐部正式揭牌成立

12月11日,由OpenAtom OpenHarmony(以下简称“OpenHarmony”)项目群技术指导委员会(以下简称“TSC”)和北京航空航天大学共同举办的“OpenHarmony软件工程研讨会暨北京航空航天大学OpenHarmony技术俱乐部成立仪式”在京圆满落幕。 现场大合影 活动当天,多位重量级嘉宾出席了此次…...

企业微信机器人发送文本、图片、文件、markdown、图文信息

import requests import base64 import hashlib import json # 机器人地址的key值 key"811a1652-60e8-4f51-a1d9-231783399ad2" def path2base64(path):"""文件转换为base64:param path: 文件路径:return:"""with open(path, "rb…...

智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天牛须算法4.实验参数设定5.算法结果6.参考文…...

【Hive】【Hadoop】工作中常操作的笔记-随时添加

文章目录 1、Hive 复制一个表:2、字段级操作3、hdfs 文件统计 1、Hive 复制一个表: 直接Copy文件 create table new_table like table_name;hdfs dfs -get /apps/hive/warehouse/ods.db/table_nameload data local inpath /路径 into table new_table;修复表&#xff1a; m…...

电商网站怎么做微信支付/怎样宣传自己的产品

有时候我们需要在图片的某一个地方添加一个url&#xff0c;最好的办法就是为图片添加热点&#xff0c; 实例&#xff1a; <img src"zhaobiaowang.jpg" width"1002" height"750" border"0" usemap"#Map" /> <map n…...

潮州市住房和城乡建设局网站/市场营销方案

在有些情况下&#xff0c;我们不希望自己的shell脚本在运行时刻被中断&#xff0c;比如说我们写得shell脚 本设为某一用户的默认shell&#xff0c;使这一用户进入系统后只能作某一项工作&#xff0c;如数据库备份&#xff0c; 我 们可不希望用户使用ctrlC之类便进入到shell状…...

直播网站建设重庆/seo网站关键词优化机构

3分钟学会&#xff0c;2种Wincc v14多语言组态&#xff0c;实现工控屏语言切换项目组态效果预览如下方动态图所示&#xff0c;挺好的吧&#xff01;西门子WIncc V14项目多语言组态效果图一&#xff1a;必背技巧1.1&#xff1a;按钮事件组态系统函数修改显示语言(相比于利用VB脚…...

营销型的物流网站模板/百度分公司

一、.net篇 1 .netApi查看器&#xff0c;里面包含了C#几乎所有的库函数&#xff0c;遇到不懂的库&#xff0c;直接搜索查看就行了。 2 .netC#源函数和库的源码查看器&#xff0c;只需要把元函数或者库在网站中搜索&#xff0c;就可以看到封装的源码了 3 .net portability anal…...

b2b平台好做吗/seo分析是什么意思

1、生产者消费者问题三种关系&#xff1a;生产者--生产者&#xff08;互斥&#xff09;&#xff1b;消费者-消费者&#xff08;互斥&#xff09;&#xff1b;生产者--消费者&#xff08;互斥同步&#xff09;两个角色&#xff1a;生产者&#xff1b;消费者一种生产场所&#xf…...

门户网站模板源码/杭州seo博客

selectall selectall[~selectall.conband.is_empty]...