C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

news2025/1/9 20:33:30

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层

  • 一.容器适配器的介绍
  • 二.利用容器适配器实现栈和队列
    • 1.stack
    • 2.queue
  • 三.仿函数介绍
    • 1.什么是仿函数
    • 2.仿函数的使用
    • 3.函数指针的使用
      • 1.函数指针的用处
      • 2.利用函数指针完成回调
      • 3.利用仿函数完成回调
    • 4.仿函数的玩法
      • 1.取出Key/Key-Value模型中的Key
      • 2.自定义排序
  • 四.利用容器适配器和仿函数实现优先级队列
  • 五.利用正向迭代器作为适配器实现反向迭代器
    • 1.STL库里面的实现逻辑
      • 1.rbegin和rend的实现
    • 2.反向迭代器的实现
    • 3.画图模拟反向迭代器具体的遍历流程
      • 1.vector
      • 2.list
    • 4.具体实现
    • 5.对于list的适用
    • 6.对于vector的适用
    • 7.const_reverse_iterator的实现
    • 8.验证
      • 1.list
      • 2.vector
  • 六.deque的介绍
  • 七.deque的底层原理

一.容器适配器的介绍

适配器是一种设计模式(所谓的设计模式就是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结,是很多大佬的编程的过程中总结下来的经验,类似于"武林秘籍"),
该种模式是将一个类的接口转换成客户希望的另外一个接口。

我们来看一下STL库中stack的源码,了解一下容器适配器模式到底是什么
在这里插入图片描述
下面就让我们借助容器适配器来实现一下栈和队列吧
实现之后大家就会对容器适配器模式有更加深刻的理解

二.利用容器适配器实现栈和队列

1.stack

#pragma once
//容器适配器:vector可以,list可以,deque也可以,库里面默认使用deque
namespace wzs
{
    template<class T, class Container = deque<T>>
    class stack
    {
    public:
        //直接使用编译器默认生成的默认成员函数即可
        void push(const T& x)
        {
            _con.push_back(x);
        }

        void pop()
        {
            _con.pop_back();
        }

        T& top()
        {
            return _con.back();
        }

        const T& top()const
        {
            return _con.back();
        }

        size_t size()const
        {
            return _con.size();
        }

        bool empty()const
        {
            return _con.empty();
        }

    private:
        Container _con;
    };
}

可见,非常的easy
就是容器的复用而已
对于stack而言
它的适配器必须满足:
push_back,pop_back,back,size,empty这几个接口
因此stack的适配器可以是
vector
list
deque中的任何一个
在这里插入图片描述
验证完毕

2.queue

#pragma once
//容器适配器:list可以,deque也可以,库里面是deque,不过vector不可以,因为vector没有头删这个接口
namespace wzs
{
    template<class T, class Container = deque<T>>
    class queue
    {

    public:
        //使用编译器默认生成的默认成员函数即可

        void push(const T& x)
        {
            _con.push_back(x);
        }

        void pop()
        {
            _con.pop_front();
        }

        T& back()
        {
            return _con.back();
        }

        const T& back()const
        {
            return _con.back();
        }

        T& front()
        {
            return _con.front();
        }

        const T& front()const
        {
            return _con.front();
        }

        size_t size()const
        {
            return _con.size();
        }

        bool empty()const
        {
            return _con.empty();
        }

    private:

        Container _con;

    };
}

可见,非常的easy
就是容器的复用而已
对于queue而言
它的适配器必须满足:
push_back,pop_front,back,front,size,empty这几个接口
因此stack的适配器可以是
list
deque中的任何一个
而vector因为没有pop_front这个接口,因此不能作为queue的适配器
在这里插入图片描述
验证完毕

三.仿函数介绍

1.什么是仿函数

仿函数,又叫做函数对象,它是一个类
只不过这个类重载了operator()这个运算符,使得这个类实例化出的对象在调用operator()这个函数时使用起来特别像一个函数,
也就是说这个类实例化出的对象能够像函数一样调用,因此这个类被称为仿函数

