【C++】list讲解及模拟

news2024/10/1 17:18:44

目录

list的基本介绍

list模拟实现

一.创建节点

二.迭代器

1.模版参数

2.迭代器的实现:

a. !=

b. ==

c. ++ --

d. *指针

e.&引用

整体iterator (与const复用):

三.功能实现

1.模版参数

2.具体功能实现:

2.1 构造函数

2.2 begin() && end()

2.3插入

insert任意位置插入

push_back 尾插&& push_front前插

2.4 删除

erase任意位置删除

pop_back 头删 && pop_front尾删

2.5 拷贝构造 && 赋值操作符

2.6 clear() && 析构函数

代码示例

Test.cpp

list.h


list的基本介绍

list本质上是一个带头双向循环链表,列表是一种用于存储一组元素的数据结构,元素按照插入的顺序排列。它允许动态地添加和删除元素,可以重复存储相同的值。列表提供了对元素的插入、删除、访问和遍历等常用操作。

列表是序列容器,允许在序列内的任何位置插入和擦除操作,并在两个方向上进行迭代。

列表容器被实现为双链接列表;双链接列表可以将它们所包含的每个元素存储在不同的和不相关的存储位置中。顺序通过与前面元素的链接和后面元素的链接的关联在内部保持。

与其他序列容器相比,列表和前向列表的主要缺点是它们无法通过位置直接访问元素; 例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,该位置之间的距离需要线性时间。它们还会消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大量小元素列表的一个重要因素)。

若要查看双向循环链表相关知识→:数据结构:线性表之-循环双向链表(万字详解)_数据结构循环双链表概念-CSDN博客

list模拟实现

一.创建节点

template <class T>//模版
struct list_node
{
    list_node<T> *_prev;//前一节点
    list_node<T> *_next;//后一节点
    T _data;
​
    // 构造函数,创建链表
    list_node(const T &x = T()) // 用匿名对象做缺省值(调用默认构造),以存储其他类型的元素
        : _next(nullptr), _prev(nullptr), _data(x)
    {}
};

二.迭代器

1.模版参数

template <class T, class Ref, class Ptr>
  1. class T:表示元素类型,为了应对要接收不同类型的数据

  2. class Ref:引用类型参数模版,Ref用于提供对迭代器所指向元素的引用

  3. class Ptr:指针类型参数模版,Ptr用于提供对迭代器所指向元素的指针。

后面会提到Ref,Ptr作用,请仔细阅读哦

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;//指向列表节点的指针,用于追踪迭代器的当前位置。
​
  //构造函数,接受一个指向列表节点的指针,并将其作为初始位置给 _node。
  __list_iterator(node *n)
      : _node(n)
  {}
};

这个结构体的作用是提供列表的迭代功能,它可以被用于遍历列表中的元素,并对元素进行访问和操作。

"const T&"表示迭代器所指向元素的引用类型,而"const T*"表示迭代器所指向元素的指针类型。 这样定义迭代器的目的是为了在const成员函数中使用该迭代器,并保证在遍历列表时不会修改列表中的元素"

参考:

list<int>::iterator it = lt.begin();
//__list_itreator后续被重命名为iterator
a. !=
bool operator!=(const self &s)
{
    return _node != s._node;
}
b. ==
bool operator==(const self &s)
{
    return _node == s._node;
}
c. ++ --
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;
}
d. *指针

重载了解引用运算符(*),返回 _node->_data 的引用,即迭代器所指向的元素

Ref &operator*()//加const不能修改数据
{
    return _node->_data;
}
e.&引用

重载了箭头运算符(->),返回 _node->_data 的指针,即迭代器所指向元素的指针

Ptr operator->()
{
    return &(_node->_data); // 取地址
}

Ref与Ptr的定义在class list中进行定义

整体iterator (与const复用):
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->()
    {
        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;
    }
};

三.功能实现

1.模版参数

    
template <class T>
class list
{
    typedef list_node<T> node;

public:
    //iterator和const_iterator都是公用接口
    typedef __list_iterator<T, T &, T *> iterator;
    typedef __list_iterator<T, const T &, const T *> const_iterator;

private:
    //头节点
    node *_head; // ListNode<T>是类型 , ListNode是类名
};

2.具体功能实现:

2.1 构造函数

