C++——list容器以及手动实现

news2025/1/16 1:04:14

LIST容器

  • list概述
    • 列表
    • 容器属性
    • 例子
  • list函数
    • 构造函数
      • 默认构造函数:
      • 带有元素个数和元素初值的构造函数:
      • 范围构造函数:
      • 拷贝构造函数:
      • 移动构造函数:
      • 示例
    • 赋值运算符重载
      • 拷贝赋值操作符 (1):
      • 移动赋值操作符 (2):
      • 初始化列表赋值操作符 (3):
      • 示例
      • 注意事项
    • 迭代器函数
    • 插入和删除函数
    • 清空和删除函数
  • 自己实现的list容器案例

list概述

std::list

template < class T, class Alloc = allocator<T> > class list;

列表

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

列表容器以双向链表的形式实现;双向链表可以将它们包含的每个元素存储在不同且不相关的存储位置。排序是通过与每个元素的关联在内部保持的,该关联链接到它前面的元素,以及与它后面的元素的链接。

它们与 forward_list 非常相似:主要区别在于forward_list对象是单链表,因此它们只能向前迭代,以换取更小、更高效的性能。

与其他基本标准序列容器(数组、向量和 deque)相比,列表在插入、提取和移动已获得迭代器的容器内的任何位置的元素方面通常表现更好,因此在大量使用这些元素的算法(如排序算法)中也是如此。

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

容器属性

序列

序列容器中的元素按严格的线性顺序排序。各个元素通过它们在此序列中的位置进行访问。

双向链表

每个元素都保留有关如何定位下一个和上一个元素的信息,允许在特定元素(甚至整个范围)之前或之后进行恒定时间插入和擦除操作,但不能直接随机访问。

分配器感知

容器使用分配器对象来动态处理其存储需求。

模板参数

T

元素的类型

别名为成员类型 list::value_type。

分配

用于定义存储分配模型的分配器对象的类型。默认情况下,使用分配器类模板,该模板定义了最简单的内存分配模型,并且与值无关。

别名为成员类型 list::allocator_type。

例子

std::list 是 C++ 标准库中的双向链表(doubly linked list)容器,它提供了高效的插入和删除操作,但不支持随机访问元素。下面简要介绍一下 std::list 的底层实现机制和一个简单的示例。

底层实现机制

std::list 使用双向链表作为其底层数据结构,每个节点(node)包含两个指针:一个指向前一个节点,一个指向后一个节点。这种结构使得在任意位置插入和删除操作都很高效,因为只需要调整相邻节点的指针即可,不需要像数组那样移动大量元素。

双向链表的结构如下所示

nullptr <-> Node1 <-> Node2 <-> … <-> NodeN <-> nullptr
其中 nullptr 表示空指针,用来表示链表的头尾。每个节点中会存储实际的数据,比如 int、char、struct 等。

示例

下面是一个简单的示例展示如何使用 std::list 容器:

#include <iostream>
#include <list>