下面给大家演示一下
这是比较两个T类型的大小
在这里插入图片描述
只要一个类重载了operator(),这个类就是一个仿函数类
这个类实例化出的对象就能像函数一样进行调用

2.仿函数的使用

算法库里面的sort函数就使用了仿函数
在这里插入图片描述
默认情况下sort是排升序的
如果我们想要排降序呢?
就要用到仿函数了
我们来演示一下,顺便学习一下仿函数的语法和特性

默认排升序
在这里插入图片描述
排降序
在这里插入图片描述
sort的第三个参数要求传入仿函数对象,所以可以这样做
在这里插入图片描述
其实我们也可以自己实现一个仿函数
一般来说仿函数写出来就是为了给外界用的,所以定义成class的话要加public访问限定符调整成公有成员
不过也可以直接用struct定义这个类,毕竟struct定义的类的访问限定符默认就是public

template<class T>
struct greater
{
    bool operator()(const T& a, const T& b)
    {
        return a > b;
    }
};

在这里插入图片描述
其实也可以直接传匿名对象,省下起名字了
在这里插入图片描述

3.函数指针的使用

1.函数指针的用处

可见仿函数是非常多功能的,那么它的用处是什么呢?
为什么C++创始人要设计仿函数这一语法呢?
仿函数是为了替代C语言当中的函数指针而出现的

我们知道函数指针是用来完成回调的,例如C语言库中的qsort函数
关于回调函数大家可以看我的这篇博客:征服C语言指针系列(3)
在这里插入图片描述
这里的比较规则就是由cmp这个函数指针来完成的

在学习堆的时候,我们曾经借助于函数指针来完成回调函数,实现无需修改具体函数的实现细节来完成大小堆的切换
数据结构-堆的实现及应用(堆排序和TOP-K问题)
在这里插入图片描述

2.利用函数指针完成回调

下面我们来演示一下使用函数指针完成回调

//返回a是否小于b
bool less1(int a, int b)
{
	return a < b;
}

class A
{
public:
	A(bool (*p)(int,int))
		:_p(p)
	{}

	//返回两个数中更小的那个数
	int smaller(int left, int right)
	{
		if (_p(left, right)) return left;
		else return right;
	}

private:
	bool (*_p)(int, int);
};

int main()
{
	bool (*ptr)(int, int) = less1;
	A aa(ptr);
	cout << aa.smaller(1, 7) << endl;
	cout << aa.smaller(2, 5) << endl;
	return 0;
}

在这里插入图片描述
需要注意的是:

  1. 因为类A在回调less1这个函数时只能在类的成员函数进行
    而且可能类A的很多成员函数都需要回调less1这个函数,因此在类A当中增加了一个函数指针类型的成员变量,这个函数指针的参数类型和顺序以及返回值都需要跟less1这个函数一样

2.上面那个代码只能完成int和int的比较功能,无法完成string和string等等诸多类型的比较
并不符合泛型编程的思想

3.less1这个函数比较简单,因此这个函数指针并不复杂,可是那些很复杂的函数和类,如果使用函数指针的话…结果就让人很难受了

3.利用仿函数完成回调

下面我们来演示一下仿函数完成回调

template<class T>
class Less
{
public:
	bool operator()(const T& a, const T& b)
	{
		return a < b;
	}
};

template <class T,class Compare>
class A
{
public:
	//返回两个元素中更小的那个元素
	const T& smaller(const T& left, const T& right)
	{
		if (_cmp(left, right)) return left;
		else return right;
	}
private:
	Compare _cmp;
};

int main()
{
	//注意:这里要往类模板的参数列表中传入实参
	//应该传入类型,而不是对象!!
	A<string, Less<string>> aa;
	cout << aa.smaller("abc", "wzs") << endl;
	A<int, Less<int>> ab;
	cout << ab.smaller(1, 8) << endl;
	return 0;
}