为了后续操作的方便,将初始化链表代码写在另一个函数里

void empty_init()
{
    _head = new node;
    _head->_next = _head;
    _head->_prev = _head;
}
list()
{
    empty_init();
}
2.2 begin() && end()
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);
}

test:通过迭代器依次打印出元素

list<int>::iterator it = lt.begin();
while (it != lt.end())
{
    cout << *it << " ";
    ++it;
}
cout << endl;

我们将迭代器遍历封装到一个函数内:

void print_list(const list<T> &lt)
{
    cout << "---list---" << endl;
    // list<int>::const_iterator it = lt.begin();
    list<int>::const_iterator it = lt.begin();
    while (it != lt.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl
         << "---list---" << endl;
}
2.3插入
insert任意位置插入
void insert(iterator pos, const T &x)
{
    node *cur = pos._node;   // .访问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;
}
push_back 尾插&& push_front前插
void push_back(const T &x)
{
    insert(end(), x);
}
void push_front(const T &x)
{
    insert(begin(), x);
}

test:

void test_list3()
{
    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;
​
    it = lt.begin();
    list<int>::iterator pos = lt.begin();
    ++pos;
    lt.insert(pos, 20);
​
    lt.print_list(lt);
​
    cout << endl;
}
2.4 删除
erase任意位置删除
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);
}
pop_back 头删 && pop_front尾删
void pop_back()
{
    erase(--end());
}
void pop_front()
{
    erase(begin());
}

test:

void test_list4()
{
    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.print_list(lt);
    cout << endl;
    lt.push_back(100);
    lt.push_front(99);
    lt.print_list(lt);
    cout << endl;
​
    lt.pop_back();
    lt.pop_front();
    lt.print_list(lt);
    cout << endl;
}

2.5 拷贝构造 && 赋值操作符

swap交换函数:

void swap(list<T> &temp)
{
    std::swap(_head, temp._head);
}

当调用swap函数时[例子:lt2拷贝lt1调用swap时],调用拷贝构造将lt1进行拷贝再交换到lt2

list:

list(const list<T> &lt)
{
    empty_init();//创建头节点
    list<T> temp(lt.begin(), lt.end());
    swap(temp);
}

赋值操作数:

// lt3=lt2
// 不能使用&,而是传值调用拷贝构造,拷贝lt2,赋值给lt3
list<T> &operator=(const list<T> lt)//const list<T>& lt
{
    swap(lt);
    return *this;
}

test:

void test_list6()
{
    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.print_list(lt);
    cout << endl;
​
    // list<int> lt2(lt);
    // lt2.print_list(lt2);
    // cout << endl;
    list<int> lt2 = lt;
    lt2.print_list(lt2);
    lt.print_list(lt);
}

2.6 clear() && 析构函数

clear:清除头节点以外的数据

void clear()
{
    iterator it = begin();
    while (it != end())
        it = erase(it); // erase(it++);//后置++返回的是前一个的拷贝,不会失效
}

test:

void test_list5()
{
    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.print_list(lt);
    cout << endl;
​
    lt.clear();
    lt.push_back(20);
​
    lt.print_list(lt);
}

析构:

~list()
{
    clear();
    delete _head;
    _head = nullptr;
}

代码示例

Test.cpp

#include "list.h"

int main()
{
    wzf::test_list6();

    return 0;
}

list.h

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;

namespace wzf
{
    // 节点
    template <class T>
    struct list_node
    {
        list_node<T> *_prev;
        list_node<T> *_next;
        T _data;

        // 构造函数,创建链表
        list_node(const T &x = T()) // 用匿名对象做缺省值(调用默认构造),以存储收其他类型的元素
            : _next(nullptr), _prev(nullptr), _data(x)
        {
        }
    };

    // 迭代器
    // // 1.iterator
    // template <class T>
    // struct __list_iterator
    // {
    //     typedef list_node<T> node;
    //     typedef __list_iterator<T> self;
    //     node *_node;

    //     __list_iterator(node *n)
    //         : _node(n)
    //     {
    //     }

    //     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;
    //     }
    // };
    // // 2.const_iterator
    // 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*() // 与1区别的地方,加const不能修改数据
    //     {
    //         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 Ref>
    // struct __list_iterator
    // {
    //     typedef list_node<T> node;
    //     typedef __list_iterator<T,Ref> self;
    //     node *_node;