int main() {
    // 创建一个空的 std::list 容器
    std::list<int> mylist;

    // 向 list 中插入元素
    mylist.push_back(1);    // {1}
    mylist.push_back(2);    // {1, 2}
    mylist.push_front(3);   // {3, 1, 2}
    mylist.push_back(4);    // {3, 1, 2, 4}
    
    // 使用迭代器遍历输出 list 中的元素
    std::cout << "List elements: ";
    for (auto it = mylist.begin(); it != mylist.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 在指定位置插入元素
    auto it = ++mylist.begin(); // 获取第二个元素的迭代器
    mylist.insert(it, 5); // 在第二个元素后面插入 5,{3, 5, 1, 2, 4}

    // 删除元素
    mylist.pop_front(); // 删除第一个元素,{5, 1, 2, 4}
    mylist.pop_back();  // 删除最后一个元素,{5, 1, 2}

    // 输出修改后的 list 元素
    std::cout << "Modified List elements: ";
    for (auto it = mylist.begin(); it != mylist.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

示例解释

1,首先,我们创建了一个 std::list 类型的空列表 mylist。

2,使用 push_back() 和 push_front() 方法向列表中添加元素。

3,使用迭代器 begin() 和 end() 遍历输出列表中的元素。

4,使用 insert() 在指定位置插入元素。

5,使用 pop_front() 和 pop_back() 方法删除第一个和最后一个元素。

6,最后,再次使用迭代器遍历输出修改后的列表元素。

这个例子展示了 std::list 容器的基本操作,包括插入、删除和遍历元素等,利用了其底层双向链表的特性,使得这些操作都能够高效地执行。

list函数

构造函数

在这里插入图片描述

std::list 的构造函数可以分为以下几类:

默认构造函数:

std::list();

创建一个空的双向链表。链表中不包含任何元素。

带有元素个数和元素初值的构造函数:

explicit std::list(size_type count, const T& value = T());

创建一个包含 count 个元素的链表,每个元素的值都是 value。例如:

std::list<int> mylist(5, 10);  // 创建一个包含5个值为10的元素的链表

范围构造函数:

template<class InputIterator>
std::list(InputIterator first, InputIterator last);

从迭代器范围 [first, last) 中构造链表,将范围内的元素复制到新建的链表中。例如:

int arr[] = {1, 2, 3, 4, 5};
std::list<int> mylist(arr, arr + 5);  // 从数组中复制元素到链表

拷贝构造函数:

std::list(const std::list& other);

使用另一个 std::list 对象 other 中的元素创建新的链表。例如:

std::list<int> original = {1, 2, 3};
std::list<int> copy = original;  // 使用拷贝构造函数创建副本

移动构造函数:

std::list(std::list&& other) noexcept;

使用另一个 std::list 对象 other 中的元素创建新的链表,并接管 other 的资源。移动构造函数通常比拷贝构造函数更高效。例如:

std::list<int> source = {1, 2, 3};
std::list<int> dest = std::move(source);  // 使用移动构造函数

示例

下面是一个综合示例,展示了 std::list 的不同构造函数的使用方式:

#include <iostream>
#include <list>

int main() {
    // 默认构造函数创建空链表
    std::list<int> empty_list;

    // 使用带有元素个数和初值的构造函数
    std::list<int> filled_list(5, 10);  // 包含5个值为10的元素的链表

    // 使用范围构造函数
    int arr[] = {1, 2, 3, 4, 5};
    std::list<int> range_list(arr, arr + 5);  // 从数组中复制元素到链表

    // 使用拷贝构造函数
    std::list<int> original = {1, 2, 3};
    std::list<int> copy = original;  // 创建副本

    // 使用移动构造函数
    std::list<int> source = {4, 5, 6};
    std::list<int> dest = std::move(source);  // 移动构造函数

    // 输出链表中的元素
    std::cout << "Filled list elements:";
    for (auto& elem : filled_list) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    std::cout << "Range list elements:";
    for (auto& elem : range_list) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    std::cout << "Copy list elements:";
    for (auto& elem : copy) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    std::cout << "Moved list elements:";
    for (auto& elem : dest) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    return 0;
    

赋值运算符重载

在这里插入图片描述

拷贝赋值操作符 (1):

list& operator= (const list& x);

将另一个 std::list 对象 x 中的元素拷贝赋值给当前链表对象。例如:

std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {4, 5};


list2 = list1;  // 使用拷贝赋值操作符
// 现在 list2 的元素为 {1, 2, 3}

移动赋值操作符 (2):

list& operator= (list&& x);

将另一个 std::list 对象 x 中的元素移动赋值给当前链表对象。移动赋值操作符通常用于提高效率。例如:

std::list<int> list1 = {1, 2, 3};
std::list<int> list2 = {4, 5};

list2 = std::move(list1);  // 使用移动赋值操作符
// 现在 list2 的元素为 {1, 2, 3},list1 变成空链表

初始化列表赋值操作符 (3):

list& operator= (initializer_list<value_type> il);

使用初始化列表 il 中的元素来赋值给当前链表对象。例如:

std::list<int> list1 = {1, 2, 3};

list1 = {4, 5, 6};  // 使用初始化列表赋值操作符
// 现在 list1 的元素为 {4, 5, 6}

示例

下面是一个综合示例,演示了 std::list 中各种赋值操作符的使用:

#include <iostream>
#include <list>

int main() {
    // 拷贝赋值操作符示例
    std::list<int> list1 = {1, 2, 3};
    std::list<int> list2 = {4, 5};

    list2 = list1;  // 拷贝赋值操作符
    std::cout << "List2 after copy assignment:";
    for (auto& elem : list2) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    // 移动赋值操作符示例
    std::list<int> list3 = {7, 8};
    std::list<int> list4 = {9, 10};

    list4 = std::move(list3);  // 移动赋值操作符
    std::cout << "List4 after move assignment:";
    for (auto& elem : list4) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    // 初始化列表赋值操作符示例
    std::list<int> list5 = {11, 12, 13};

    list5 = {14, 15, 16};  // 初始化列表赋值操作符
    std::cout << "List5 after initializer list assignment:";
    for (auto& elem : list5) {
        std::cout << " " << elem;
    }
    std::cout << std::endl;

    return 0;
}

注意事项

拷贝赋值操作符和移动赋值操作符的选择通常取决于右侧操作数的类型和实际需求。

初始化列表赋值操作符用于通过大括号 {} 直接赋值一组元素。

迭代器函数

1,begin() 和 end():

iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;

这些函数返回链表的起始迭代器和结束迭代器。对于非常量对象,begin() 返回指向第一个元素的迭代器,end() 返回指向最后一个元素后面位置的迭代器;对于常量对象,返回的是 const_iterator,用于只读访问链表的元素。

示例

std::list<int> myList = {1, 2, 3, 4};

// 使用迭代器遍历链表
for (auto it = myList.begin(); it != myList.end(); ++it) {
    std::cout << *it << " ";
}

2,rbegin() 和 rend():

reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;

这些函数返回链表的反向迭代器,用于反向遍历链表元素。rbegin() 返回指向最后一个元素的反向迭代器,rend() 返回指向第一个元素前面位置的反向迭代器;对于常量对象,返回的是 const_reverse_iterator。

示例

std::list<int> myList = {1, 2, 3, 4};

// 使用反向迭代器遍历链表
for (auto rit = myList.rbegin(); rit != myList.rend(); ++rit) {
    std::cout << *rit << " ";
}

3,cbegin() 和 cend():

const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;

这些函数返回链表的常量迭代器,用于只读访问链表元素。cbegin() 返回指向第一个元素的常量迭代器,cend() 返回指向最后一个元素后面位置的常量迭代器。

示例

std::list<int> myList = {1, 2, 3, 4};

// 使用常量迭代器遍历链表
for (auto cit = myList.cbegin(); cit != myList.cend(); ++cit) {
    std::cout << *cit << " ";
}

4,crbegin() 和 crend():

const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

这些函数返回链表的常量反向迭代器,用于只读反向访问链表元素。crbegin() 返回指向最后一个元素的常量反向迭代器,crend() 返回指向第一个元素前面位置的常量反向迭代器。

示例

std::list<int> myList = {1, 2, 3, 4};

// 使用常量反向迭代器遍历链表
for (auto crit = myList.crbegin(); crit != myList.crend(); ++crit) {
    std::cout << *crit << " ";
}

插入和删除函数

  • push_front(const T& value)
    在链表头部插入一个元素。

语法结构

void push_front(const T& value);

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};

    // 在链表头部插入元素
    myList.push_front(0); // 现在链表为 {0, 1, 2, 3}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • push_back(const T& value)
    在链表尾部插入一个元素。

语法结构

void push_back(const T& value);

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};

    // 在链表尾部插入元素
    myList.push_back(4); // 现在链表为 {1, 2, 3, 4}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • pop_front()
    删除链表头部的元素。

语法结构

void pop_front();

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};

    // 删除链表头部的元素
    myList.pop_front(); // 现在链表为 {2, 3}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • pop_back()
    删除链表尾部的元素。

语法结构

void pop_back();

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};

    // 删除链表尾部的元素
    myList.pop_back(); // 现在链表为 {1, 2}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • insert(const_iterator pos, const T& value)
    在迭代器 pos 所指位置插入元素 value。