在这里插入图片描述
这样就既符合泛型编程的思想,使用起来也非常的好用了

4.仿函数的玩法

当然,仿函数的玩法是很多的,

1.取出Key/Key-Value模型中的Key

比如下面的这个例子:
这是取出一个键或者键值对当中的键
我们之前学过的二叉搜索树当中的Key模型和Key-Value模型就可以这样玩
这里是通过函数重载和类模板的缺省参数完成的
在这里插入图片描述

2.自定义排序

我们要实现一个比较算法,对不同的商品按照价格分别升序和降序排序

struct Goods
{
    string _name;//名称
    double _price;//价格
    int _evaluate;//评价
    Goods(const char* str, double price, int evaluate)
        :_name(str)
        , _price(price)
        , _evaluate(evaluate)
    {}
};

//按照价格升序
struct ComparePriceLess
{
    bool operator()(const Goods& left, const Goods& right)
    {
        return left._price < right._price;
    }
};

//按照价格降序
struct ComparePriceGreater
{
    bool operator()(const Goods& left, const Goods& right)
    {
        return left._price > right._price;
    }
};

int main()
{
    vector<Goods> v = { { "苹果", 2.5, 5 }, { "香蕉", 3.2, 4 }, { "橙子", 2.9, 3 }, { "菠萝", 1.5, 4 } };
    sort(v.begin(),v.end(), ComparePriceLess());
    for (auto& e : v)
    {
        cout << "商品名称: " << e._name << " 价格 :" << e._price << " 评价:" << e._evaluate << endl;
    }
    cout << endl;
    sort(v.begin(), v.end(), ComparePriceGreater());
    for (auto& e : v)
    {
        cout << "商品名称: " << e._name << " 价格 :" << e._price << " 评价:" << e._evaluate << endl;
    }
    cout << endl;
    return 0;
}

在这里插入图片描述
这样就可以按照我们想要的方式自定义排序规则进行排序了
当然,仿函数也有一个缺点:使用仿函数完成回调必须要定义出一个类来,有点大材小用的感觉
因此我们以后会介绍一个C++11新增的语法:lambda表达式,它可以在这种情况下替代仿函数

四.利用容器适配器和仿函数实现优先级队列

优先级队列其实就是堆,
关于堆的知识,实现,应用,大家可以看我的这篇博客,里面有详细的介绍:数据结构-堆的实现及应用(堆排序和TOP-K问题)
头文件是<queue>
在这里插入图片描述
它也可以用容器适配器来实现
默认是大堆,要想实现小堆的话:第三个参数仿函数传入greater类

容器适配器:vector可以,deque也可以,库里面是vector
因为要能够支持下标随机访问(也就是operator[]),而且vector的operator[]的速度远高于deque

#pragma once
//priority_queue的头文件是queue
//priority_queue默认是大堆
//要想实现小堆的话:第三个参数仿函数传入greator类
//容器适配器:vector可以,deque也可以,库里面是vector
//大堆:父亲大于孩子
//小堆:父亲小于孩子
namespace wzs
{
    template <class T, class Container = vector<T>, class Compare = less<T> >
    class priority_queue
    {
    public:
        //使用编译器默认生成的默认成员函数即可
        priority_queue() = default;//C++11新语法:强制生成默认构造
        template <class InputIterator>
		//迭代器区间构造
        priority_queue(InputIterator first, InputIterator last)
            :_con(first, last)
        {
            //先调一下迭代器区间构造,构造适配器对象_con
            //然后建堆即可
            //注意:向上调整算法建堆的时间复杂度O(N*logN)
            //向下调整算法建堆的时间复杂度O(N)
            //因此这里向下建堆
            for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
            {
                adjust_down(i);
            }
        }

        bool empty() const
        {
            return _con.empty();
        }

