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

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的介绍与底层的全部内容,希望能对大家有所帮助!

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

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

相关文章

CSS之粘性定位

让我为大家介绍一下粘性定位吧&#xff01; 大家应该都了解过绝对定位&#xff0c;它是相对于父级定位 那么粘性定位相对于谁呢&#xff1f; 它相对于overflow:hidden; 如果没找到就会跟fixed固定定位一样&#xff0c;相对于视口 <!DOCTYPE html> <html lang"en…

实习日志5

活字格图片上传功能&#xff08;批量&#xff09; 这个报错真的恶心&#xff0c;又看不了他服务器源码&#xff0c;接口文档又是错的 活字格V9获取图片失败bug&#xff0c;报错404-CSDN博客 代码BUG记录&#xff1a; 问题&#xff1a;上传多个文件的base64编码被最后一个文…

76 C++对象模型探索。多重继承中虚函数表分析

多重继承非重点内容&#xff0c;在实际开发中使用的不多&#xff0c; 这里只是为了知识点的完整&#xff0c;记录一下。 直接上结论。 一个类&#xff0c;如果继承于多个基类&#xff0c;且这个多个基类中有虚函数&#xff0c;那么 这个类 会有多个 虚函数表。 这个 类的对…

THM学习笔记——john

John the Ripper是目前最好的哈希破解工具之一。 John基本语法&#xff1a; john [options] [path to file] john&#xff1a;调用John the Ripper程序。 [path to file]&#xff1a;包含你要尝试破解的哈希的文件&#xff0c;如果它们在同一个目录中&#xff0c;你就不需要命名…

Docker容器基本管理

目录 一、概述 &#xff08;一&#xff09;为什么要用到容器 &#xff08;二&#xff09;docker概念 1.镜像 2.容器 3.仓库 &#xff08;三&#xff09;Docker与虚拟机的区别 &#xff08;四&#xff09;Linux namespace的六大类型 二、安装docker容器引擎 &#xff…

光耦驱动继电器电路图大全

光耦驱动继电器电路图&#xff08;一&#xff09; 注&#xff1a; 1U1-1脚可接12V&#xff0c;也可接5V&#xff0c;1U1导通&#xff0c;1Q1导通&#xff0c;1Q1-30V&#xff0c;线圈两端电压为11.7V. 1U1-1脚不接或接地&#xff0c;1U1不通&#xff0c;1Q1截止&#xff0c;1…

Federated Optimization in Heterogeneous Networks —— Fedprox算法

Federated Optimization in Heterogeneous Networks 1. 论文信息 论文题目: Federated Optimization in Heterogeneous Networks Fedprox算法&#xff0c;plato小项目跑通并理解作者&#xff1a;Tian Li, Anit Kumar Sahu, Manzil Zaheer, Maziar Sanjabi, Ameet Talwalkar, …

使用阿里云的oss对象存储服务实现图片上传(前端vue后端java详解)

一&#xff1a;前期准备&#xff1a; 1.1&#xff1a;注册阿里云账号&#xff0c;开启对象存储oss功能&#xff0c;创建一个bucket&#xff08;百度教程多的是&#xff0c;跟着创建一个就行&#xff0c;创建时注意存储类型是标准存储&#xff0c;读写权限是公共读&#xff09;…

HNU-编译原理-甘晴void学习感悟

前言 熬过煎熬的考试周、复习以及更加煎熬的等成绩&#xff0c;查到成绩的那一刻&#xff0c;心里还是挺开心的。 虽然我没有完全学懂这门课程&#xff0c;但我还是兢兢业业地通过了课程的考试&#xff0c;拿到了这门课程的认可。 记录一下自己对编译原理的学习感悟&#xf…

python使用pyinstaller 快速打包成一个exe程序方案

使用PyInstaller是一种将Python脚本打包成独立可执行文件&#xff08;.exe&#xff09;的方便方法。 以下是一个简单的步骤&#xff0c;以及相关的说明和代码示例&#xff1a; 1.安装PyInstaller: pip install pyinstaller2.在终端中导航到你的Python脚本所在的目录: cd pat…

day32_CSS