    //     __list_iterator(node *n)
    //         : _node(n)
    //     {
    //     }

    //     Ref &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 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->()
        {
            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;
        }
        /*
        "const T&"表示迭代器所指向元素的引用类型,
        而"const T*"表示迭代器所指向元素的指针类型。
        这样定义迭代器的目的是为了在const成员函数中
        使用该迭代器,并保证在遍历列表时不会修改列表中的元素
        */
    };
    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()
        {
            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);
        }

        void empty_init()
        {
            _head = new node;
            _head->_next = _head;
            _head->_prev = _head;
        }
        list()
        {
            empty_init();
        }

        // 构造函数, 迭代器区间
        template <class Iterator>
        list(const Iterator first, const Iterator last)
        {
            empty_init(); // 创建头节点
            for (Iterator it = first; it != last; ++it)
                push_back(*it);
        }

        void swap(list<T> &temp)
        {
            std::swap(_head, temp._head);
        }
        // 拷贝构造
        // lt2(lt1)
        // list(const list<T> &lt)
        // {
        //     empty_init();
        //     const_iterator it = lt.begin();
        //     while (it != lt.end())
        //     {
        //         push_back(*it);
        //         ++it;
        //     }
        // }
        list(const list<T> &lt)
        {
            empty_init();
            list<T> temp(lt.begin(), lt.end());
            swap(temp);
        }

        // 赋值操作符
        // lt3=lt2
        // 不能使用&,而是传值调用拷贝构造,拷贝lt2,赋值给lt3
        list<T> &operator=(const 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)
        // {
        //     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;
        // }
        void push_back(const T &x)
        {
            insert(end(), x);
        }
        void push_front(const T &x)
        {
            insert(begin(), x);
        }

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

        void print_list(const list<T> &lt)
        {
            cout << "---list---" << endl;
            // list<int>::const_iterator it = lt.begin();
            list<int>::const_iterator it = lt.begin();
            while (it != lt.end())
            {
                cout << *it << " ";
                ++it;
            }
            cout << endl
                 << "---list---" << endl;
        }

        void insert(iterator pos, const T &x)
        {
            node *cur = pos._node;   // .访问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);
        }
        /*
        在该函数的最后一行,返回了一个迭代器对象 `iterator(next)`。
        这是因为在 C++ STL 中,通常情况下,删除一个元素后,我们希望返回
        删除元素的下一个位置作为新的迭代器。直接返回 `next` 的话,可能会
        暴露内部实现细节,使得用户可以直接操作指针 `next`,可能导致潜在的问题。
        为了隐藏底层指针的细节,通常会将其封装在迭代器对象中返回。因此
        ,返回 `iterator(next)` 的方式可以提供更好的封装性和安全性,
        使用户能够使用迭代器对象来操作返回的下一个位置,而不需要直接访问底层的指针。
        这也符合 C++ STL 设计的一般原则,即通过迭代器提供统一的接口,隐藏底层的具体实现细节。
        */

    private:
        node *_head; // ListNode<T>是类型 , ListNode是类名
    };
    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;
        lt.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, 2));
        lt.push_back(AA(3, 4));
        lt.push_back(AA(5, 6));

        list<AA>::iterator it = lt.begin();
        while (it != lt.end())
        {
            cout << it->_a1 << " " << it._node->_data._a2 << endl;
            cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;
            cout << it.operator->() << endl
                 << endl; // 地址值
            ++it;
        }
    }

    void test_list3()
    {
        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;

        it = lt.begin();
        list<int>::iterator pos = lt.begin();
        ++pos;
        lt.insert(pos, 20);

        lt.print_list(lt);

        cout << endl;
    }

    void test_list4()
    {
        list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);
        lt.print_list(lt);
        cout << endl;
        lt.push_back(100);
        lt.push_front(99);
        lt.print_list(lt);
        cout << endl;

        lt.pop_back();
        lt.pop_front();
        lt.print_list(lt);
        cout << endl;
    }

    void test_list5()
    {
        list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);
        lt.print_list(lt);
        cout << endl;

        lt.clear();
        lt.push_back(20);

        lt.print_list(lt);
    }

    void test_list6()
    {
        list<int> lt;
        lt.push_back(1);
        lt.push_back(2);
        lt.push_back(3);
        lt.push_back(4);
        lt.print_list(lt);
        cout << endl;

        // list<int> lt2(lt);
        // lt2.print_list(lt2);
        // cout << endl;
        list<int> lt2 = lt;
        lt2.print_list(lt2);
        lt.print_list(lt);
    }
}

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

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

