C++初阶编程:list容器的简单模拟实现

大家好啊,今天给大家带来的是我们C++编程中,stl库里的重要角色--list的简单的模拟实现,希望通过这篇小博客,对大家更加深入理解list容器有所帮助。

前言:

在C++标准库中,list是一种双向链表容器。

这里简单提一下双向链表——什么是双向链表呢?

双向链表是一种链式数据结构,其中每个节点包含三个部分:

  • 一个存储数据的字段。(我们通常用_data表示)
  • 一个指向前驱节点的指针。(我们通常用_prev表示)
  • 一个指向后继节点的指针。(我们通常用_next表示)

 这样,每个节点都知道它的前一个节点和后一个节点,从而支持在常数时间内进行插入和删除操作。

一:节点结构的定义

在实现list之前,我们要先定义一下这个链表的节点结构。一个链表是有多个节点链接组成,所以节点自然是重中之重。

我们在头文件定义一下节点结构,上文讲到,一个节点包括_data、_prev、_next三个部分:

template <class T>
struct ListNode
{ListNode(const T& data = T())//给的缺省值是我们想要存储的数据类型的一个匿名对象(自定义类型需要构造函数):_data(data), _next(nullptr), _prev(nullptr){}T _data;ListNode<T>* _next;//指向下一个节点ListNode<T>* _prev;//指向上一个节点
};

当然,也要记得写这个模板类的默认构造,我们用想存储的数据的一个匿名对象来完成对_data的初始化。 

二、list类的默认构造,成员变量

我们用_count来记录链表的节点数目,_head记录双向带头链表的头节点。

为了简写代码,方便我们操作,我们顺便把ListNode<T>重命名为Node。

随后书写list的默认构造函数,就是赋予头节点空间,将头节点的_prev与_next指向自己,还有把_count初始化为0。

template<class T>
class list
{typedef ListNode<T> Node;
public:list(){_head = new Node();_head->_next = _head;_head->_prev = _head;_count = 0;}
private:Node* _head;size_t _count;
};

三、list:用类实现迭代器的思想

在实现我们list的各种接口之前,我们首先要来实现一下list容器的迭代器。

这属于是list内容的重中之重,不同于vector,我们返回一个指针作为迭代器,指针的++就可以让迭代器向后移动到另一个元素。我们的list是由许多个节点链接而成,又怎么可以使用各种++操作符呢?

在这个基础上,我们想到了,可以是先用一个类,在这个类中重载各种++,--运算符,手动实现迭代器的向后移动(向前移动)。

那我们又如何实现const的迭代器呢?难不成学vector在前面加个const就可以了吗?

显而易见,由于底层结构的不同,const迭代器的实现原理也有所不同。

其实很简单,要想实现const迭代器的作用,我们只需要在迭代器类的各种内置函数的返回参数的类型做手脚就行。函数返回类型变成了const,自然就是const迭代器的作用。这样的代价就是我们要写两个迭代器模板。

但为了减少我们的麻烦,我们可以在写迭代器的时候在tmplete后面多加几个类型参数就行,这样就把我们的麻烦当做礼物送给了编译器(编译器:听我说,谢谢你)。

template<class T,class Ref,class Ptr>
struct ListIterator
{typedef ListNode<T> Node;//节点类型typedef ListIterator<T, Ref, Ptr> Self;//代表自己这个类型Node _node;ListIterator(Node node = nullptr)//缺省为nullptr的默认构造函数:_node(node){}ListIterator(const Self& l)//传一个迭代器类型(在实现后置++,后置--可以用得到):_node(l._node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;//Ptr是指针类型,模拟实现->时应该返回的是地址,即返回一个指向当前值的指针}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& l){return _node != l._node;}bool operator==(const Self& l){return _node == l._node;}
};

四、反向迭代器的实现

与我们刚刚实现正向迭代器一样的思想,反向迭代器也需要用模板类的思想来解决。

在实现反向迭代器的时候,我们核心仍然通过正向迭代器去运转,只不过在反向迭代器类中再次重载了各种操作符。例如,反向迭代器的前置++,我们只需要在实现的时候,在函数内调用正向迭代器的前置--就行。 