语法结构

iterator insert(const_iterator pos, const T& value);

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};
    auto it = myList.begin();
    ++it; // 移动到第二个位置

    // 在指定位置插入元素
    myList.insert(it, 4); // 现在链表为 {1, 4, 2, 3}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • erase(const_iterator pos)
    删除迭代器 pos 所指位置的元素。

语法结构

iterator erase(const_iterator pos);

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 3};
    auto it = myList.begin();
    ++it; // 移动到第二个位置

    // 删除指定位置的元素
    myList.erase(it); // 现在链表为 {1, 3}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

清空和删除函数

  • clear()
    清空链表,移除所有元素。

语法结构

void clear();

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 2, 3};

    // 清空链表
    myList.clear(); // 现在链表为空

    std::cout << "List size after clearing: " << myList.size() << std::endl;

    return 0;
}
  • remove(const T& value)
    移除链表中所有等于 value 的元素。

语法结构

void remove(const T& value);

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 2, 3};

    // 移除所有值为 2 的元素
    myList.remove(2); // 现在链表为 {1, 3}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • remove_if(UnaryPredicate p)
    根据条件 p 移除符合条件的元素。

语法结构

template<class UnaryPredicate>
void remove_if(UnaryPredicate p);

示例用法

#include <iostream>
#include <list>