        size_t size() const
        {
            return _con.size();
        }

        const T& top() const
        {
            return _con.front();
        }

        T& top()
        {
            return _con.front();
        }

        //向上调整算法
        void adjust_up(int child)
        {
            int parent = (child - 1) / 2;
            while (child > 0)
            {
                if (_cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                {
                    break;
                }
            }
        }

        void push(const T& x)
        {
            //先插入数据,然后向上调整
            _con.push_back(x);
            adjust_up(_con.size() - 1);
        }

        //向下调整算法
        void adjust_down(int parent)
        {
            int child = 2 * parent + 1;//默认跟左孩子比较
            int n = _con.size();
            while (child < n)
            {
                //实际要跟右孩子比较
                if (child + 1 < n && _cmp(_con[child], _con[child + 1]))
                {
                    child++;
                }
                if (_cmp(_con[parent], _con[child]))
                {
                    swap(_con[parent], _con[child]);
                    parent = child;
                    child = 2 * parent + 1;
                }
                else
                {
                    break;
                }
            }
        }

        void pop()
        {
            //先交换第一个和最后一个数据
            swap(_con[0], _con[_con.size() - 1]);
            //然后删除最后一个数据
            _con.pop_back();
            //最后向下调整
            adjust_down(0);
        }

    private:

        Container _con;

        Compare _cmp;

    };
    //仿函数greater
    template<class T>
    struct greater
    {
        bool operator()(const T& a, const T& b)
        {
            return a > b;
        }
    };
};

注意:
建小堆传入仿函数时:
因为优先级队列的类模板中规定仿函数传入类
因此不能传入对象,而且缺省参数也不支持跳着传

priority_queue<int, greater<int>> heap;//err:仿函数是第三个参数,只有在第二个参数传了之后才能传第3个参数
priority_queue<int,vector<int>, greater<int>()> heap;//err:仿函数是类模板,必须传入类型,不能传入对象
priority_queue<int, vector<int>, greater<int>> heap;//yes,正确的传法

在这里插入图片描述

五.利用正向迭代器作为适配器实现反向迭代器

下面我们来通过适配器的知识借助vector和list的正向迭代器实现它们的反向迭代器

首先要说明的是,反向迭代器是这么使用的
会反向打印这个容器中的数据
这里以vector为例,对于其他支持迭代器的容器来说也是这样的
在这里插入图片描述

1.STL库里面的实现逻辑

1.rbegin和rend的实现

在这里插入图片描述

2.反向迭代器的实现

在这里插入图片描述

3.画图模拟反向迭代器具体的遍历流程

1.vector

在这里插入图片描述

2.list

在这里插入图片描述
可见STL大佬的实现体现出了一种对称美(rbegin就是end,rend就是begin)
下面我们就来实现一下

4.具体实现

// 适配器 -- 复用
template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{
	typedef Reverse_iterator<Iterator, Ref, Ptr> Self;
	//构造函数
	Reverse_iterator(Iterator it)
		:_it(it)
	{}

	Iterator _it;
	Ref operator*()
	{
		Iterator tmp(_it);
		return *(--tmp);
	}
	Ptr operator->()
	{
		return &(operator*());
	}

	//前置++
	Self& operator++()
	{
		--_it;
		return *this;
	}

	//前置--
	Self& operator--()
	{
		++_it;
		return *this;
	}

	//后置++
	Self& operator++(int)
	{
		Self tmp(*this);
		--_it;
		return tmp;
	}

	//后置--
	Self& operator--(int)
	{
		Self tmp(*this);
		++_it;
		return tmp;
	}

	bool operator==(const Self& s)
	{
		return _it == s._it;
	}
	bool operator!=(const Self& s)
	{
		return _it != s._it;
	}
};

5.对于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 Reverse_iterator<iterator, T&, T*> reverse_iterator;


	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);
	}

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

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

	//其他成员....无需改动
}