template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{typedef typedef Reverse_iterator Self;Iterator _it;Reverse_iterator(Iterator it):_it(it){}Ref operator*()//因为反向迭代器的首位置是由正向迭代器的end()初始化的,在最后一个元素的下一个位置,// 解引用时要先创建一个临时变量,使其向前移动一步,才是正确的返回位置(避免改变反向迭代器位置){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){Iterator tmp = _it;--tmp;return &(*tmp);}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& l){return _it != l._it;}bool operator==(const Self& l){return _it == l._it;}};

五、list迭代接口的实现

终于把list的迭代器给实现了,紧接着,我们就应该在list类里实现迭代器的各种接口。

先来重命名迭代器:

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

大家请看上面四行代码,我们通过传递的不同类型的参数类型,实例化出四种不同的迭代器,我们想使用const迭代器时就在重命名const_iterator时传递const T&,const T*就行。

	iterator begin(){return iterator(_head->_next);}const_iterator begin()const{return const_iterator(_head->_next);}reverse_iterator rbegin(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}

六、list插入函数以及删除函数的实现

list的插入主要是push_back,insert,push_front三个函数,删除操作主要是pop_back(),erase,pop_front三个函数。

//不涉及释放空间,不存在迭代器失效
// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val)
{Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;prev->_next = newnode;_count++;return iterator(newnode);//返回由Node类型的newnode初始化完成的匿名对象
}// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)//存在迭代器失效
{assert(pos != end());//防止把头节点给删了Node* node = pos._node;Node* pnext = node->_next;Node* prev = node->_prev;prev->_next = pnext;pnext->_prev = prev;delete node;_count--;return iterator(pnext);
}

随后,我们就可以让push_back()和push_front调用insert函数实现复用,让pop_back()和pop_front调用erase实现复用,减少我们所需要写的代码:

void push_back(const T& data))
{insert(end(), data);
}void pop_back()
{erase(--end());
}void push_front(const T& data))
{insert(begin(), data);
}void pop_front()
{erase(begin());
}

七、list各种默认函数的实现

我们需要实现各种其他构造函数,方便list类的各种构造,例如(int n, const T& value = T())//传n个元素,每个元素默认为T(),又或者是根据迭代器区间默认构造。
 我们不难想到,由于要实现这么多的构造函数,这么多的构造函数,如果在构造前都要现在函数里初始化一遍,破坏了封装性,所以我们可以把初始化这个功能写成一个新的函数,随后,在各种构造函数里调用就行:

void empty_init()
{_head = new Node();_head->_next = _head;_head->_prev = _head;_count = 0;
}list()//更改默认构造函数
{empty_init();
}

  各种构造函数实现:

list(int n, const T& value = T())
{empty_init();for (int i = 0; i < n; ++i){push_back(value);}
}template <class Iterator>//适应各个迭代器的构造
list(Iterator first, Iterator last)
{empty_init();while (first != last){push_back(*first);++first;}
}list(const list<T>& l)//拷贝构造
{empty_init();for (const auto& it : l){push_back(it);}
}list<T>& operator=(const list<T> l)//赋值重载
{swap(l);return *this;
}~list()
{clear();delete _head;_head = nullptr;
}

当然,在赋值重载中,我们仍然选择了现代写法,于是我们就要实现一个swap接口,在析构函数中,我们也选择用一个clear来删除除了头结点之外的所有节点,所以我们也需要实现一个clear:

void swap(list<T>& l)
{std::swap(_head, l._head);std::swap(_count, l._count);
}void clear(list<T>& l)
{auto it = begin();while (it != end()){it = erase(it);//小心迭代器失效}
}

八、其他接口的实现:

我们想要看这个链表多长,就需要调用我们的size接口,想知道最后或者第一个元素的值,也需要调用back(),front()等接口。

以下是该接口的实现:

	T& front(){assert(_count > 0);return _head->_next->_data;}const T& front()const{assert(_count > 0);return _head->_next->_data;}T& back(){assert(_count > 0);return _head->_prev->_data;}const T& back()const{assert(_count > 0);return _head->_prev->_data;}void push_back(const T& data){insert(end(), data);}void pop_back(){erase(--end());}void push_front(const T& data){insert(begin(), data);}void pop_front(){erase(begin());}

九、总代码

​
#pragma once
#include<assert.h>namespace bit
{template <class T>struct ListNode{ListNode(const T& data = T())//给的缺省值是我们想要存储的数据类型的一个匿名对象(自定义类型需要构造函数):_data(data), _next(nullptr), _prev(nullptr){}T _data;ListNode<T>* _next;//指向下一个节点ListNode<T>* _prev;//指向上一个节点};template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* Node;//节点类型typedef ListIterator<T, Ref, Ptr> Self;//代表自己这个类型Node _node;ListIterator(Node node = nullptr)//缺省为nullptr的默认构造函数:_node(node){}ListIterator(const Self& l)//传一个迭代器类型(在实现后置++,后置--可以用得到):_node(l._node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;//Ptr是指针类型,模拟实现->时应该返回的是地址,即返回一个指向当前值的指针}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& l){return _node != l._node;}bool operator==(const Self& l){return _node == l._node;}};template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator Self;Iterator _it;Reverse_iterator(Iterator it):_it(it){}Ref operator*()//因为反向迭代器的首位置是由正向迭代器的end()初始化的,在最后一个元素的下一个位置,// 解引用时要先创建一个临时变量,使其向前移动一步,才是正确的返回位置(避免改变反向迭代器位置){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){Iterator tmp = _it;--tmp;return &(*tmp);}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& l){return _it != l._it;}bool operator==(const Self& l){return _it == l._it;}};template<class T>
class list
{typedef ListNode<T> Node;
public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;void empty_init(){_head = new Node();_head->_next = _head;_head->_prev = _head;_count = 0;}list(){empty_init();}list(int n, const T& value = T()){empty_init();for (int i = 0; i < n; ++i){push_back(value);}}template <class Iterator>//适应各个迭代器的构造list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}list(const list<T>& l)//拷贝构造{empty_init();for (const auto& it : l){push_back(it);}}list<T>& operator=(const list<T> l)//赋值重载{swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}iterator begin(){return iterator(_head->_next);}const_iterator begin()const{return const_iterator(_head->_next);}reverse_iterator rbegin(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}size_t size()const{return _count;}bool empty()const{return _count == 0;}T& front(){assert(_count > 0);return _head->_next->_data;}const T& front()const{assert(_count > 0);return _head->_next->_data;}T& back(){assert(_count > 0);return _head->_prev->_data;}const T& back()const{assert(_count > 0);return _head->_prev->_data;}void push_back(const T& data){insert(end(), data);}void pop_back(){erase(--end());}void push_front(const T& data){insert(begin(), data);}void pop_front(){erase(begin());}//不涉及释放空间,不存在迭代器失效// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;prev->_next = newnode;_count++;return iterator(newnode);//返回由Node类型的newnode初始化完成的匿名对象}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos)//存在迭代器失效{assert(pos != end());//防止把头节点给删了Node* node = pos._node;Node* pnext = node->_next;Node* prev = node->_prev;prev->_next = pnext;pnext->_prev = prev;delete node;_count--;return iterator(pnext);}void swap(list<T>& l){std::swap(_head, l._head);std::swap(_count, l._count);}void clear(){auto it = begin();while (it != end()){it = erase(it);}}private:Node* _head;size_t _count;};
}#pragma once
#include<assert.h>namespace bit
{template <class T>struct ListNode{ListNode(const T& data = T())//给的缺省值是我们想要存储的数据类型的一个匿名对象(自定义类型需要构造函数):_data(data), _next(nullptr), _prev(nullptr){}T _data;ListNode<T>* _next;//指向下一个节点ListNode<T>* _prev;//指向上一个节点};template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* Node;//节点类型typedef ListIterator<T, Ref, Ptr> Self;//代表自己这个类型Node _node;ListIterator(Node node = nullptr)//缺省为nullptr的默认构造函数:_node(node){}ListIterator(const Self& l)//传一个迭代器类型(在实现后置++,后置--可以用得到):_node(l._node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;//Ptr是指针类型,模拟实现->时应该返回的是地址,即返回一个指向当前值的指针}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& l){return _node != l._node;}bool operator==(const Self& l){return _node == l._node;}};template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator Self;Iterator _it;Reverse_iterator(Iterator it):_it(it){}Ref operator*()//因为反向迭代器的首位置是由正向迭代器的end()初始化的,在最后一个元素的下一个位置,// 解引用时要先创建一个临时变量,使其向前移动一步,才是正确的返回位置(避免改变反向迭代器位置){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){Iterator tmp = _it;--tmp;return &(*tmp);}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& l){return _it != l._it;}bool operator==(const Self& l){return _it == l._it;}};template<class T>
class list
{typedef ListNode<T> Node;
public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;void empty_init(){_head = new Node();_head->_next = _head;_head->_prev = _head;_count = 0;}list(){empty_init();}list(int n, const T& value = T()){empty_init();for (int i = 0; i < n; ++i){push_back(value);}}template <class Iterator>//适应各个迭代器的构造list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}list(const list<T>& l)//拷贝构造{empty_init();for (const auto& it : l){push_back(it);}}list<T>& operator=(const list<T> l)//赋值重载{swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}iterator begin(){return iterator(_head->_next);}const_iterator begin()const{return const_iterator(_head->_next);}reverse_iterator rbegin(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}size_t size()const{return _count;}bool empty()const{return _count == 0;}T& front(){assert(_count > 0);return _head->_next->_data;}const T& front()const{assert(_count > 0);return _head->_next->_data;}T& back(){assert(_count > 0);return _head->_prev->_data;}const T& back()const{assert(_count > 0);return _head->_prev->_data;}void push_back(const T& data){insert(end(), data);}void pop_back(){erase(--end());}void push_front(const T& data){insert(begin(), data);}void pop_front(){erase(begin());}//不涉及释放空间,不存在迭代器失效// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;prev->_next = newnode;_count++;return iterator(newnode);//返回由Node类型的newnode初始化完成的匿名对象}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos)//存在迭代器失效{assert(pos != end());//防止把头节点给删了Node* node = pos._node;Node* pnext = node->_next;Node* prev = node->_prev;prev->_next = pnext;pnext->_prev = prev;delete node;_count--;return iterator(pnext);}void swap(list<T>& l){std::swap(_head, l._head);std::swap(_count, l._count);}void clear(){auto it = begin();while (it != end()){it = erase(it);}}private:Node* _head;size_t _count;};
}​

十、总结:

本文实现了一个简化版的双向链表模板类 list,主要包括以下内容:

  1. ListNode 结构体

    • 表示链表的节点,包含数据 _data 和指向前一个节点 _prev、后一个节点 _next 的指针。
  2. ListIterator 结构体

    • 实现了链表的迭代器,支持前向和后向遍历,以及解引用操作符 * 和箭头操作符 ->
  3. list 类

    • 使用 ListNode 实现了双向链表的基本操作,包括插入、删除、遍历等功能。
    • 提供了正向迭代器 iterator 和反向迭代器 reverse_iterator
  4. 功能实现

    • 支持构造函数、拷贝构造函数和赋值运算符重载。
    • 实现了 begin()end()rbegin()rend() 等方法,用于迭代器的初始化和操作。
    • 提供了 push_back()pop_back()push_front()pop_front() 等方法,支持双向链表的节点插入和删除。
    • 包含 size()empty()front()back() 等方法,用于获取链表大小和访问首尾元素。

通过这些实现,希望大家可以更加深入理解了双向链表的底层实现原理,并且掌握如何使用迭代器来操作链表元素等方法。

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

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

相关文章

C#基于SkiaSharp实现印章管理(3)

本系列第一篇文章中创建的基本框架限定了印章形状为矩形&#xff0c;但常用的印章有方形、圆形等多种形状&#xff0c;本文调整程序以支持定义并显示矩形、圆角矩形、圆形、椭圆等4种形式的印章背景形状。   定义印章背景形状枚举类型&#xff0c;矩形、圆形、椭圆相关的尺寸…

mathcup大数据竞赛论文中集成学习(或模型融合)的运用分析

ps: (模型融合和集成学习是两个紧密相关但又有所区别的概念。集成学习是一种更广泛的范式&#xff0c;而模型融合可以被视为集成学习的一种特殊形式或策略。) 1.集成学习原理 图1 如图1所示&#xff0c;集成学习是一种通过结合多个机器学习模型的预测来提高整体性能的策略。其…

全国今日油价查询-全国今日油价查询接口-API接口

关于油价的信息&#xff0c;以下是详细的分点表示和归纳&#xff1a; 最新油价调整&#xff1a; 时间&#xff1a;2024年6月28日0时 调整内容&#xff1a;汽油价格上调210元/吨&#xff0c;柴油价格上调200元/吨。 涨幅&#xff1a;加油站油价上涨0.16元/升-0.20元/升。 具体油…

20240629在NanoPi R6C开发板的预编译的Android12下使用iperf3测试网速

20240629在NanoPi R6C开发板的预编译的Android12下使用iperf3测试网速 2024/6/29 11:11 【表扬一下】友善之臂没有提供update.img的预编译固件&#xff0c;我心里一凉&#xff0c;这么多IMG文件&#xff0c;得一个一个选择呀&#xff01; 但是别人友善之臂特别急人之所急&#…

6.27-6.29 旧c语言

#include<stdio.h> struct stu {int num;float score;struct stu *next; }; void main() {struct stu a,b,c,*head;//静态链表a.num 1;a.score 10;b.num 2;b.score 20;c.num 3;c.score 30;head &a;a.next &b;b.next &c;do{printf("%d,%5.1f\n&…

Flink 从入门到放弃

0 写在前面 程序员闯荡江湖的一生都在与数据打交道&#xff0c;初入江湖时基于 MySQL 的 CRUD&#xff0c;渐入佳境后利用 Redis 实现查询加速及分布式控制&#xff0c;本质上都是数据处理&#xff1b;无论主动/被动&#xff0c;都在利用数据来达成业务/技术目的。自然而然的&a…

javaSE知识点整理总结(下)、MySQL数据库

目录 一、异常 1.常见异常类型 2.异常体系结构 3.异常处理 &#xff08;1&#xff09;finally &#xff08;2&#xff09;throws 二、JDBC 1.JDBC搭建 2.执行SQL语句两种方法 三、MySQL数据库 1.ddl 2.dml 3.dql &#xff08;1&#xff09;字符函数 &#xff08;…

Linux开发讲课22---I2C读写 EEPROM 实验(含代码)

EEPROM 是一种掉电后数据不丢失的存储器&#xff0c;常用来存储一些配置信息&#xff0c;以便系统重新上电的时候加载之。 EEPOM 芯片最常用的通讯方式就是 I2C 协议&#xff0c;本小节以 EEPROM的读写实 验为大家讲解 STM32 的 I2C 使用方法。实验中 STM32 的 I2C 外设采用主模…

防止它人代码调试?分享 1 段优质 JS 代码片段!

大家好&#xff0c;我是大澈&#xff01; 本文约 600 字&#xff0c;整篇阅读约需 1 分钟。 每日分享一段优质代码片段。 今天分享一段 JS 代码片段&#xff0c;是防止代码被调试或篡改的基础。 老规矩&#xff0c;先阅读代码片段并思考&#xff0c;再看代码解析再思考&#…

如何轻松解决复杂文档格式转换问题

上周&#xff0c;我遇到了一个棘手的问题&#xff1a;需要将一大堆PDF文件转换成可编辑的Word文档&#xff0c;时间紧迫&#xff0c;手动转换根本来不及。朋友推荐我使用了一个网站——xuelin.cc&#xff0c;这个网站不仅提供强大的AI对话功能&#xff0c;还能轻松完成各种文档…

Hadoop3:Yarn框架的三种调度算法

一、概述 目前&#xff0c;Hadoop作业调度器主要有三种&#xff1a;FIFO、容量&#xff08;Capacity Scheduler&#xff09;和公平&#xff08;Fair Scheduler&#xff09;。Apache Hadoop3.1.3默认的资源调度器是Capacity Scheduler。 CDH框架默认调度器是Fair Scheduler。 …

改机软件有哪些?实现一键新机、改串号、改IMEI和手机参数的需求 硬改手机软件,新机环境模拟 设备伪装,一键改机,一键复原

这次针对可以直接开端口修改参数的机型做一些工具解析 前面接触合作过很多工作室。其中很多工作室对于各自软件的跳验证有各自的需求。 一个机型各项参数一般有IMEI WiFi 蓝牙 sn psb ESN等等。 针对这些参数的修改首先要明白各自软件检测的具体是哪些参数来验证。 对于常用…

#HDC2024 心得分享#主题演讲学习-加入鸿蒙生态正当时

一、主题演讲学习心得 通过本次主题演讲的聆听与学习&#xff0c;我们在猜出中和不太确定的相关内容纷纷呈现。比如鸿蒙内核与HarmonyOS Next获得行业内最高等级的安全认证&#xff1b;盘古大模型、小艺智能体、意图理解与分发框架等构筑的AI、AIGC能力对HarmonyOS Next及原生…

MySQL高级-索引-使用规则-覆盖索引回表查询

文章目录 1、覆盖索引1.1、查看索引1.2、删除单列索引 idx_user_pro1.3、查询 profession软件工程 and age31 and status01.4、执行计划 profession软件工程 and age31 and status01.5、执行计划 select id,profession,age,status1.6、执行计划 select id,profession,age,statu…

Transformer教程之多头自注意力机制

大家好&#xff0c;今天我们要聊一聊Transformer中的一个核心组件——多头自注意力机制。无论你是AI领域的新手&#xff0c;还是深度学习的老鸟&#xff0c;这篇文章都会帮助你更深入地理解这个关键概念。我们会从基础开始&#xff0c;逐步深入&#xff0c;最终让你对多头自注意…

软考《信息系统运行管理员》-1.3信息系统运维的发展

1.3信息系统运维的发展 我国信息系统运维的发展总体现状 呈现三个“二八现象” 从时间周期看&#xff08;开发流程&#xff09;从信息系统效益看&#xff08;消息体现为“用好”&#xff09;从资金投入看&#xff08;重开发&#xff0c;轻服务&#xff09; 信息系统运维的发…

Codeforces Beta Round 32 (Div. 2, Codeforces format) D. Constellation 题解 枚举

Constellation 题目描述 A star map in Berland is a checked field n m nm nm squares. In each square there is or there is not a star. The favorite constellation of all Berland’s astronomers is the constellation of the Cross. This constellation can be for…

JAVA高级进阶13单元测试、反射、注解

第十三天、单元测试、反射、注解 单元测试 介绍 单元测试 就是针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试 咱们之前是如何进行单元测试的&#xff1f; 有啥问题 &#xff1f; 只能在main方法编写测试代码&#xff0c;去调用其他方法进行测试。 …

页面开发感想

页面开发 1、 前端预览 2、一些思路 2.1、首页自定义element-plus的走马灯 :deep(.el-carousel__arrow){border-radius: 0%;height: 10vh; }需要使用:deep(标签)才能修改样式 或者 ::v-deep 标签 2.2、整体设计思路 <template><div class"card" style&…

【ChatBI】text2sql-不需要访问数据表-超轻量Python库Vanna快速上手,对接oneapi

oneapi 准备 首先确保你有oneapi &#xff0c;然后申请 kimi的api 需要去Moonshot AI - 开放平台 然后添加一个api key 然后打开oneapi的渠道界面&#xff0c;添加kimi。 然后点击 测试&#xff0c; 如果能生成响应时间&#xff0c;就是配置正确。 然后创建令牌 http:…