bool isEven(int num) {
    return num % 2 == 0;
}

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // 移除所有偶数元素
    myList.remove_if(isEven); // 现在链表为 {1, 3, 5}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • unique()
    移除链表中连续重复的元素,只保留一个。

语法结构

void unique();

示例用法

#include <iostream>
#include <list>

int main() {
    std::list<int> myList = {1, 2, 2, 3, 3, 3, 4};

    // 移除连续重复的元素
    myList.unique(); // 现在链表为 {1, 2, 3, 4}

    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

自己实现的list容器案例

namespace mylist
{
    // List的节点类
    template<class T>
    struct ListNode
    {
        ListNode(const T& val = T())
            : _pPre(nullptr), _pNext(nullptr), _val(val) {}

        ListNode<T>* _pPre;
        ListNode<T>* _pNext;
        T _val;
    };

    // List的迭代器类
    template<class T, class Ref, class Ptr>
    class ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;

    public:
        ListIterator(PNode pNode = nullptr)
            : _pNode(pNode) {}

        ListIterator(const Self& l)
            : _pNode(l._pNode) {}

        PNode Ptr() const
        {
            return _pNode;
        }

        T& operator*() const
        {
            return _pNode->_val; // 直接解引用 _pNode
        }

        T* operator->() const
        {
            return &_pNode->_val; // 直接返回 _pNode->_val 的地址
        }

        Self& operator++()
        {
            _pNode = _pNode->_pNext;
            return *this;
        }

        Self operator++(int)
        {
            Self tem(_pNode);
            _pNode = _pNode->_pNext;
            return tem;
        }

        Self& operator--()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }

        Self operator--(int)
        {
            Self tem(_pNode);
            _pNode = _pNode->_pPre;
            return tem;
        }

        bool operator!=(const Self& l) const
        {
            return _pNode != l._pNode;
        }

        bool operator==(const Self& l) const
        {
            return _pNode == l._pNode;
        }

    private:
        PNode _pNode;
    };

    // list类
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef Node* PNode;

    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T&> const_iterator;

    public:
        list()
        {
            CreateHead();
            length = 0;
        }

        list(int n, const T& value = T())
        {
            CreateHead();
            length = n;
            while (n--)
            {
                PNode tem = new Node(value); //创建 Node 对象非 PNode
                _pHead->_pPre->_pNext = tem;
                tem->_pPre = _pHead->_pPre;
                tem->_pNext = _pHead;
                _pHead->_pPre = tem;
            }
        }

        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            CreateHead();
            while (first != last)
            {
                PNode tem = new Node(*first); //创建 Node 对象非 PNode
                first++;
                _pHead->_pPre->_pNext = tem;
                tem->_pPre = _pHead->_pPre;
                tem->_pNext = _pHead;
                _pHead->_pPre = tem;
                length++;
            }
        }

        list(const list<T>& l)
        {
            CreateHead();
            PNode sta = l._pHead->_pNext;
            PNode end = l._pHead;

            while (sta != end)
            {
                PNode tem = new Node(sta->_val); // 创建 Node 对象而非 PNode
                sta = sta->_pNext;
                _pHead->_pPre->_pNext = tem;
                tem->_pPre = _pHead->_pPre;
                tem->_pNext = _pHead;
                _pHead->_pPre = tem;
                length++;
            }
        }

        list<T>& operator=(const list<T>& l)
        {
            clear(); // 使用 clear() 而不是 ~list() 来清空内容
            CreateHead();
            PNode sta = l._pHead->_pNext;
            PNode end = l._pHead;

            while (sta != end)
            {
                PNode tem = new Node(sta->_val); // 创建 Node 对象而非 PNode
                sta = sta->_pNext;

                _pHead->_pPre->_pNext = tem;
                tem->_pPre = _pHead->_pPre;
                tem->_pNext = _pHead;
                _pHead->_pPre = tem;
                length++;
            }

            return *this;
        }

        ~list()
        {
            clear(); // 使用 clear() 来删除所有节点
            delete _pHead; //删除链表头节点
        }

        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_pHead->_pNext);
        }

        iterator end()
        {
            return iterator(_pHead);
        }

        const_iterator begin() const
        {
            return const_iterator(_pHead->_pNext);
        }

        const_iterator end() const
        {
            return const_iterator(_pHead);
        }

        ///
        // List Capacity
        size_t size() const
        {
            return length;
        }

        bool empty() const
        {
            return length == 0;
        }

        
        // List Access
        T& front()
        {
            assert(!empty()); // assert(!empty())
            return _pHead->_pNext->_val;
        }

        const T& front() const
        {
            assert(!empty()); // assert(!empty())
            return _pHead->_pNext->_val;
        }

        T& back()
        {
            assert(!empty()); // assert(!empty())
            return _pHead->_pPre->_val;
        }

        const T& back() const
        {
            assert(!empty()); // 修改:assert(!empty())
            return _pHead->_pPre->_val;
        }

        
        // List Modify
        void push_back(const T& val) { insert(end(), val); }

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

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

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

        iterator insert(iterator pos, const T& val)
        {
            assert(pos != end());
            PNode cur = pos.Ptr();
            PNode tem = new Node(val);

            tem->_pPre = cur->_pPre; // 修正插入节点的前驱指针
            tem->_pNext = cur;
            cur->_pPre->_pNext = tem;
            cur->_pPre = tem;

            length++;
            return iterator(tem);
        }

        iterator erase(iterator pos)
        {
            PNode cur = pos.Ptr();

            cur->_pPre->_pNext = cur->_pNext;
            cur->_pNext->_pPre = cur->_pPre;

            iterator next(cur->_pNext);
            delete cur;
            length--;

            return next;
        }

        void clear()
        {
            PNode cur = _pHead->_pNext;
            while (cur != _pHead)
            {
                PNode next = cur->_pNext;
                delete cur;
                cur = next;
            }

            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
            length = 0;
        }

        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
            std::swap(length, l.length);
        }

    private:

        void CreateHead()
        {
            _pHead = new Node;
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }

        PNode _pHead;
        size_t length;
    };

};

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

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