6.对于vector的适用

template<class T>
class vector
{
public:
	typedef T* iterator;
	typedef const T* const_iterator;
	typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;

	/
	// 迭代器相关
	iterator begin()
	{
		return _start;
	}

	iterator end()
	{
		return _finish;
	}

	const_iterator begin() const
	{
		return _start;
	}

	const_iterator end() const
	{
		return _finish;
	}

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

	reverse_iterator rend()
	{
		return reverse_iterator(begin());
	}
	其他成员.... 无需改动

7.const_reverse_iterator的实现

关于const_reverse_iterator的实现,我们需要实现支持使用普通的reverse_iterator来构造const_reverse_iterator
因此我们需要增加一个模板参数T

template<class T,class Iterator,class Ref,class Ptr>
struct Reverse_iterator
{
	typedef Reverse_iterator<T, Iterator, Ref, Ptr> Self;
	typedef Reverse_iterator<T, Iterator, T&, T*> reverse_iterator;
	
	Iterator cur;
	Reverse_iterator(Iterator it)
		:cur(it)
	{}

	//支持reverse_iterator向const_reverse_iterator的构造
	Reverse_iterator(const reverse_iterator& it)
		:cur(it.cur)
	{}

	//运算符重载都是一样的
};

因为const迭代器中const保护迭代器指向的内容不被修改的功能是由解引用操作的返回值类型即Ref和Ptr所决定的,
因此可以在list和vector当中这么定义const_reverse_iterator
这份代码在list和vector当中都是一样的

typedef Reverse_iterator<T, iterator,const T&,const T*> const_reverse_iterator;

const_reverse_iterator rbegin() const
{
	return const_reverse_iterator(end());
}

const_reverse_iterator rend() const
{
	return const_reverse_iterator(begin());
}

8.验证

1.list

class AA
{
public:
	AA(int a = 1,int b = 2)
		:_a(a)
		,_b(b)
	{}
	int _a;
	int _b;
};

void TestReverseIterator()
{
	list<int> lt;
	int a[] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto& e : a)
	{
		lt.push_back(e);
	}
	list<int>::reverse_iterator it = lt.rbegin();
	while (it != lt.rend())
	{
		*it -= 5;//可以修改
		cout << *it << " ";
		++it;
	}
	cout<<endl;
	list<AA> lt2;
	for (auto& e : a)
	{
		lt2.push_back(AA(e,e));
	}
	list<AA>::const_reverse_iterator it2 = lt2.rbegin();
	while (it2 != lt2.rend())
	{
		//it2->_b -= 2;//不可修改
		cout << it2->_a << ":" << it2->_b << endl;
		++it2;
	}

}

在这里插入图片描述
验证成功

2.vector

void TestReverseIterator2()
{
	vector<int> v;
	int a[] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto& e : a)
	{
		v.push_back(e);
	}
	vector<int>::reverse_iterator it = v.rbegin();
	while (it != v.rend())
	{
		*it -= 5;//可以修改
		cout << *it << " ";
		++it;
	}
	cout<<endl;
	vector<AA> v2;
	for (auto& e : a)
	{
		v2.push_back(AA(e,e));
	}
	vector<AA>::const_reverse_iterator it2 = v2.rbegin();
	while (it2 != v2.rend())
	{
		//it2->_b -= 2;//不可修改
		cout << it2->_a << ":" << it2->_b << endl;
		++it2;
	}
}

在这里插入图片描述
验证成功

六.deque的介绍

deque:双端队列,名字叫做双端队列,但是跟队列没有任何关系
在这里插入图片描述

七.deque的底层原理

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的
deque的底层是一个指针数组
deque为了维护其“整体连续”以及随机访问的假象,所以它的迭代器就比较复杂了
在这里插入图片描述
在这里插入图片描述

通过保证每一个tmp数组的大小都是一样的,这样就能实现O(1)的operator[]了,