相关文章

第139期 做大还是做小-Oracle名称哪些事(20240125)

数据库管理139期 2024-01-25 第139期 做大还是做小-Oracle名称哪些事&#xff08;20240125&#xff09;1 问题2 排查3 扩展总结 第139期 做大还是做小-Oracle名称哪些事&#xff08;20240125&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&#xff09; Oracle A…

云计算中的弹性是什么?

云弹性是指当客户需求增加或减少时&#xff0c;自动从数据中心配置和取消配置资源。这使得云资源(包括计算、存储和内存资源)能够根据需求变化快速重新分配。CPU/处理、内存、输入/输出带宽和存储容量等计算资源可以根据需要增加或减少&#xff0c;而不会影响系统性能。 它旨在…

前端工程化基础(一):Node模块化

Node模块化 Node.js是什么 官方定义&#xff1a;Node.js是一个基于V8 JavaScript引擎的JavaScript运行时的环境 Node.js基于V8引擎来执行 JavaScript代码&#xff0c;但是Node.js中不仅仅有V8 我们知道&#xff0c;V8可以嵌入到C应用程序中&#xff0c;因此无论是Chrome还是No…

EventSource 长链接执行

EventSource 说明文档MDN 其他参考文档 一、利用node启服务 import fs from fs import express from express const app express() // eventSource 仅支持 get 方法 // 服务器端发送的数据必须是纯文本格式&#xff0c;不能是二进制数据。 app.get(/api, (req, res) > …

智能AI系统开发,专业软件硬件物联网开发公司,探索未来科技新纪元

在信息时代&#xff0c;人工智能&#xff08;AI&#xff09;、物联网等前沿技术日益受到人们的关注。智能AI系统、专业软件硬件物联网开发公司应运而生。今天&#xff0c;我们将向大家介绍一家位于XX城的专业公司&#xff0c;致力于智能AI系统开发和软件硬件物联网领域的创新研…

光学系统的核心--分辨率

前言 在机器视觉领域&#xff0c;可以把各个部件划分为光源&#xff0c;镜头&#xff0c;相机&#xff0c;采集卡&#xff0c;算法&#xff0c;运动平台等。各个部件都是系统的有机组合&#xff0c;均有各自的重要性。在实际应用中&#xff0c;成像镜头涉及的光学理论较多&…

Vue 响应式原理源码剖析

文章目录 1. 说明2. 初始化initState()initProps()initData()observe()ObserverdefineReactive() 3. 数据代理4. 模板解析4.1. 模板解析的基本流程4.2. 模板解析(1): 大括号表达式解析4.3. 模板解析(2): 事件指令解析4.4. 模板解析(3): 一般指令解析 5. 数据绑定5.1. 数据绑定5…

实体识别与分类方法综述

目录 前言1 实体识别简介2 基于模板和规则的方法3 基于序列标注的方法3.1 常见序列标注模型3.2 模型参数估计和学习问题3.3 常见序列预测模型 4. 基于深度学习的实体识别方法5 基于预训练语言模型的实体识别5.1 BERT、GPT等预训练语言模型5.2 解码策略 6 特殊问题与挑战6.1 标签…

Ultraleap 3Di新建项目之给所有的Joint挂载物体

工程文件 Ultraleap 3Di给所有的Joint挂载物体 前期准备 参考上一期文章&#xff0c;进行正确配置 Ultraleap 3Di配置以及在 Unity 中使用 Ultraleap 3Di手部跟踪 新建项目 初始项目如下&#xff1a; 新建Create Empty 将新建的Create Empty&#xff0c;重命名为LeapPro…

10-微服务Nacos Config的通用配置

一、解决不同环境相同配置问题-自定义Data ID配置 在实际的开发过程中&#xff0c;我们的项目所用到的配置参数有的时候并不需要根据不同的环境进行区分&#xff0c;生产、测试、开发环境所用到的参数值是相同的。那么解决同一服务在多环境中&#xff0c;引用相同的配置的问题…