相关文章

安全通信|数据加密的由来|加密算法简介|中间人攻击与证书认证|身份验证

&#x1f448;️下一篇 计算机网络-专栏&#x1f448;️ 数据加密的由来|加密算法简介|中间人攻击与证书认证 引言 在客户端(client)-服务器(server)模式下&#xff0c;客户端与服务器间通信&#xff0c;如果明文传输数据&#xff0c;在传输过程被劫持&#xff0c;内容直接泄…

MySQL触发器和存储过程

1、触发器 &#xff08;1&#xff09;&#xff1a;建立触发器&#xff0c;订单表中增加订单数量后&#xff0c;商品表商品数量同步减少对应的商品订单出数量,并测试 mysql> create trigger orders_after_insert_trigger-> after insert on orders for each row-> up…

不知道你们有没有我这样的一种状态...总是这样又总是那样...

各位小伙伴们&#xff0c;我是风尚&#xff0c;我不知道你们有没有那么一刻&#xff0c;就是感觉站在人生的十字路口&#xff0c;感觉自己就像是被扔进了一个没有导航的迷宫&#xff0c;四周都是墙&#xff0c;头顶是蓝天白云&#xff0c;却怎么也找不到出口的方向&#xff1f;…

重磅推荐!GBD再度登顶Lancet!| GBD数据库周报(7.17~7.23)