假设每个tmp数组的大小都是n,要查找下标为pos的元素 那么就是第pos/n个tmp数组的第pos%n个元素

对于deque来说我们了解即可,因为deque无法取代vector和list
实际并不常用

以上就是C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层的全部内容,希望能对大家有所帮助!

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

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

相关文章

docker 体验怀旧游戏(魂斗罗等)

docker run --restart always -p 8081:80 --name fc-games -d registry.cn-hangzhou.aliyuncs.com/bystart/fc-games:latest ip:8081访问 jsnes: js制作了一个网页版的NES模拟&#xff0c;可以在网页上玩fc游戏 (gitee.com)

创建第一个 Spring 项目(IDEA社区版)

文章目录 创建 Spring 项目创建一个普通的 Maven 项目添加 Spring 依赖IDEA更换国内源 运行第一个 Spring 项目新建启动类存储 Bean 对象将Bean注册到Spring 获取并使用 Bean 对象 创建 Spring 项目 创建一个普通的 Maven 项目 首先创建一个普通的 Maven 项目 添加 Spring 依…

Tomcat好帮手---JDK

目录 1、Tomcat好帮手---JDK 2、安装JDK 部署Tomcat参考博主博客 部署TOMCAT详解-CSDN博客 1、Tomcat好帮手---JDK JDK是 Java 语言的软件开发工具包&#xff0c;JDK是整个java开发的核心&#xff0c;它包含了JAVA的运行环境&#xff08;JVMJava系统类库&#xff09;和JAVA…

2024年新提出的算法:一种新的基于数学的优化算法——牛顿-拉夫森优化算法|Newton-Raphson-based optimizer,NRBO

1、简介 开发了一种新的元启发式算法——Newton-Raphson-Based优化器&#xff08;NRBO&#xff09;。NRBO受到Newton-Raphson方法的启发&#xff0c;它使用两个规则&#xff1a;Newton-Raphson搜索规则&#xff08;NRSR&#xff09;和Trap Avoidance算子&#xff08;TAO&#…

视频压缩怎么才能保持画质清晰?这样设置参数~

很多时候我们都需要压缩视频&#xff0c;但在减小视频大小的时候我们也会担心画质清晰度问题&#xff0c;那怎么既能压缩视频大小&#xff0c;又能保证视频清晰度呢&#xff1f;下面就来了解下吧~ 视频压缩分为无损压缩和有损压缩&#xff0c;如果想保持画质清晰&#xff0c;可…