今日内容 0 复习昨日 1 css属性 2 盒子模型 【重点】 3 css扩展属性 4 Bootstrap【重点】 0 复习昨日 1 表格标签 table表格里面有tr , (行)行内有单元格,td行合并,rowspan列合并,colspan 2 写出input标签type属性的值 文本框 text 密码框 password 单选框 radio 复选框 checkb…

在线教育系统开发:构建现代化学习平台

随着科技的迅速发展&#xff0c;在线教育系统在教育领域扮演着越来越重要的角色。本文将深入探讨在线教育系统的开发过程&#xff0c;涉及关键技术和代码实现。 技术选型 在开始开发之前&#xff0c;我们首先需要选择适合在线教育系统的技术栈。以下是一些常见的技术选项&am…

使用宝塔面板部署Nuxt3项目到云服务器上

1、前期准备 1&#xff09;准备一台云服务器2&#xff09; 在云服务器上安装宝塔面板软件应用&#xff0c;安装步骤可参考博客:使用宝塔面板部署Node.jsMysql服务和Vue3-Admin项目到云服务器上 2、进行Nuxt3项目的部署 1)、本地执行打包命令&#xff0c;输出以下两个文件目录…

Android系统开发之TimeZoneDetectorService浅析--上

一&#xff1a;问题描述&#xff1a; 客户有一个关闭通话功能的需求&#xff0c;根据MTK的配置方法关闭了大概8个宏开关后&#xff0c;实现通话功能&#xff0c;但是导致插好sim卡开机后&#xff0c;时间和时区不能更新的问题。 二&#xff1a;问题分析&#xff1a; (1).MTK…

AF700 NHS 酯,AF 700 Succinimidyl Ester,一种明亮且具有光稳定性的近红外染料

AF700 NHS 酯&#xff0c;AF 700 Succinimidyl Ester&#xff0c;一种明亮且具有光稳定性的近红外染料&#xff0c;AF700-NHS-酯&#xff0c;具有水溶性和 pH 值不敏感性 您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;AF700 NHS 酯&#xff0c;AF 700 Succinimid…

深度视觉目标跟踪进展综述-论文笔记

中科大学报上的一篇综述&#xff0c;总结得很详细&#xff0c;整理了相关笔记。 1 引言 目标跟踪旨在基于初始帧中指定的感兴趣目标( 一般用矩形框表示) &#xff0c;在后续帧中对该目标进行持续的定位。 基于深度学习的跟踪算法&#xff0c;采用的框架包括相关滤波器、分类…

pcl+vtk(十四)vtkCamera相机简单介绍

一、vtkCamera相机 人眼相当于三维场景下的相机&#xff0c; VTK是用vtkCamera类来表示三维渲染场景中的相机。vtkCamera负责把三维场景投影到二维平面&#xff0c;如屏幕、图像等。 相机位置&#xff1a;即相机所在的位置&#xff0c;用方法vtkCamera::SetPosition()设置。 相…

力扣hot100 腐烂的橘子 BFS 矢量数组 满注释版

Problem: 994. 腐烂的橘子 文章目录 思路复杂度&#x1f49d; Code 思路 &#x1f468;‍&#x1f3eb; 参考 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) &#x1f49d; Code class Solution {int[] dx new int[] { 0, 1, 0, -1 };// 行 矢…

如何快速搭建实用的爬虫管理平台

目录 一、前言 二、选择合适的爬虫框架 三、搭建数据库 步骤1 步骤2 步骤3 四、搭建Web服务器 步骤1 步骤2 步骤3 步骤4 五、管理爬虫 六、总结 一、前言 爬虫是互联网数据采集的关键工具&#xff0c;但是随着数据量的增加和需求的多样化&#xff0c;手动运行和管…

SpringMVC-HttpMessageConverter 报文信息转化器

文章目录 HttpMessageConverter一、概念二、RequestBody三、RequestEntity四、 ResponseBody1.返回JSON格式的字符串 五、RestController六、ResponseEntity HttpMessageConverter 一、概念 报文信息转化器&#xff0c;将请求报文转化为Java对象&#xff0c;或将Java对象转化…