全球疾病负担&#xff08;GBD&#xff09;是迄今为止规模最大、最全面的一项研究&#xff0c;旨在量化不同地区和不同时期的健康损失&#xff0c;从而改善卫生系统并消除差异。 该研究由华盛顿大学健康指标与评估研究所 (IHME) 牵头&#xff0c;是一项真正的全球性研究&#xf…

MySQL--数据库与表的操作

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 数据库的基本操作 # 1、查看数据库show databases;​# 2、创建数据库create database 数据库名称;​# 3、删除数据库drop databse 数据库名称; 数据表…

RAC(Teamcenter )开发,Bom行解包和打包的方法

1、打包 UnpackAllAction allAction new UnpackAllAction((AbstractBOMLineViewerApplication) currentApplication, "packAllAction"); new Thread(allAction).start();2、解包 UnpackCommand command new UnpackCommand(bomLine); command.executeModal();3、注…

Marin说PCB之Orcad Capture调网表时出现了“Duplicate Pin Name”该怎么搞?

最近大巴黎在如火如荼的举行着奥运会&#xff0c;中国健儿们也是不负众望在很多项目中取得金牌的好成绩&#xff0c;其中中国选手陈芋汐/全红婵夺得巴黎奥运会跳水女子双人10米台金牌&#xff0c;其实没有看我就知道比赛的结果了&#xff0c;肯定是我们中国队夺得金牌的。 看到…

月薪竟然高达60k,AI大模型凭什么?

你是不是最近经常看到或听到“AI大模型”这个关键词&#xff1f;我也是&#xff01;所以好奇去Boss直聘上搜了下工作机会。看到结果时&#xff0c;我有点不淡定了&#xff01;薪资竟然这么高&#xff01; 这是我随便搜的结果&#xff0c;发出来给大家看看。 下面&#xff0c;我…

多线程习题

1.使用两个线程完成两个文件的拷贝&#xff0c;分支线程1拷贝前一半&#xff0c;分支线程拷贝后一般&#xff0c;主线程回收两个分支线程的资源 #include<myhead.h> struct Buf {const char *srcfile;const char *destfile;int start;int len1; }; //创建求源文件大小的函…

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景读取并保存NPOI信息NPOI 插件介绍基本功能示例代码写入 Excel 文件…