[C#]winform部署yolov5实例分割模型onnx

【官方框架地址】 https://github.com/ultralytics/yolov5 【算法介绍】 YOLOv5实例分割是目标检测算法的一个变种&#xff0c;主要用于识别和分割图像中的多个物体。它是在YOLOv5的基础上&#xff0c;通过添加一个实例分割模块来实现的。 在实例分割中&#xff0c;算法不仅…

spring-boot redis stream消息队列demo-及死信简单处理

Redis stream 是 Redis 5 引入的一种新的数据结构&#xff0c;它是一个高性能、高可靠性的消息队列&#xff0c;主要用于异步消息处理和流式数据处理。在此之前&#xff0c;想要使用 Redis 实现消息队列&#xff0c;通常可以使用例如&#xff1a;列表&#xff0c;有序集合、发布…

RedisInsight详细安装教程

简介 RedisInsight 是一个直观高效的 Redis GUI 管理工具&#xff0c;它可以对 Redis 的内存、连接数、命中率以及正常运行时间进行监控&#xff0c;并且可以在界面上使用 CLI 和连接的 Redis 进行交互&#xff08;RedisInsight 内置对 Redis 模块支持&#xff09;。 RedisIn…

用navigator.sendBeacon完成网页埋点异步请求记录用户行为,当网页关闭的时候,依然后完美完成接口请求,不会因为浏览器关闭了被中断请求。

代码用例 <template><div :class"$options.name"><el-button type"primary" click"sendBeacon">navigator.sendBeacon 请求埋点接口 发送json对象数据</el-button></div> </template><script> expor…

JVM系列-7内存调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

TensorFlow2实战-系列教程3:猫狗识别1

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 1、项目介绍 数据预处理&#xff1a;图像数据处理&#xff0c;准备训练和验证数据集卷…

无人值守变电所运维在海南市某住宅区的应用

1 前言 随着国家电网改革政策的逐步推进和落实&#xff0c;AcrelCloud-1000变电所运维云平台运用互联网和大数据技术&#xff0c;为电力运维公司提供变电所运维云平台。该平台作为连接运维单位和用电企业的纽带&#xff0c;监视用户配电系统的运行状态和电量数据&#xff0c;为…

HCIA学习第二天OSI七层协议与网络协议_操纵网络设备

第一天总结&#xff1a; 对等网——网络变大——无限的传输距离 无冲突 单播 为满足以上问题&#xff0c;出现了--网桥--紧接着出现了交换机——介质访问控制层&#xff08;二层设备&#xff09;——识别MAC地址 &#xff08;认识有记录-单播 不认识无记录-泛洪&#xff08;泛…

【java面试】Spring

目录 1. Spring 介绍1.1 Spring 的优点1.2 Spring 的缺点1.3 详细讲解一下核心容器&#xff08;spring context应用上下文) 模块 2. Spring俩大核心概念IOC&#xff0c;Inversion of Control&#xff0c;控制反转AOP(Aspect-OrientedProgramming)&#xff0c;面向切面编程Sprin…

如何实现高效一键群发1000人?

对于职场人来说&#xff0c;微信里的客户越多&#xff0c;成交的概率越大。但客户太多&#xff0c;群发是个难题&#xff0c;因为微信本身的群发是有数量限制的。 我们都知道&#xff0c;群发消息可以帮助我们&#xff1a; 1. 高效传递信息&#xff1a;群发短信的方式能够迅速…

Vue<圆形旋转菜单栏效果>

效果图: 大家不一定非要制成菜单栏,可以看下人家的华丽效果😝,参考地址 https://travelshift.com/ 大佬写的效果可比我的强多了,但是无从下手,所以就自己琢磨怎么写了,只能说效果勉强差不多 可以通过更改data值和注释我标注的css样式处部分,就可以实现全圆的效果😄…

vue3 + antd 封装动态表单组件(二)

传送带&#xff1a; vue3 antd 封装动态表单组件&#xff08;一&#xff09; 前置条件&#xff1a; vue版本 v3.3.11 ant-design-vue版本 v4.1.1 vue3 antd 封装动态表单组件&#xff08;一&#xff09;是基础版本&#xff0c;但是并不好用&#xff0c; 因为需要配置很多表…

echarts + gauge + 半圆效果

请注意以下配置需要echarts 5.0.0以上版本&#xff0c;4是不行的 option {series: [{center: [50%, 80%],type: gauge,startAngle: 180,endAngle: 0,min: 0,max: 150,axisTick: {show: false},splitLine: {show: false},detail: {color: #3096fe,offsetCenter: [0, -10],form…

Docker部署Stable-Diffusion-webui

前排提示&#xff1a;如果不想折腾&#xff0c;可直接跳到最后获取封装好的容器&#xff0c;一键运行 :D 前言 乘上AI生成的快车&#xff0c;一同看看沿途的风景。 启一个miniconda容器 docker run -itd -v 宿主机内SD项目路径:/tmp --gpus all --ipc host -p 7860:7860 con…

echarts柱状图添加白色柱状图背景+滚动+柱状顶部添加横线

echarts柱状图添加白色柱状图背景滚动 <template><div class"stream-water-wrapper"><div id"biologybgchart" class"bck-chart"></div><div id"biologychart" class"biology-chart"></…