HTTP中POST、GET、PUT、DELETE方式的区别

GET请求会向数据库发索取数据的请求&#xff0c;从而来获取信息&#xff0c;该请求就像数据库的select操作一样&#xff0c;只是用来查询一下数据&#xff0c;不会修改、增加数据&#xff0c;不会影响资源的内容&#xff0c;即该请求不会产生副作用。无论进行多少次操作&#x…

uni-app 微信小程序之红包雨活动

文章目录 1. 页面效果2. 页面样式代码 1. 页面效果 GIF录屏有点卡&#xff0c;实际比较丝滑 每0.5s掉落一个红包控制4s后自动移除红包点击红包消除红包&#xff08;或者自行1&#xff0c;或者弹窗需求&#xff09; 2. 页面样式代码 <!-- 红包雨活动 --> <template>…

【TCP】重传与超时机制

前言 在网络通信的世界里&#xff0c;传输控制协议&#xff08;TCP&#xff09;扮演着一个至关重要的角色。它确保了数据的可靠传输&#xff0c;就像邮差确保每一封信都能准确无误地送达收件人手中一样。但是&#xff0c;网络环境充满了不确定性&#xff0c;数据包可能会因为各…

(大众金融)SQL server面试题(3)-客户已用额度总和

今天&#xff0c;面试了一家公司&#xff0c;什么也不说先来三道面试题做做&#xff0c;第三题。 那么&#xff0c;我们就开始做题吧&#xff0c;谁叫我们是打工人呢。 题目是这样的&#xff1a; DEALER_INFO经销商授信协议号码经销商名称经销商证件号注册地址员工人数信息维…

web3d-three.js场景设计器-mesh网格添加多模型-模型描述随动

给场景中的模型加上广告牌描述&#xff0c;可以在模型的MESH里添加Sprite&#xff0c;配上相应的文字&#xff0c; 描述Sprite的位置则是在mesh中的相对位置&#xff0c;比如模型高10&#xff0c;那么我们可以给一个y等于10 来进行适配&#xff0c;这样在移动模型mesh网格时可…

重磅!讯飞星火V3.5马上发布!AI写作、AI编程、AI绘画等功能全面提升!

讯飞星火大模型相信很多友友已经不陌生了&#xff0c;可以说是国内GPT相关领域的龙头标杆&#xff0c;而对于1月30日即将在讯飞星火发布会发出的V3.5新版本来说&#xff0c;讯飞星火V3.5与之前版本相比&#xff0c;性能提升方面相当明显&#xff0c;在提示语义理解、内容生成、…

常见の算法链表问题

时间复杂度 1.链表逆序 package class04;import java.util.ArrayList; import java.util.List;public class Code01_ReverseList {public static class Node {public int value;public Node next;public Node(int data) {value data;}}public static class DoubleNode {publi…

零基础学习数学建模——(四)备战美赛

本篇博客将讲解如何备战美赛。 什么是美赛 美赛&#xff0c;全称是美国大学生数学建模竞赛&#xff08;MCM/ICM&#xff09;&#xff0c;由美国数学及其应用联合会主办&#xff0c;是最高的国际性数学建模竞赛&#xff0c;也是世界范围内最具影响力的数学建模竞赛。 赛题内容…

Unity3D学习之UI系统——NGUI

文章目录 1. 前言2 NGUI下载和导入3. NGUI三大组件3.1 Root组件3.1.1 分辨率概念3.1.2 Root的作用3.1.3 root脚本各组件3.1.4 总结 3.2 Panel 组件3.2.1 Panel的作用3.2.2 Panel的控件3.2.3 总结 3.3 EventSystem组件3.3.1 作用3.3.2 组件3.3.3 总结 4 图集制作4.1 图集的作用4…

华为和苹果手机迁移备忘录数据方法

在数字时代&#xff0c;手机已成为我们生活的重要组成部分&#xff0c;而备忘录更是我们日常不可或缺的小助手。但当我们从华为切换到苹果&#xff0c;或从苹果转向华为时&#xff0c;如何确保那些重要的备忘信息不丢失&#xff0c;顺利迁移到新手机中呢&#xff1f; 我曾亲身…