继电器测试中常见的故障和解决方法有哪些?

在继电器测试中&#xff0c;可能会遇到诸如电源问题、负载问题、控制系统问题和显示问题等故障。如果电源电压不稳定或波动过大&#xff0c;可能会导致继电器测试负载箱无法正常工作。此时需要检查电源线路&#xff0c;确保电源电压稳定在规定范围内。如有必要&#xff0c;可以…

详细说明Java中Map和Set接口的使用方法

Map与Set的基本概念与场景 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有&#xff1a; 1. 直接遍历&#xff0c;时间复杂度为O(N)&#xff0c;元素如果比较多效率会非常慢。 2. 二分查找&#x…

PSINS工具箱函数介绍——insinit

insinit是初始化INS系统的函数 函数需要用到PSINS工具箱&#xff0c;关于工具箱的一些入门知识&#xff0c;参考这篇文章&#xff0c;是关于工具箱的讲解&#xff1a; PSINS初学指导&#xff1a;https://blog.csdn.net/callmeup/article/details/137087932 函数使用方法 正…

vulhub:Apache解析漏洞apache_parsing

在Apache1.x/2.x中Apache 解析文件的规则是从右到左开始判断解析&#xff0c;如果后缀名为不可识别文件解析&#xff0c;就再往左判断。如 1.php.xxxxx 漏洞原理 Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。比如如下配置文件 AddType te…

蓝牙网关北京厂家_蓝牙网关型号价格介绍

蓝牙网关北京厂家介绍&#xff1a;北京桂花网科技有限公司成立于2015年&#xff0c;开发了远距离蓝牙网关&#xff0c;重新定义了蓝牙&#xff0c;拓展了蓝牙的应用范围&#xff0c;在2016年1月的拉斯维加斯世界消费电子CES展会上一举夺得Best of CES创新大奖。随后&#xff0c…

操作系统_内存管理学习心得

1. 操作系统结构 1.1 内核 计算机是由各种外部硬件设备组成的,比如内存、cpu、 硬盘等,如果每个应用都要和这些硬件设备对接通信协议&#xff0c;那这样太累了&#xff0c;所以这个中间人就由内核来负责,让内核作为应用连接硬件设备的桥梁,应用程序只需关心与内核交写&#x…

day19Tomcat

1. Tomcat启动服务 1. 使用命令&#xff1a; /usr/local/tomcat/bin/startup.sh 启动Tomcat服务。 2. 使用命令&#xff1a; netstat -lnput|grep java 查看端口状态&#xff0c;可以看到8080和8005两个端口。 3. 使用命令&#xff1a; /usr/local/tomcat/bin/shutdown.sh 停止…

用18讲必看:宇哥亲划重点内容+核心题总结

25考研结束之后&#xff0c;张宇老师的风评可能会两极分化 其中一波把张宇老师奉为考研数学之神&#xff0c;吹捧「三向解题法」天下无敌。 另外一波对张宇老师的评价负面&#xff0c;在网上黑张宇老师&#xff01; 为什么会这么说&#xff0c;因为张宇老师的新版36讲争议太…

【八股文】并发编程相关考点

1.线程和进程和协程的区别 进程是操作系统中资源分配和调度的基本单位&#xff0c;是程序的一次执行过程&#xff0c;因此是动态的&#xff0c;即一个进程从创建到运行再到消亡。每个进程都有独立的内存空间&#xff0c;一位置一个进程的变量修改不会影响到其他经常。进程之间的…

大数据HBase图文简介

往期推荐 数据仓库及数仓架构概述-CSDN博客 数仓常见名词解析和名词之间的关系-CSDN博客 引言 要想明白为什么产生 HBase&#xff0c;就需要先了解一下 Hadoop 存在的限制&#xff1a;Hadoop 可以通过 HDFS 来存 储结构化、半结构甚至非结构化的数据&#xff0c;是传统数据库的…