【C++】C++ STL标准模板库知识点总结(秋招篇)

文章目录


머리말

C++ STL 표준 템플릿 라이브러리 요약 가을 모집 노트 요약
작성자가 chatgpt로 작성했기 때문에 일부 답변에 대한 탈출구가 있을 수 있으며(GPT 3.5 버전에는 일부 결함이 있음) 대부분의 답변은 완료한 후 수정했습니다. 쓰기, 불일치가 있습니다. 학생들이 장소를 지적하기를 바랍니다.

2023.7.28 첫 업데이트

긴 코드의 다음 부분은 다크호스 프로그래머 에 통합됩니다. 여기에서 각 컨테이너의 공통 기능을 CPP 파일에 통합했습니다.별도로 읽고 싶다면 스테이션 B로 직접 이동하여 다크호스 프로그래머를 검색하여 해당 노트를 읽을 수 있습니다.
Dark Horse Programmer Station B 주소: Dark Horse Programmer C++

마인드맵은 다음과 같습니다.
여기에 이미지 설명 삽입

STL의 여섯 가지 구성 요소는 무엇입니까?

STL(标准模板库)是C++标准库中的一个重要组成部分,它提供了一套通用的模板类和算法,用于处理各种数据结构和操作。STL的六大组件如下:

  1. 容器(Containers):容器是用于存储和管理数据的类模板。STL提供了多种容器,包括向量(vector)、链表(list)、双端队列(deque)、集合(set)、映射(map)等。每种容器都有不同的特点和适用场景。
  2. 算法(Algorithms):算法是用于执行各种操作的函数模板。STL提供了大量的算法,例如排序、查找、合并、删除等。这些算法可以应用于各种容器,使得对数据的处理更加方便和高效。
  3. 迭代器(Iterators):迭代器用于遍历容器中的元素,类似于指针的概念。STL提供了多种类型的迭代器,包括输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。迭代器提供了统一的接口,使得算法可以独立于容器而操作。
  4. 仿函数(Functors):仿函数是重载了函数调用运算符的类对象,它可以像函数一样被调用。STL中的算法通常接受仿函数作为参数,用于指定特定的操作。STL提供了一些内置的仿函数,同时也可以自定义仿函数。
  5. 适配器(Adapters):适配器是用于在不同接口之间进行转换的类模板。STL提供了两种常用的适配器:容器适配器和迭代器适配器。容器适配器可以将一个容器的接口转换为另一个容器的接口,例如栈(stack)和队列(queue)。迭代器适配器可以改变迭代器的行为,例如反向迭代器(reverse_iterator)和插入迭代器(insert_iterator)。
  6. 分配器(Allocators):分配器用于管理内存的分配和释放。STL提供了默认的分配器,同时也允许用户自定义分配器。分配器可以在容器中指定,用于控制容器的内存管理方式。

这些组件相互配合,使得STL成为一个强大而灵活的工具,可以大大简化C++程序的开发和维护。

容器(container) 算法(algorithm) 迭代器(iterator) 三者的关系?

컨테이너(container), 알고리즘(algorithm), 반복자(iterator)는 C++ STL(Standard Template Library)에서 중요한 세 가지 개념으로 서로 밀접한 관계가 있습니다.

vector컨테이너는 , , list등과 map같이 데이터를 저장하고 구성하는 데 사용되는 객체입니다. 컨테이너는 데이터를 관리하고 액세스하기 위해 삽입, 삭제, 검색 및 순회 등과 같은 다양한 작업을 제공합니다.

알고리즘은 정렬, 찾기, 순회 등과 같은 컨테이너의 데이터에 대한 작업을 수행하는 기능 템플릿입니다. 알고리즘은 컨테이너와 독립적으로 사용할 수 있으며 컨테이너가 알고리즘의 요구 사항을 충족하는 한 다양한 유형의 컨테이너에서 작동할 수 있습니다.

반복자는 컨테이너와 컨테이너의 요소를 순회하는 데 사용되는 알고리즘 사이의 브리지입니다. 반복자는 컨테이너의 요소에 액세스하기 위한 인터페이스를 제공하며 컨테이너의 데이터는 반복자를 통해 액세스하고 조작할 수 있습니다. 반복자는 컨테이너 요소에 대한 포인터로 간주될 수 있으며 순회, 액세스 및 수정과 같은 작업을 수행할 수 있습니다.

컨테이너, 알고리즘 및 반복기 간의 관계는 다음과 같습니다.

  • 컨테이너는 데이터 스토리지 및 구성 방법을 제공하며 알고리즘을 사용하여 컨테이너의 데이터를 조작할 수 있습니다.
  • 알고리즘은 컨테이너에서 작동하고 컨테이너와 독립적으로 사용할 수 있는 함수 템플릿입니다.
  • 반복자는 컨테이너의 요소를 순회하는 데 사용되며 컨테이너의 요소에 액세스하기 위한 인터페이스를 제공합니다.

컨테이너, 알고리즘 및 반복자를 결합하여 데이터를 효율적으로 관리하고 처리할 수 있습니다. STL은 일련의 컨테이너, 알고리즘 및 반복자를 제공하여 C++ 프로그래밍을 보다 편리하고 효율적으로 만듭니다.

얼마나 많은 종류의 컨테이너가 있습니까? 그들은 무엇인가?

C++ STL의 컨테이너는 시퀀스 컨테이너와 연관 컨테이너의 두 가지 유형으로 나눌 수 있습니다. 순차 컨테이너 : 값의 정렬을 강조하며 순차 컨테이너의 각 요소는 고정된 위치를 가집니다. 연관 컨테이너 : 이진 트리 구조, 요소 간에 엄격한 물리적 순서 관계가 없습니다.

순차 컨테이너는 요소가 컨테이너에 저장된 순서대로 요소를 저장하고 액세스하는 컨테이너입니다. 컨테이너 끝에 요소 삽입, 지정된 위치에 요소 삽입, 요소 삭제 등과 같은 일련의 작업을 제공합니다. 일반적인 순차 컨테이너에는 다음이 포함됩니다.

  1. vector: 빠른 랜덤 액세스를 지원하는 동적 배열.
  2. list: 이중 연결 리스트, 어느 위치에서나 삽입과 삭제를 지원합니다.
  3. deque: 양쪽 끝에서 삽입 및 삭제 작업을 지원하는 양방향 큐.
  4. array: 크기가 컴파일 타임에 결정되는 고정 크기 배열입니다.
  5. forward_list: 임의의 위치에서 삽입 및 삭제 작업을 지원하는 단일 연결 목록입니다.

연관 컨테이너는 키로 요소를 저장하고 액세스하는 컨테이너입니다. 특정 데이터 구조(예: 레드-블랙 트리)를 사용하여 요소를 빠르게 조회합니다. 연관 컨테이너의 요소는 키의 정렬 방법에 따라 구성되며 키를 통해 요소에 액세스할 수 있습니다. 일반적인 연관 컨테이너에는 다음이 포함됩니다.

  1. set: 키의 오름차순으로 정렬된 고유한 요소를 저장하는 컬렉션입니다.
  2. map: 매핑, 키-값 쌍 저장, 키 오름차순으로 정렬.
  3. multiset: 다중 컬렉션, 중복을 허용하는 요소 저장, 키 오름차순으로 정렬.
  4. multimap: 중복된 키-값 쌍을 저장하고 키의 오름차순으로 정렬하는 멀티맵.

순차 컨테이너와 연관 컨테이너는 기능과 사용 방법이 다르므로 올바른 컨테이너를 선택하는 것은 특정 요구 사항과 사용 시나리오에 따라 다릅니다.

연관 컨테이너와 비연관 컨테이너의 차이점은 무엇입니까?

연관 컨테이너와 비연관 컨테이너는 C++ 표준 라이브러리에서 서로 다른 두 가지 유형의 컨테이너입니다.
연관 컨테이너는 연관 데이터 구조를 기반으로 구현 되며 키-값 쌍을 기반으로 데이터를 저장하고 액세스하는 메커니즘을 제공합니다. 연관 컨테이너에는 std::map, std::set, std::multimap 및 std::multiset이 포함됩니다. 이러한 컨테이너의 요소는 키 값으로 정렬되며 각 키 값은 고유합니다(std::set 및 std::multiset의 경우 순서는 요소 값을 기준으로 함). 연관 컨테이너는 특정 순서로 액세스해야 하거나 요소를 빠르게 찾아야 하는 시나리오에 적합합니다.
비연관 컨테이너는
요소가 삽입된 순서대로 데이터를 저장하고 액세스하기 위한 메커니즘을 제공하는 선형 데이터 구조를 기반으로
구현 됩니다 . 비연관 컨테이너에는 std::vector, std::list, std::deque 및 std::array가 포함됩니다. 이러한 컨테이너의 요소는 삽입 순서대로 저장되며 인덱스 또는 반복자로 액세스할 수 있습니다. 비연관 컨테이너는 요소의 삽입 순서를 유지해야 하거나 빈번한 삽입 및 삭제 작업이 필요한 시나리오에 적합합니다.

벡터 컨테이너의 크기는 어떻게 조정됩니까? (메모리 부족시 동작)

벡터 크기를 조정할 때 구체적인 단계는 다음과 같습니다.

1) 벡터의 크기를 늘리려면 resize() 함수 또는 insert() 함수를 사용하여 새 요소를 추가할 수 있습니다.

resize() 함수: 새 크기를 지정하고 마지막에 기본 구성 요소를 추가할 수 있습니다. 예를 들어 myVector.resize(newSize);는 벡터의 크기를 newSize로 조정하고 끝에 기본 구성 요소를 추가합니다.

insert() 함수: 지정된 위치에 요소를 삽입하여 벡터의 크기를 늘릴 수 있습니다. 예를 들어 myVector.insert(myIterator, element);는 myIterator가 지정한 위치에 요소 요소를 삽입합니다.

2) 벡터의 크기를 줄이려면 erase() 함수를 사용하여 요소를 삭제할 수 있습니다.

Erase() 기능: 지정된 위치 또는 지정된 범위 내의 요소를 삭제하여 벡터 크기를 줄일 수 있습니다. 예를 들어 myVector.erase(myIterator);는 myIterator가 지정한 위치에 있는 요소를 삭제합니다.
벡터의 크기를 조정할 때 메모리 재할당과 요소 이동이 수반된다는 점에 유의해야 합니다. 구체적인 단계는 다음과 같습니다.

3) 벡터의 크기를 늘리려면 새 크기가 현재 용량을 초과하면 벡터가 더 큰 메모리 공간을 재할당합니다. 일반적으로 벡터는 메모리 공간의 현재 크기의 두 배(또는 그 이상)를 할당한 다음 원래 요소를 새 메모리 공간에 복사합니다.

4) 벡터의 크기를 줄이려면 새 크기가 현재 용량보다 작을 때 벡터가 후속 요소를 앞으로 이동하여 삭제된 요소의 빈 공간을 채웁니다.
벡터 크기를 조정한 후 요소의 위치가 변경되어 원래 반복자가 유효하지 않게 될 수 있습니다. 유효하지 않은 이터레이터를 사용하지 않으려면 벡터 크기를 조정한 후 올바른 요소 위치를 가리키도록 이터레이터를 적시에 업데이트해야 합니다.

반복자와 포인터의 차이점

컨테이너 반복자는 일반적으로 포인터와 같은 기능을 제공하는 템플릿 클래스로 구현됩니다 . 반복자 클래스 템플릿은 반복자를 통해 컨테이너의 요소에 액세스할 수 있도록 하는 일련의 연산자 및 멤버 함수를 정의합니다.
반복자와 포인터는 약간의 유사점이 있지만 개념과 사용법에는 약간의 차이가 있습니다. :

1) 개념적 차이:

포인터는 배열 및 기타 데이터 구조를 순회하고 조작하는 데 사용할 수 있는 메모리 주소에 직접 액세스하기 위한 도구입니다.

반복자는 컨테이너의 내부 구현 세부 정보를 몰라도 컨테이너의 요소(예: 배열, 연결 목록, 벡터 등)에 액세스할 수 있는 통합된 방법을 제공하는 추상적인 개념입니다.

2) 유연성 및 보안:

포인터는 높은 유연성을 가지며 임의의 주소 연산 및 포인터 산술 연산을 수행할 수 있습니다. 그러나 범위를 벗어나 액세스하거나 유효하지 않은 메모리를 해제하는 등의 오류 가능성도 높아집니다.

반복자는 잘 정의된 작업 집합을 제공하여 컨테이너를 더 안전하게 순회할 수 있습니다. 반복자는 일반적으로 경계 검사 및 자동 증분과 같은 기능을 제공하여 액세스가 컨테이너 범위 내에 있는지 확인하고 오류 가능성을 줄입니다.

3) 컨테이너의 추상화:

반복자는 컨테이너의 액세스 방법을 추상화하므로 다른 유형의 컨테이너가 동일한 순회 및 작업 방법을 사용할 수 있습니다. 이렇게 하면 다양한 컨테이너 유형에 대한 특정 코드를 작성하지 않고도 코드를 보다 일반적이고 재사용할 수 있습니다.

포인터는 특정 유형의 컨테이너에만 사용할 수 있으며 올바르게 액세스하려면 컨테이너의 내부 구조에 대한 지식이 필요합니다. 이렇게 하면 코드의 결합이 증가하고 충분히 일반적이지 않습니다.

4) 반복자 분류:

Iterator는 순방향 반복기, 양방향 반복기, 임의 액세스 반복기 등과 같은 기능 및 액세스 방법에 따라 분류할 수 있습니다. 이러한 다양한 유형의 반복기는 다양한 수준의 기능과 성능을 제공하며 필요에 따라 적절한 반복기 유형을 선택할 수 있습니다.

포인터는 배열과 같은 데이터 구조를 반복하는 데 사용할 수 있지만 반복자는 컨테이너에 액세스하는 더 높은 수준의 안전하고 추상적인 방법을 제공합니다. 반복자는 코드를 보다 일반적이고 재사용 가능하게 만들고 컨테이너의 다양한 특성에 따라 적절한 반복자 유형을 선택할 수 있습니다. 따라서 포인터가 강력한 도구인 반면 반복자는 C++에서 일반적으로 사용되는 컨테이너 액세스 및 조작을 위한 추상 도구입니다.

반복자가 실패하는 이유는 무엇입니까? 해결 방법이 무엇입니까?

반복자를 사용하는 과정 에서 반복자 무효화 문제가 발생할 수 있습니다. Iterator 무효화는 iterator를 사용하는 동안 컨테이너의 구조가 변경되어 iterator가 가리키는 요소가 존재하지 않거나 잘못된 요소를 가리킨다는 사실을 의미합니다 . 이 경우 유효하지 않은 반복자를 사용하면 정의되지 않은 동작 또는 프로그램 충돌이 발생할 수 있습니다.
반복자 무효화 문제는 일반적으로 다음과 같은 상황에서 나타납니다.

1) 요소 삽입 및 삭제: 컨테이너에 요소를 삽입하거나 삭제할 때 반복자가 무효화될 수 있습니다. 요소를 삽입하면 원래 반복자가 가리키는 요소의 위치가 변경될 수 있으며 요소를 삭제하면 반복자가 가리키는 요소가 삭제될 수 있습니다.

2) 컨테이너 크기 변경: 컨테이너의 크기를 변경하면(예: 벡터 크기 조정) 반복자가 무효화될 수 있습니다. 컨테이너의 크기를 변경하면 원래 반복자가 가리키는 요소의 위치가 변경될 수 있습니다.

3)使用end迭代器:在使用迭代器遍历容器时,如果迭代器到达容器的end位置后继续使用,就会导致迭代器失效。end迭代器表示容器中最后一个元素的下一个位置,它不指向一个有效的元素。
为了避免迭代器失效问题,我们可以采取以下措施:

1)在插入和删除元素时,尽量使用返回新的迭代器的插入和删除函数,而不是使用原有的迭代器。

2)在遍历容器时,使用前向迭代器或双向迭代器,避免使用随机访问迭代器。因为前向迭代器和双向迭代器的失效范围相对较小。

3)在改变容器大小之前,将需要保留的元素先拷贝到另一个容器中,然后重新构建原容器。

讲一下vector的erase函数 使用后迭代器的变化

erase()函数是STL容器提供的一个成员函数,用于从容器中删除一个或多个元素。它接受一个迭代器作为参数,指定要删除的元素的位置,并返回一个指向被删除元素之后元素的迭代器。

下面是一些使用erase()函数后迭代器的变化情况:

删除单个元素:

auto it = vec.erase(position);

在删除单个元素后,迭代器it将指向被删除元素之后的元素。如果被删除的是最后一个元素,则it将指向容器的end()迭代器。

删除一个范围内的元素:

auto it = vec.erase(first, last);

在删除一个范围内的元素后,迭代器it将指向被删除元素之后的元素。如果被删除的是最后一个元素,则it将指向容器的end()迭代器。
需要注意的是,删除元素后,原来的迭代器将失效,不能再使用。如果需要继续遍历容器,应该使用返回的新迭代器。
以下是一个示例,展示了erase()函数使用后迭代器的变化:

#include <iostream>
#include <vector>

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

    auto it = vec.erase(vec.begin() + 2); // 删除第三个元素

    std::cout << "After erasing: ";
    for (auto num : vec) {
    
    
        std::cout << num << " ";
    }
    std::cout << std::endl;

    std::cout << "Iterator position: " << *it << std::endl;

    return 0;
}

在上述示例中,我们使用erase()函数删除了容器vec中的第三个元素。然后,我们输出删除后的容器内容,并打印迭代器it的位置。

其他容器(如list、deque、set、map等)的erase函数操作后,迭代器怎么变化的?

下面是一些常见容器的erase()函数使用后迭代器的变化情况:

1)list:

단일 요소 삭제: erase() 함수는 삭제된 요소 뒤의 요소를 가리키는 반복자를 반환합니다.

범위의 요소 삭제: erase() 함수는 삭제할 범위 뒤의 요소를 가리키는 반복자를 반환합니다.

2) 따라서:

단일 요소 삭제: erase() 함수는 삭제된 요소 뒤의 요소를 가리키는 반복자를 반환합니다.

범위의 요소 삭제: erase() 함수는 삭제할 범위 뒤의 요소를 가리키는 반복자를 반환합니다.

3) 설정 및 지도:

단일 요소 삭제: erase() 함수는 삭제된 요소 뒤의 요소를 가리키는 반복자를 반환합니다.

요소 범위 삭제: erase() 함수는 반복자를 반환하지 않습니다.

set 및 map의 경우 범위의 요소를 삭제할 때 erase() 함수는 반복자를 반환하지 않습니다. 이러한 컨테이너는 순서가 지정되어 있고 범위를 삭제한 후 후속 요소의 위치가 자동으로 조정되기 때문입니다.
erase() 함수를 사용한 후에는 잘못된 이터레이터를 사용하지 않도록 이터레이터의 위치를 ​​신중하게 처리해야 합니다.

벡터 컨테이너는 컬렉션을 사용합니다.

std::vector, C++ 표준 라이브러리의 문자열 클래스이며 메모리는 일반적으로 힙에 할당됩니다.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//自定义类
class person{
    
    
public:
    person(int age,float high){
    
    
        this->age=age;
        this->high=high;
        cout<<"对象建立成功!"<<endl;
    }
    void printself(){
    
    
        cout<<"我的年龄是"<<this->age<<endl;
        cout<<"我的身高是"<<this->high<<endl;
    }
    ~person(){
    
    
        cout<<"对象已经被销毁!"<<endl;
    }
private:
    int age;
    float high;
};
//0.vector的三种遍历方式

//vector第三种遍历方式需要传入for_each的打印函数
void print3(int val){
    
    
    cout<<val<<" ";
}
//vector遍历方式1
void printVector(vector<int> v){
    
    
    vector<int>::iterator begin=v.begin();
    vector<int>::iterator end=v.end();
    while(begin!=end){
    
    
        cout<<*begin<<" ";//相当于是解引用
        begin++;
    }
    cout<<endl;
}
// vector遍历方式2(比较常用)
void printVector2(vector<int> v) {
    
    

	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}
// vector遍历方式3(使用STL提供的算法)
void printVector3(vector<int> v){
    
    
    for_each(v.begin(),v.end(),print3);
    cout<<endl;
}

int main(){
    
    

    //vector基础操作指令集(以int为例)
    //1.构造方式4种
    vector<int> v1;//无参构造方式
    
	for (int i = 0; i < 10; i++)
	{
    
    
		v1.push_back(i);
	}
	printVector(v1);
    // printVector2(v1);
    // printVector3(v1);
	vector<int> v2(v1.begin(), v1.end());//使用迭代器范围构造
	printVector(v2);

	vector<int> v3(10, 100);//使用重载的构造函数构造
	printVector(v3);
	
	vector<int> v4(v3);//使用拷贝构造函数构造,属于深拷贝(vector的赋值就是深拷贝)
	printVector(v4);

    //2.赋值方式
    vector<int> v5;
    v5=v1;//直接赋值操作,也是深拷贝,和前面vector<int> v4(v3)比较像
    //但是使用拷贝构造函数的方式更为直接和简洁,而赋值操作需要先创建空对象再进行赋值。
 
    vector<int> v6;
    v6.assign(v1.begin(), v1.end());//assign迭代器赋值方式

    vector<int> v7;
    v7.assign(10,100);//assign重载赋值方式
    //3.容器和大小
    if(v1.empty()){
    
    
        cout<<"动态数组1为空!"<<endl;
    }
    else{
    
    
        cout<<"动态数组1不为空!"<<endl;
        cout<<"v1的容量是:"<<v1.capacity()<<endl;//是动态变化的 比容器现在的大小大一些
        cout<<"v1的大小是"<<v1.size()<<endl;//现在的大小
    }
    //4.插入和删除
    v1.push_back(11);//尾插
    v1.pop_back();//尾删
    v1.insert(v1.begin(),100);//指定地方插入1个元素
    v1.insert(v1.begin(),2,100);//指定地方插入多个元素
    // printVector(v1);
    v1.erase(v1.begin());//删除元素
    // printVector(v1);
    v1.erase(v1.begin(),v1.end());//清空方式1
    v1.clear();//清空方式2
    // if(v1.empty()){
    
    
    //     cout<<"动态数组1为空!"<<endl;
    // }
    
    //5.数据存取
    cout<<v1[0]<<" ";//类似数组方法
    cout<<v2.at(0)<<" ";//at方法
    cout<<v3.front()<<" ";//取第一个元素
    cout<<v4.back()<<" ";//取最后一个元素
    cout<<endl;
    //6.容器元素互换
    cout<<"交换前"<<endl;
    printVector(v5);
    printVector(v3);
    v5.swap(v3);
    cout<<"交换后"<<endl;
    printVector(v5);
    printVector(v3);
    //7.预留空间
    v1.reserve(100000);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
    
    return 0;
}

최종 결과:

[외부 링크 이미지 전송 실패, 소스 사이트에 거머리 방지 메커니즘이 있을 수 있습니다. 이미지를 저장하고 직접 업로드하는 것이 좋습니다. (img-VNdg4hJ0-1690345543433) typora-user-images\ image-20230720200548128.png)]

Deque 컨테이너는 컬렉션을 사용합니다.

std::string, C++ 표준 라이브러리의 문자열 클래스이며 메모리는 일반적으로 힙에 할당됩니다.

#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;

// 0.双端数组的遍历操作
void printDeque(const deque<int>& d) 
//用const是为了防止改变传入对象的状态
//使用&是为了避免重复复制的开销
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}

int main()
{
    
    
	//deque基础操作指令集(以int为例)
    //1.构造方式
    deque<int> d1; //无参构造函数
	for (int i = 0; i < 10; i++)
	{
    
    
		d1.push_back(i);
	}
	printDeque(d1);
	deque<int> d2(d1.begin(),d1.end());//构造函数将[beg, end)区间中的元素拷贝给本身。
	printDeque(d2);

	deque<int>d3(10,100); //构造函数将n个elem拷贝给本身。
	printDeque(d3);

	deque<int>d4 = d3;//拷贝构造函数的一种形式
    //另外一种deque<int>d4(d3)
	printDeque(d4);

    //2.赋值操作
    deque<int> d21;
	for (int i = 0; i < 10; i++)
	{
    
    
		d21.push_back(i);
	}
	printDeque(d21);

	deque<int>d22;
	d22 = d21; //重载等号操作符
	printDeque(d22);

	deque<int>d23;
	d23.assign(d21.begin(), d21.end()); //将[beg, end)区间中的数据拷贝赋值给本身。
	printDeque(d23);

	deque<int>d24;
	d24.assign(10, 100);//将n个elem拷贝赋值给本身。
	printDeque(d24);

    //3.容器大小操作
    deque<int> d31;
	for (int i = 0; i < 10; i++)
	{
    
    
		d31.push_back(i);
	}
	printDeque(d31);

	//判断容器是否为空
	if (d31.empty()) {
    
    
		cout << "d31为空!" << endl;
	}
	else {
    
    
		cout << "d31不为空!" << endl;
		//统计大小
		cout << "d31的大小为:" << d31.size() << endl;
	}

	//重新指定大小
	d31.resize(15, 1);
    //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
	printDeque(d31);

	d31.resize(5);
    //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
	printDeque(d31);

    //4.插入和删除
    deque<int> d41;
	//尾插
	d41.push_back(10);
	d41.push_back(20);
	//头插
	d41.push_front(100);
	d41.push_front(200);

	printDeque(d41);

	//尾删
	d41.pop_back();
	//头删
	d41.pop_front();
	printDeque(d41);
    deque<int> d42;
	d42.push_back(10);
	d42.push_back(20);
	d42.push_front(100);
	d42.push_front(200);
	printDeque(d42);

	d42.insert(d42.begin(), 1000);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
	printDeque(d42);

	d42.insert(d42.begin(), 2,10000);//在pos位置插入n个elem数据,无返回值。
	printDeque(d42);

	deque<int>d43;
	d43.push_back(1);
	d43.push_back(2);
	d43.push_back(3);

	d43.insert(d43.begin(), d43.begin(), d43.end()); //在pos位置插入[beg,end)区间的数据,无返回值。
	printDeque(d43);
    deque<int> d44;
	d44.push_back(10);
	d44.push_back(20);
	d44.push_front(100);
	d44.push_front(200);
	printDeque(d44);

	d44.erase(d44.begin());
	printDeque(d44); //删除pos位置的数据,返回下一个数据的位置。

	d44.erase(d44.begin(), d44.end()); //删除[beg,end)区间的数据,返回下一个数据的位置。
	d44.clear(); //清空容器的所有数据
	printDeque(d44);

    //5.数据存取
    deque<int> d5;
	d5.push_back(10);
	d5.push_back(20);
	d5.push_front(100);
	d5.push_front(200);

	for (int i = 0; i < d5.size(); i++) {
    
    
		cout << d5[i] << " ";
	}
	cout << endl;


	for (int i = 0; i < d5.size(); i++) {
    
    
		cout << d5.at(i) << " ";
	}
	cout << endl;

	cout << "front:" << d5.front() << endl;

	cout << "back:" << d5.back() << endl;
    
    //6.排序
	deque<int> d6;
	d6.push_back(10);
	d6.push_back(20);
	d6.push_front(100);
	d6.push_front(200);

	printDeque(d6);
	sort(d6.begin(), d6.end());//算法库实现
	printDeque(d6);

    return 0;
}

최종 결과:

[외부 링크 사진 전송 실패, 소스 사이트에 도난 방지 링크 메커니즘이 있을 수 있으므로 사진을 저장하고 직접 업로드하는 것이 좋습니다. (img-J6IJ6pn5-1690345543433) \typora-user-images\ image-20230721114404666.png)]

Deque 컨테이너와 Vector 컨테이너의 차이점은 무엇입니까?

Deque 컨테이너와 벡터 컨테이너는 내부 구현과 사용법이 약간 다른 두 가지 컨테이너 유형입니다.

  1. 내부 구현: deque 컨테이너는 여러 개의 연속 버퍼로 구성된 양방향 배열(양단 대기열이라고도 함)이며 각 버퍼는 여러 요소를 저장할 수 있습니다. 벡터 컨테이너는 요소를 메모리에 연속적으로 저장하는 동적 배열입니다.
  2. 삽입 및 삭제 작업: deque 컨테이너 양쪽 끝에서 삽입 및 삭제 작업의 시간 복잡도는 O(1)인 반면 벡터 컨테이너 끝에서 삽입 및 삭제 작업의 시간 복잡도는 O(1)이지만 삽입과 삭제의 시간복잡도는 O(n)이다. 왜냐하면 다른 요소를 옮겨야 하기 때문이다.
  3. 액세스 요소: deque 컨테이너와 벡터 컨테이너 모두 임의 액세스를 지원합니다. 즉, 요소는 첨자를 통해 직접 액세스할 수 있습니다. 그러나 벡터 컨테이너의 요소가 메모리에 연속적으로 저장되므로 벡터 컨테이너의 임의 액세스 속도가 더 빠릅니다. deque 컨테이너이건 vector 컨테이너이건 요소의 첨자를 알면 요소 에 접근하는 시간복잡도 는 O(1) 이다 .
  4. 内存分配:deque容器在内部使用多个缓冲区,每个缓冲区的大小可以根据需要动态调整。vector容器分配的内存空间是连续的,当容器大小增加时,可能需要重新分配更大的内存空间,并将原有元素复制到新的内存空间。

根据具体的使用场景和需求,选择deque容器还是vector容器会有所不同。如果需要在容器的两端频繁进行插入和删除操作,并且不需要频繁的随机访问元素,可以选择deque容器。如果需要频繁的随机访问元素,并且在尾部进行插入和删除操作,可以选择vector容器。

讲一讲deque容器的工作原理,缓冲区是什么,中控器又是什么?

deque(双端队列)是一种由多个连续的缓冲区组成的容器,它的内部工作原理涉及到缓冲区和中控器的概念。

缓冲区是deque容器内部的存储单元,它是一块连续的内存空间,用于存储元素。每个缓冲区都有固定的大小,可以容纳一定数量的元素。当我们向deque容器的头部或尾部插入元素时,元素会被存储在相应的缓冲区中。

中控器是deque容器的核心,它包含了一些重要的信息,用于管理和控制缓冲区。中控器维护了一个指向首缓冲区和尾缓冲区的指针,以及一个指向当前活动缓冲区的指针。中控器还记录了当前使用的缓冲区数量、缓冲区的起始地址和大小等信息。

当我们向deque容器的头部或尾部插入元素时,中控器会根据当前活动缓冲区的情况来进行相应的操作。如果当前活动缓冲区还有足够的空间,插入操作会直接在当前活动缓冲区进行,时间复杂度为O(1)。如果当前活动缓冲区已满,中控器会创建一个新的缓冲区,并将其插入到首部或尾部,然后将元素插入到新的缓冲区中。

当我们从deque容器的头部或尾部删除元素时,中控器也会根据当前活动缓冲区的情况来进行相应的操作。如果当前活动缓冲区还有元素,删除操作会直接在当前活动缓冲区进行,时间复杂度为O(1)。如果当前活动缓冲区为空,中控器会将其从deque容器中移除,并将首缓冲区或尾缓冲区作为新的活动缓冲区。

중앙 컨트롤러의 관리를 통해 deque 컨테이너는 양 끝에서 효율적인 삽입 및 삭제 작업을 구현할 수 있으며 요소에 대한 임의 액세스를 지원합니다. deque 컨테이너 내부의 버퍼는 블록에 저장되기 때문에 다양한 요구에 맞게 버퍼 크기를 동적으로 조정할 수 있습니다. 이로 인해 일부 시나리오에서는 deque 컨테이너가 벡터 컨테이너보다 더 적합합니다.

deque.begin()은 deque.front()와 동일합니까?

deque.begin()deque 컨테이너의 첫 번째 요소를 가리키는 반복자를 반환하는 멤버 함수입니다.

deque.front()또한 deque 컨테이너의 첫 번째 요소에 대한 참조를 반환하는 멤버 함수입니다.

(다른 컨테이너도 비슷한 답변이 있습니다)

문자열 컨테이너에 의해 할당된 메모리가 연속적입니까?

예, std::string 컨테이너 내부에 할당된 메모리는 연속적입니다. C++ 표준 라이브러리에서 std::string은 일반적으로 동적으로 할당된 연속 메모리를 사용하여 문자열 데이터를 저장합니다.
특히 std::string은 문자열의 문자 데이터를 저장하기 위해 힙에 연속 메모리를 동적으로 할당합니다. 이는 문자열의 문자가 메모리에 순차적으로 배열되고 포인터와 오프셋을 통해 효율적으로 액세스할 수 있음을 의미합니다. (랜덤 액세스)
std::string의 길이가 현재 할당된 메모리 크기를 초과하면 더 큰 메모리 블록을 재할당하고 원래 문자 데이터를 새 메모리에 복사할 수 있습니다. 이 프로세스를 동적 메모리 재할당이라고 하지만 연속 메모리의 특성은 그대로 유지합니다.

문자열 컨테이너는 컬렉션을 사용합니다.

std::string, C++ 표준 라이브러리의 문자열 클래스이며 메모리는 일반적으로 힙에 할당됩니다.

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int main(){
    
    
    //string基础操作指令集(以int为例)
    //1.构造方式4种
    string s1="hello1";//无参构造方式
    cout<<"s1="<<s1<<endl;

    const char* str="hello2";
    string s2(str);//将C语言风格字符串转换为C++风格字符串
    cout<<"s2="<<s2<<endl;
    string s3(s2);//调用拷贝构造函数 深拷贝
    cout<<"s3="<<s3<<endl;

    string s4(10,'a');//使用重载的构造函数
    cout<<"s4="<<s4<<endl;

    //2.赋值方式
    string str1; //char*类型字符串 赋值给当前的字符串
	str1 = "hello world";
	cout << "str1 = " << str1 << endl;

	string str2;
	str2 = str1;//把字符串s赋给当前的字符串
	cout << "str2 = " << str2 << endl;

	string str3;//字符赋值给当前的字符串
	str3 = 'a';
	cout << "str3 = " << str3 << endl;

	string str4; //把字符串s赋给当前字符串
	str4.assign("hello c++");
	cout << "str4 = " << str4 << endl;

	string str5;
	str5.assign("hello c++",5);//把字符串s的前n个字符赋给当前的字符串
	cout << "str5 = " << str5 << endl;

	string str6;
	str6.assign(str5);//把字符串s赋给当前字符串 
    // 和str4的方法很相似 str4输入的参数是const char *s  str6输入的参数是const string &s
	cout << "str6 = " << str6 << endl;

	string str7;
	str7.assign(5, 'x'); //用n个字符c赋给当前字符串
	cout << "str7 = " << str7 << endl;
    //3.字符串拼接
    string str31 = "我";
	str31 += "爱玩游戏";//重载+=操作符string& operator+=(const char* str);
	cout << "str31 = " << str31 << endl;
	str31 += ':';//重载+=操作符 string& operator+=(const char c);
	cout << "str31 = " << str31 << endl;
	string str32 = "LOL DNF";
	str31 += str32;//重载+=操作符`string& operator+=(const string& str);`      
	cout << "str31 = " << str31 << endl;
	string str33 = "I";
	str33.append(" love ");//把字符串s连接到当前字符串结尾
	str33.append("game abcde", 4);//把字符串s的前n个字符连接到当前字符串结尾
	//str3.append(str2);
	str33.append(str32, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
	cout << "str33 = " << str33 << endl;
    
    //4.查找和替换
    string str41 = "abcdefgde";
	int pos = str41.find("de");//查找s第一次出现位置,找到了就返回下标(起始位置可以改)
	if (pos == -1)
	{
    
    
		cout << "未找到" << endl;
	}
	else
	{
    
    
		cout << "pos = " << pos << endl;
	}
	pos = str41.rfind("de");//查找s最后一次出现位置
	cout << "pos = " << pos << endl;
    string str42 = "abcdefgde";
	str42.replace(1, 3, "1111");//替换从pos开始的n个字符为字符串s
	cout << "str1 = " << str42 << endl;
    //5.字符串比较
    string s51 = "hello";
	string s52 = "aello";

	int ret = s51.compare(s52);

	if (ret == 0) {
    
    
		cout << "s51 等于 s52" << endl;
	}
	else if (ret > 0)
	{
    
    
		cout << "s51 大于 s52" << endl;
	}
	else
	{
    
    
		cout << "s51 小于 s52" << endl;
	}
    //根据ASCII码表,h的ASCII码值大于a的ASCII码值。
    //如果两个字符串的首字母相同,那么compare()函数会继续比较下一个字符,直到找到不同的字符或者其中一个字符串结束。
    //6.字符存取
    string str61 = "hello world";
	//字符修改
	str61[0] = 'x';//通过[]方式取字符
	str61.at(1) = 'x';  //通过at方法获取字符
	cout << str61 << endl;
    //7.插入和删除
    string str71 = "hello";
	str71.insert(1, "111");//插入字符串
	cout << str71 << endl;

	str71.erase(1, 3);  //从1号位置开始3个字符,删除
	cout << str71 << endl;
    //8.子串
    string str81 = "abcdefg";
	string subStr81 = str81.substr(1, 3);//返回由pos开始的n个字符组成的字符串 pos是第一个参数
	cout << "subStr81 = " << subStr81 << endl;

	string email = "[email protected]";
	int pos2 = email.find("@");
	string username = email.substr(0, pos2);//返回由pos开始的n个字符组成的字符串
	cout << "username: " << username << endl;
    return 0;
}

최종 결과:

[외부 링크 사진 전송 실패, 소스 사이트에 거머리 방지 메커니즘이 있을 수 있으므로 사진을 저장하고 직접 업로드하는 것이 좋습니다. (img-iuy1GsLg-1690345543434) typora-user-images\ image-20230721103712827.png)]

STL의 스택 큐가 나타내는 데이터 구조 소개

std::stack은 다른 컨테이너를 기본 데이터 구조로 사용하고 스택(LIFO) 기능을 제공하는 어댑터 컨테이너입니다. 기본적으로 std::deque(double-ended queue)는 std::stack의 기본 컨테이너로 사용되지만 std::vector 또는 std::list와 같은 컨테이너도 사용할 수 있습니다.

std::stack은 기본 컨테이너의 특성에 따라 효율적인 스택 작업을 제공합니다. 역순 출력, 브래킷 매칭, 깊이 우선 검색 등과 같은 스택 기능이 필요한 시나리오에 적합합니다.

std::queue는 다른 컨테이너를 기본 데이터 구조로 사용하고 대기열(FIFO)의 기능을 제공하는 어댑터 컨테이너이기도 합니다. 기본적으로 std::deque(double-ended queue)는 std::queue의 기본 컨테이너로 사용되지만 std::list와 같은 컨테이너도 사용할 수 있습니다.

std::queue는 기본 컨테이너의 특성에 따라 효율적인 대기열 작업을 제공합니다. 너비 우선 검색, 작업 예약 등과 같은 대기열 기능이 필요한 시나리오에 적합합니다.

어댑터 컨테이너란?

어댑터 컨테이너는 다른 컨테이너를 기본 데이터 구조로 사용 하고 기본 컨테이너의 기능이 다양한 요구에 적응할 수 있도록 하는 특정 인터페이스 집합을 제공하는 특수 컨테이너입니다 .
어댑터 컨테이너는 기본 컨테이너를 캡슐화하여 해당 동작을 변경하거나 특정 요구 사항을 충족하는 새로운 기능을 제공합니다. 개발 프로세스를 단순화하고 더 높은 수준의 추상화를 제공하며 코드를 보다 유연하고 재사용 가능하게 만들 수 있습니다.
STL에서 std::stack 및 std::queue는 어댑터 컨테이너의 예입니다. 기본 데이터 구조로 std::deque와 같은 다른 컨테이너를 사용하고 스택 및 대기열에 대한 기능적 인터페이스를 제공합니다.

예를 들어 std::vector는 다음 구문을 사용하여 std::stack의 기본 컨테이너로 사용할 수 있습니다.

std::stack<int, std::vector<int>> myStack;

이렇게 하면 myStack은 기본 std::deque 대신 기본 컨테이너로 std::vector를 사용합니다.
std::stack의 정의에는 T와 Container라는 두 개의 템플릿 매개변수가 있습니다.

T는 스택에 저장된 요소의 유형입니다. 귀하의 예에서 T는 스택에 저장된 요소가 정수 유형임을 나타내는 int로 지정됩니다.

컨테이너는 기본 컨테이너의 유형입니다. 귀하의 예에서 컨테이너는 std::vector로 지정됩니다. 이는 std::vector를 기본 컨테이너로 사용하여 스택의 기능을 실현한다는 의미입니다.
deque에 이중 끝 목록이 있는 것은 놀라운 일이 아니며 스택 및 대기열의 기능도 구현하는 것으로 밝혀졌습니다.

스택 컨테이너는 컬렉션을 사용합니다.

#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;

int main(){
    
    
    //list基础操作指令集(以int为例)
    stack<int> s;

	//向栈中添加元素,叫做 压栈 入栈
	s.push(10);
	s.push(20);
	s.push(30);

	while (!s.empty()) {
    
    
		//输出栈顶元素
		cout << "栈顶元素为: " << s.top() << endl;
		//弹出栈顶元素
		s.pop();
	}
	cout << "栈的大小为:" << s.size() << endl;
    
    return 0;
}

여기에 이미지 설명 삽입

대기열 컨테이너는 컬렉션을 사용합니다.

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
class Person
{
    
    
public:
	Person(string name, int age)
	{
    
    
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;
};
int main(){
    
    
    //queue基础操作指令集(以int为例)
    //创建队列
	queue<Person> q;

	//准备数据
	Person p1("唐僧", 30);
	Person p2("孙悟空", 1000);
	Person p3("猪八戒", 900);
	Person p4("沙僧", 800);

	//向队列中添加元素  入队操作
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);

	//队列不提供迭代器,更不支持随机访问	
	while (!q.empty()) {
    
    
		//输出队头元素
		cout << "队头元素-- 姓名: " << q.front().m_Name 
              << " 年龄: "<< q.front().m_Age << endl;
        
		cout << "队尾元素-- 姓名: " << q.back().m_Name  
              << " 年龄: " << q.back().m_Age << endl;
        
		cout << endl;
		//弹出队头元素
		q.pop();
	}

	cout << "队列大小为:" << q.size() << endl;

    return 0;
}

여기에 이미지 설명 삽입

어떤 데이터 구조로 구현되는 목록 컨테이너를 소개합니까?

List(linked list)는 C++ 표준 라이브러리의 컨테이너로, 어느 위치에서나 효율적인 삽입 및 삭제 작업을 수행할 수 있는 이중 연결 목록입니다.
목록은 컨테이너의 시작, 끝 또는 중간에 요소를 삽입하고 제거할 때 우수한 성능을 보이는 것이 특징입니다. 연결된 목록의 구조는 배열과 같은 요소를 재할당하고 이동할 필요 없이 일정한 시간에 삽입 및 삭제 작업을 허용하기 때문입니다. (장점)
vector나 deque와 달리 list는 배열처럼 연속적인 메모리 공간이 없기 때문에 요소에 대한 임의 접근을 지원하지 않는다(단점). 목록의 요소에 액세스하려면 순회하는 반복자를 사용해야 합니다. 그리고 양방향 반복자입니다. (컨테이너의 요소를 앞뒤로 탐색할 수 있지만 임의 액세스를 지원하지 않으며 매번 첫 번째 요소부터 액세스를 시작해야 합니다. )
list는 또한 지정된 위치에 요소를 삽입하고 두 개의 Ordered를 병합하는 것과 같은 몇 가지 특수 작업을 제공합니다. 목록, 반전 목록 등 이러한 작업은 요소를 자주 삽입하고 삭제해야 하는 상황과 같은 특정 시나리오에서 매우 유용합니다.
일반적으로 목록은 임의 액세스 없이 요소를 자주 삽입하고 삭제해야 하는 시나리오에 적합한 유연하고 효율적인 컨테이너입니다. 연산 복잡도는 O(1)이나 요소에 접근할 때 연결 리스트 전체를 순회해야 하므로 성능 면에서 vector나 deque만큼 좋지 않을 수 있다.

동적 저장소 할당에 속하는 이중 연결 목록과 같은 데이터 구조로 구현됩니다.

목록 컨테이너는 컬렉션을 사용합니다.

#include<iostream>
#include<list>
#include<algorithm>
using namespace std;

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}
bool myCompare(int val1 , int val2)
{
    
    
	return val1 > val2;
}//自定义排序规则
int main(){
    
    
    //list基础操作指令集(以int为例)
    //1.构造方式
    list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	printList(L1);

	list<int>L2(L1.begin(),L1.end());
	printList(L2);

	list<int>L3(L2);
	printList(L3);

	list<int>L4(10, 1000);
	printList(L4);
    //2.赋值和交换
    list<int>L21;
	L21.push_back(10);
	L21.push_back(20);
	L21.push_back(30);
	L21.push_back(40);
	printList(L21);

	//赋值
	list<int>L22;
	L22 = L21;
	printList(L22);

	list<int>L23;
	L23.assign(L22.begin(), L22.end());
	printList(L23);

	list<int>L24;
	L24.assign(10, 100);
	printList(L24);
    //交换
    list<int>L25;
	L25.push_back(10);
	L25.push_back(20);
	L25.push_back(30);
	L25.push_back(40);

	list<int>L26;
	L26.assign(10, 100);

	cout << "交换前: " << endl;
	printList(L25);
	printList(L26);

	cout << endl;

	L25.swap(L26);

	cout << "交换后: " << endl;
	printList(L25);
	printList(L26);
    //3.大小操作
    list<int>L31;
	L31.push_back(10);
	L31.push_back(20);
	L31.push_back(30);
	L31.push_back(40);

	if (L31.empty())
	{
    
    
		cout << "L31为空" << endl;
	}
	else
	{
    
    
		cout << "L31不为空" << endl;
		cout << "L31的大小为: " << L31.size() << endl;
	}

	//重新指定大小
	L31.resize(10);
	printList(L31);

	L31.resize(2);
	printList(L31);

    //4.插入和删除
    cout<<"插入和删除演示"<<endl;
    list<int> L41;
	//尾插
	L41.push_back(10);
	L41.push_back(20);
	L41.push_back(30);
	//头插
	L41.push_front(100);
	L41.push_front(200);
	L41.push_front(300);

	printList(L41);

	//尾删
	L41.pop_back();
	printList(L41);

	//头删
	L41.pop_front();
	printList(L41);

	//插入
	list<int>::iterator it = L41.begin();
	L41.insert(++it, 1000);
	printList(L41);

	//删除
	it = L41.begin();
	L41.erase(++it);
	printList(L41);

	//移除
	L41.push_back(10000);
	L41.push_back(10000);
	L41.push_back(10000);
	printList(L41);
	L41.remove(10000);
	printList(L41);
    
    //清空
	L41.clear();
	printList(L41);
    
    //5.数据存取
    list<int>L51;
	L51.push_back(10);
	L51.push_back(20);
	L51.push_back(30);
	L51.push_back(40);

	
	//cout << L51.at(0) << endl;//错误 不支持at访问数据
	//cout << L51[0] << endl; //错误  不支持[]方式访问数据
	cout << "第一个元素为: " << L51.front() << endl;
	cout << "最后一个元素为: " << L51.back() << endl;

	//list容器的迭代器是双向迭代器,不支持随机访问
	list<int>::iterator it11 = L51.begin();
	//it = it + 1;//错误,不可以跳跃访问,即使是+1
    
    //6.反转和排序
    list<int> L6;
	L6.push_back(90);
	L6.push_back(30);
	L6.push_back(20);
	L6.push_back(70);
	printList(L6);

	//反转容器的元素
	L6.reverse();
	printList(L6);

	//排序
	L6.sort(); //默认的排序规则 从小到大
	printList(L6);

	L6.sort(myCompare); //指定规则,从大到小
    //注意,这是类的成员函数sort,和算法库的sort不一样
	printList(L6);
    
    
    return 0;
}

여기에 이미지 설명 삽입

vector deque string list stack queue 공통 함수의 시간 복잡도에 대해 알려주세요.

vector다음은 , deque각각의 시간 복잡도 에 대한 요약 입니다 string.list

vector:

  • 시간 복잡도:
    • 랜덤 액세스: O(1)
    • 삽입 및 삭제(끝 이외의 위치에서): O(n)
    • 삽입 및 삭제(끝 위치에서): 상각 O(1) (대략 O(1))

deque:

  • 시간 복잡도:
    • 랜덤 액세스: O(1)
    • 삽입 및 삭제(처음과 끝에서): O(1)
    • 삽입 및 삭제(가운데): O(n)

string:

  • 시간 복잡도:
    • 랜덤 액세스: O(1)
    • 삽입 및 삭제(끝 이외의 위치에서): O(n)
    • 삽입 및 삭제(종료 위치에서): 상각 O(1)

list:

  • 시간 복잡도:
    • 랜덤 액세스: O(n)
    • 삽입과 삭제: O(1)

stack:

  • 시간 복잡도:
    • 삽입 및 삭제(스택 상단에서): O(1)
    • 스택의 최상위 요소에 액세스: O(1)

queue:

  • 시간 복잡도:
    • 삽입 및 삭제(꼬리 및 머리에서): O(1)
    • 헤드 요소에 대한 액세스: O(1)

STL에는 여러 유형의 반복자가 있습니다.

표준 템플릿 라이브러리(STL)는 다양한 컨테이너 및 알고리즘의 요구에 맞는 다양한 유형의 반복자를 제공합니다. 다음은 STL의 일반적인 반복자 유형입니다.

입력 반복자(Input Iterator): 컨테이너의 요소에 대한 읽기 전용 액세스에 사용됩니다. 컨테이너를 순회하기 위해 하나씩 증분하는 것을 지원하며 역참조 연산자( * )를 사용하여 요소의 값을 가져올 수 있습니다.

출력 반복자(Output Iterator): 쓰기 전용 작업의 경우 요소를 컨테이너에 삽입할 수 있습니다. 컨테이너를 트래버스하기 위해 하나씩 증분하는 것을 지원하고 역참조 연산자를 사용하여 요소의 값을 설정할 수 있습니다.

순방향 반복자(Forward Iterator): 입력 반복자와 유사하지만 다중 증가 및 역참조 작업을 지원합니다. 컨테이너를 여러 번 순회하는 데 사용할 수 있으며 순회 중에 컨테이너의 요소를 수정할 수 있습니다.

양방향 반복자(Bidirectional Iterator): 정방향 반복자와 유사하지만 감소 연산을 지원합니다. 컨테이너를 앞뒤로 순회 할 수 있으며 순회 중에 컨테이너의 요소를 수정할 수 있습니다.

임의 액세스 반복자(Random Access Iterator): ** 임의 액세스, 증가, 감소 및 산술 연산을 지원하는 가장 강력한 반복자 유형입니다. ** 일정한 시간에 컨테이너의 임의 요소에 액세스할 수 있으며 포인터와 같은 산술 연산을 지원합니다.

STL의 컨테이너 및 알고리즘은 종종 제대로 작동하는지 확인하기 위해 필요한 반복자 유형을 지정합니다.

벡터 deque 문자열 목록 스택 대기열 세트 맵에 사용되는 이터레이터는 무엇입니까?

STL에서 다른 컨테이너 유형은 다른 유형의 반복자를 사용합니다. 다음은 일반적인 컨테이너 유형과 해당 반복기 유형입니다.

  • 벡터: Random Access Iterator(Random Access Iterator)를 사용합니다. 벡터는 일정 시간 임의 액세스를 지원하므로 임의 액세스 반복자를 사용하여 요소에 효율적으로 액세스하고 수정할 수 있습니다.
  • deque: Random Access Iterator(Random Access Iterator)를 사용합니다. 벡터와 마찬가지로 deque도 일정 시간 임의 액세스를 지원합니다.
  • string: Random Access Iterator(Random Access Iterator)를 사용합니다. 문자열은 기본적으로 문자 시퀀스이므로 배열과 같은 임의 액세스 반복자를 사용하여 문자에 액세스하고 수정할 수 있습니다.
  • 목록: 양방향 반복기(Bidirectional Iterator)를 사용합니다. 목록은 이중 연결 목록이고 양방향 순회만 지원하므로 양방향 반복기를 사용하여 목록의 요소를 순회하고 수정할 수 있습니다.
  • 스택: 반복자는 지원되지 않습니다. 스택은 순회 없이 스택 맨 위에서만 삽입 및 삭제를 허용하는 후입선출(LIFO) 데이터 구조입니다.
  • 대기열: 반복자는 지원되지 않습니다. 큐는 순회 없이 큐의 한쪽 끝에서만 삽입하고 다른 쪽 끝에서는 삭제할 수 있는 선입선출(FIFO) 데이터 구조입니다.
  • set: 양방향 반복자(Bidirectional Iterator)를 사용합니다. 세트는 순서가 있고 반복되지 않는 컬렉션이며 세트의 요소는 양방향 반복기를 사용하여 순회하고 수정할 수 있습니다.
  • map: 양방향 반복자(Bidirectional Iterator)를 사용합니다. 맵은 키-값 쌍의 모음이며 맵의 요소는 양방향 반복기를 사용하여 순회하고 수정할 수 있습니다.

위의 반복자 유형은 일반적인 경우일 뿐이며 구체적인 구현은 다를 수 있습니다. 또한 C++11에서는 순방향 반복기(Forward Iterator) 및 입력 반복기(Input Iterator)와 같은 더 많은 반복기 유형을 도입하여 보다 유연한 반복 작업을 지원합니다.

RAII(Resource Acquisition Is Initialization)에 대해 이야기하기(자원 획득이 초기화)

RAII(Resource Acquisition Is Initialization)는 C++에서 리소스 획득 및 해제를 관리하기 위한 프로그래밍 기술입니다. 객체의 생성자에서 자원을 획득하고 객체의 소멸자에서 자원을 해제하여 자원의 올바른 해제를 보장하는 객체 생명주기에 기반한 관리 방법입니다.

이점은 다음과 같습니다.

  1. 간소화된 리소스 관리: 개체의 수명 주기에 리소스 획득 및 릴리스를 연결하여 수동으로 리소스를 관리하는 복잡성을 피할 수 있습니다.

  2. 리소스 누수 방지: 리소스 해제는 소멸자에서 이루어지므로 비정상적인 상황에서도 리소스를 올바르게 해제하여 리소스 누수를 방지할 수 있습니다.

  3. 예외 안전성: RAII를 사용하여 리소스를 관리할 때 예외가 발생하더라도 개체의 소멸자가 호출되어 리소스의 올바른 해제를 보장하고 더 나은 예외 안전성을 제공합니다.

  4. 코드 가독성 및 유지 관리성 향상: RAII는 개체에 리소스 획득 및 릴리스 논리를 캡슐화하여 코드를 보다 명확하고 간결하며 이해하기 쉽게 만듭니다.

구현:

1) 스마트 포인터는 RAII를 구현하는 중요한 도구입니다. std::unique_ptr, std::shared_ptr및 와 같은 여러 스마트 포인터 클래스가 C++ 표준 라이브러리에서 제공됩니다 std::weak_ptr. 이러한 스마트 포인터 클래스는 포인터를 캡슐화하고 개체 수명 주기가 끝나면 포인터가 가리키는 리소스를 자동으로 해제합니다.

2) 범위 기반 리소스 관리: C++에서는 범위의 특성을 사용하여 리소스를 관리할 수 있습니다. 간단한 RAII는 범위 내에서 개체를 만들고 개체의 소멸자에서 리소스를 해제하여 달성할 수 있습니다. 예를 들어 로컬 개체, 임시 개체 또는 함수 내부 클래스를 사용하여 리소스를 관리합니다.

3) RAII 클래스: 전용 RAII 클래스를 생성하여 리소스를 관리할 수 있습니다. 이 클래스의 생성자는 리소스 획득을 담당하고 소멸자는 리소스 해제를 담당합니다. 이 RAII 클래스의 개체를 사용하면 개체 수명이 끝날 때 리소스가 적절하게 해제되도록 할 수 있습니다.

4) 파일 핸들 캡슐화: 파일 리소스에 대해 파일 핸들을 캡슐화하는 클래스를 만들 수 있습니다.클래스의 생성자는 파일을 열고 소멸자는 파일을 닫습니다. 이러한 방식으로 개체의 수명 주기가 끝나면 파일 핸들이 자동으로 닫힙니다.

5) 잠금 자동 해제: 다중 스레드 프로그래밍에서 뮤텍스 또는 세마포어와 같은 동기화 프리미티브를 사용하여 공유 리소스를 보호할 수 있습니다. RAII 클래스에서 잠금 획득 및 해제 작업을 캡슐화하면 개체 수명 주기가 종료될 때 잠금이 자동으로 해제되어 교착 상태 및 리소스 누수를 방지할 수 있습니다.

scoped_ptr6) 적절한 리소스 관리 라이브러리: 및 Boost 라이브러리 와 같은 고급 리소스 관리 기능을 제공하는 일부 타사 라이브러리가 있습니다 scoped_array. 이러한 라이브러리는 리소스 관리 작업을 단순화하기 위해 더 많은 RAII 클래스 및 도구를 제공합니다.

집합 컨테이너를 소개하고 집합과 다중 집합의 차이점에 대해 이야기하고,

set은 C++ 표준 라이브러리의 컨테이너이며 std::set의 중국어 이름은 컬렉션 입니다 . 고유한 요소를 저장하는 방법을 제공합니다. 즉, 각 요소는 집합에서 고유하며 중복되지 않습니다.
집합 컨테이너는 요소를 저장하고 정렬하기 위해 내부적으로 Red-Black Tree(Red-Black Tree) 데이터 구조를 사용합니다. 레드-블랙 트리는 삽입, 삭제 및 조회 성능이 우수한 자체 균형 이진 검색 트리입니다.
세트 컨테이너의 특징은 다음과 같습니다.

고유성: 세트의 요소는 고유하며 중복 요소가 없습니다 .

자동 정렬: 세트의 요소는 특정 정렬 규칙에 따라 정렬되며 기본값은 오름차순으로 정렬하는 것입니다.

빠른 삽입, 삭제 및 검색: 기본 레드-블랙 트리가 사용되기 때문에 세트 컨테이너는 O(logN)의 시간 복잡성으로 빠른 삽입, 삭제 및 검색 작업을 제공합니다.

반복자 지원: 반복자는 집합 컨테이너의 요소를 순회하는 데 사용할 수 있습니다.

수정이 지원되지 않음: 설정된 컨테이너의 요소를 수정할 수 없습니다.요소를 수정해야 하는 경우 먼저 삭제한 다음 삽입해야 합니다. (수정이 필요한 요소를 찾으려면 set 컨테이너에서 제공하는 멤버 함수(예: find)를 사용하고, 컨테이너에서 요소를 삭제하려면 set 컨테이너에서 제공하는 멤버 함수(예: erase)를 사용합니다. 값을 수정합니다. 설정된 컨테이너에서 제공하는 멤버 함수(예: 삽입)를 사용하여 수정된 요소를 컨테이너에 다시 삽입합니다.)

차이점:

set과 multiset은 모두 C++ 표준 라이브러리에서 제공하는 컨테이너로 **둘 다 red-black tree를 기반으로 구현되며** 요소 집합을 저장하는 데 사용됩니다. 그들 사이의 주요 차이점은 요소의 고유성과 반복입니다.

세트 컨테이너: 세트 컨테이너의 요소는 고유합니다. 즉, 각 요소는 한 번만 나타날 수 있습니다. 이미 존재하는 요소를 삽입하려고 하면 삽입 작업이 되지 않습니다. 설정된 컨테이너는 요소의 값에 따라 자동으로 정렬되며 삽입, 삭제 및 검색 작업을 빠르게 수행할 수 있습니다.

다중 집합 컨테이너: 다중 집합 컨테이너의 요소는 반복을 허용합니다 . 즉, 동일한 요소가 여러 번 나타날 수 있습니다. multiset 컨테이너는 요소의 값에 따라 정렬되며 삽입, 삭제 및 검색 작업을 빠르게 수행할 수 있습니다. 집합 컨테이너와 달리 다중 집합 컨테이너는 반복 요소를 삽입할 수 있으며 이러한 반복 요소의 순서는 정렬 규칙에 따라 유지됩니다.

따라서 집합 컨테이너는 고유한 요소 집합을 저장하고 빠른 조회를 수행해야 하는 시나리오에 적합하고 다중 집합 컨테이너는 요소 집합을 저장하고 복제를 허용해야 하는 시나리오에 적합합니다.
설정이든 다중 집합이든 모두 삽입, 삭제, 검색 및 반복과 같은 작업을 포함하여 유사한 인터페이스와 기능을 제공합니다. 특정 요구 사항에 따라 적합한 컨테이너를 선택할 수 있습니다.

set과 multiset, unorderedset의 차이점은 무엇입니까?

std::set, std::multisetstd::unordered_set세 가지 컨테이너는 구현 및 특성에 약간의 차이가 있습니다.

  1. 정렬성: 정렬된 컨테이너 std::set이며 std::multiset요소는 해당 값에 따라 정렬됩니다. std::set고유한 요소만 저장할 수 있으며 std::multiset중복 요소는 허용됩니다. std::unordered_set정렬되지 않은 컨테이너이며 요소의 순서는 불확실합니다.
  2. 기본 구현: std::set일반적 std::multiset으로 요소의 순서를 유지하는 데이터 구조인 레드-블랙 트리(Red-Black Tree)를 사용하여 구현됩니다. std::unordered_set보통 해시 테이블(Hash Table)을 사용(해시 맵)
  3. ), 이 데이터 구조는 해시 함수를 통해 요소를 버킷에 매핑하여 빠른 삽입, 삭제 및 조회 작업을 가능하게 합니다.
  4. 시간 복잡도: std::set삽입 , 삭제 및 조회 작업의 평균 시간 복잡도가 다릅니다 std::multiset. 의 평균 시간 복잡도는 O(log n)이고 평균 시간 복잡도는 일정 시간 O(1)입니다. 그러나 최악의 경우 선형 시간 O(n)에 도달하는 것이 가능합니다. (처음 두 개가 느린 이유는 트리 자체를 찾는 것이 더 느리기 때문일 수 있습니다)std::unordered_setstd::setstd::multisetstd::unordered_setstd::unordered_set
  5. 요소 순서: std::setstd::multiset요소의 값에 따라 정렬되므로 요소의 순서가 결정됩니다. std::unordered_set요소가 정렬되지 않았으므로 요소의 순서가 정의되지 않습니다.

필요에 따라 적합한 컨테이너 유형을 선택할 수 있습니다. 순서와 고유성이 필요한 경우 std::set또는 를 선택할 수 있습니다 std::multiset. 삽입, 삭제 및 조회 속도가 더 중요하고 순서가 필요하지 않은 경우 를 선택할 수 있습니다 std::unordered_set.

레드-블랙 트리에 대해 이야기하고 기본 원칙에 대해 이야기하십시오.

설정된 컨테이너는 컬렉션을 사용합니다.

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
//自定义数据类型
class Person
{
    
    
public:
	Person(string name, int age)
	{
    
    
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;

};
//set自定义排序方法MyCompare(针对内置数据类型)
//下面用仿函数实现的
class MyCompare 
{
    
    
public:
	bool operator()(int v1, int v2) {
    
    
		return v1 > v2;
	}
};
//set自定义排序方法MyCompare(针对自定义数据类型)
//下面用仿函数实现的
class comparePerson
{
    
    
public:
	bool operator()(const Person& p1, const Person &p2)
	{
    
    
		//按照年龄进行排序  降序
		return p1.m_Age > p2.m_Age;
	}
};
void printSet(set<int> & s)
{
    
    
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main(){
    
    

    //set基础操作指令集(以int为例)
    //1.构造方式
    set<int> s1;
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	printSet(s1);
	//拷贝构造
	set<int>s2(s1);
	printSet(s2);
	//赋值
	set<int>s3;
	s3 = s2;
	printSet(s3);

    //2.求大小和交换
    set<int> s21;
	
	s21.insert(10);
	s21.insert(30);
	s21.insert(20);
	s21.insert(40);

	if (s21.empty())
	{
    
    
		cout << "s21为空" << endl;
	}
	else
	{
    
    
		cout << "s21不为空" << endl;
		cout << "s21的大小为: " << s21.size() << endl;
	}
    //交换
    set<int> s22;

	s22.insert(10);
	s22.insert(30);
	s22.insert(20);
	s22.insert(40);

	set<int> s23;

	s23.insert(100);
	s23.insert(300);
	s23.insert(200);
	s23.insert(400);

	cout << "交换前" << endl;
	printSet(s22);
	printSet(s23);
	cout << endl;

	cout << "交换后" << endl;
	s22.swap(s23);
	printSet(s22);
	printSet(s23);
    

	//3.插入和删除
	set<int> s31;
	//插入
	s31.insert(10);
	s31.insert(30);
	s31.insert(20);
	s31.insert(40);
	printSet(s31);

	//删除
	s31.erase(s31.begin());
	printSet(s31);

	s31.erase(30);
	printSet(s31);

	//清空
	//s1.erase(s1.begin(), s1.end());
	s31.clear();
	printSet(s31);
	//4.查找和统计
	set<int> s41;
	//插入
	s41.insert(10);
	s41.insert(30);
	s41.insert(20);
	s41.insert(40);
	
	//查找
	set<int>::iterator pos = s41.find(30);

	if (pos != s41.end())
	{
    
    
		cout << "找到了元素 : " << *pos << endl;
	}
	else
	{
    
    
		cout << "未找到元素" << endl;
	}

	//统计
	int num = s41.count(30);
	cout << "num = " << num << endl;
	//5.pair对组创建
	pair<string, int> p(string("Tom"), 20);
	cout << "姓名: " <<  p.first << " 年龄: " << p.second << endl;

	pair<string, int> p2 = make_pair("Jerry", 10);
	cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;
	//6.排序
	//6.1内置数据类型:
	set<int> s61;
	s61.insert(10);
	s61.insert(40);
	s61.insert(20);
	s61.insert(30);
	s61.insert(50);

	//默认从小到大
	for (set<int>::iterator it = s61.begin(); it != s61.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;

	//指定排序规则
	set<int,MyCompare> s62;
	s62.insert(10);
	s62.insert(40);
	s62.insert(20);
	s62.insert(30);
	s62.insert(50);

	for (set<int, MyCompare>::iterator it = s62.begin(); it != s62.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
	//6.2自定义类型:
	set<Person, comparePerson> s63;

	Person p1("刘备", 23);
	Person p22("关羽", 27);
	Person p3("张飞", 25);
	Person p4("赵云", 21);

	s63.insert(p1);
	s63.insert(p22);
	s63.insert(p3);
	s63.insert(p4);

	for (set<Person, comparePerson>::iterator it = s63.begin(); it != s63.end(); it++)
	{
    
    
		cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
	}

	return 0;
}

여기에 이미지 설명 삽입

세트 컨테이너와 맵 컨테이너의 차이점에 대해 이야기하기

setmap다음과 같은 방식으로 다른 C++ STL의 두 가지 유형의 연관 컨테이너입니다 .

  1. 스토리지: set컨테이너는 고유한 키를 저장하고 map컨테이너는 각 키가 고유한 키-값 쌍을 저장합니다.
  2. 정렬 및 검색: set컨테이너의 요소는 키 값에 따라 정렬되며 빠른 검색을 위해 키를 사용할 수 있습니다. map컨테이너의 요소는 키의 값으로 정렬되며 키로 해당 값을 빠르게 찾을 수 있습니다.
  3. 삽입 및 삭제: set컨테이너 에서 insert()함수를 사용하여 컨테이너에 키를 삽입할 수 있습니다. map컨테이너 에서 insert()함수 또는 []연산자를 사용하여 키-값 쌍을 삽입할 수 있습니다.
  4. 중복 키: set컨테이너의 키는 고유하며 중복이 허용되지 않습니다. map컨테이너의 키도 고유하며 복제가 허용되지 않지만 키를 사용하여 해당 값을 업데이트할 수 있습니다.
#include <iostream>
#include <set>
#include <map>

int main() {
    
    
    // set容器示例
    std::set<int> mySet;
    mySet.insert(1);
    mySet.insert(2);
    mySet.insert(3);

    for (const auto& element : mySet) {
    
    
        std::cout << "Set Key: " << element << std::endl;
    }

    // map容器示例
    std::map<int, std::string> myMap;
    myMap.insert({
    
    1, "Apple"});
    myMap.insert({
    
    2, "Banana"});
    myMap.insert({
    
    3, "Orange"});

    for (const auto& pair : myMap) {
    
    
        std::cout << "Map Key: " << pair.first << ", Value: " << pair.second << std::endl;
    }

    return 0;
}

세트 컨테이너에서 페어 페어의 개념을 고려해야 하는 이유는 무엇입니까?

C++에서는 set 컨테이너 자체가 키-값 쌍(pair)의 직접 저장을 지원하지 않기 때문입니다.
키-값 쌍을 세트 컨테이너에 저장하려면 std::pair를 사용하여 키와 값을 포함하는 요소를 만든 다음 해당 쌍을 세트 컨테이너에 삽입할 수 있습니다.
다음은 쌍을 사용하여 키-값 쌍을 포함하는 집합 컨테이너를 만드는 방법을 보여주는 예입니다.

#include <iostream>
#include <set>

int main() {
    
    
    std::set<std::pair<int, std::string>> mySet;

    mySet.insert(std::make_pair(1, "Apple"));
    mySet.insert(std::make_pair(2, "Banana"));
    mySet.insert(std::make_pair(3, "Orange"));

    for (const auto& pair : mySet) {
    
    
        std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
    }

    return 0;
}

이 예제에서는 요소가 정수 키와 문자열 값의 조합인 std::pair<int, std::string> 유형인 집합 컨테이너 mySet를 만듭니다. 그런 다음 std::make_pair 함수를 사용하여 세 개의 키-값 쌍을 만들고 mySet 컨테이너에 삽입했습니다. 마지막으로 mySet 컨테이너를 반복하고 각 키-값 쌍의 키와 값을 출력합니다. 세트 컨테이너에는 고유한 요소가 필요하므로 세트 컨테이너에 키-값 쌍을 삽입하면 세트 컨테이너는 키 값(즉, 쌍의 첫 번째 요소)에 따라 정렬 및 중복 제거된다는 점에 유의해야 합니다
. ). 이는 두 개의 키가 동일한 값을 갖는 경우 동일한 것으로 간주됨을 의미합니다. :

#include <iostream>
#include <set>

int main() {
    
    
    std::set<std::pair<int, std::string>> mySet;

    mySet.insert(std::make_pair(1, "Apple"));
    mySet.insert(std::make_pair(2, "Banana"));
    mySet.insert(std::make_pair(1, "Orange"));  // 与第一个键值对的键值相同,不会被插入

    for (const auto& pair : mySet) {
    
    
        std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
    }

    return 0;
}

이 예에서는 세트 컨테이너 mySet에 세 개의 키-값 쌍을 삽입합니다. 첫 번째 키-값 쌍의 키는 1이고 값은 "Apple"입니다. 두 번째 키-값 쌍의 키는 2이고 값은 "Banana"입니다. 세 번째 키-값 쌍의 키도 1입니다. 값은 "Orange" 입니다. 세 번째 키-값 쌍의 키는 첫 번째 키-값 쌍의 키와 동일하므로 설정된 컨테이너에 삽입되지 않습니다. 따라서 최종 출력에는 두 개의 키-값 쌍만 포함됩니다.
출력은 다음과 같습니다.
키: 1, 값: Apple
키: 2, 값: Banana

여기서 루프에 직접 for(auto pair:myset) 를 사용하지 않는 이유는 무엇입니까?
1) 컨테이너를 순회할 때 컨테이너의 요소를 수정하지 않고 읽기만 하려면 const를 사용하여 루프 변수를 수정하는 것이 좋습니다. 이렇게 하면 컨테이너의 요소를 실수로 수정하지 않습니다.
2) const auto& pair를 사용하여 참조로 컨테이너의 요소에 액세스하여 복사 작업을 피하고 효율성을 향상시킵니다.

Set<> 꺾쇠괄호는 여러 매개변수를 넣을 수 있습니다.

C++ STL(표준 템플릿 라이브러리)에는 일반적으로 세트 유형의 템플릿 매개변수가 요소 유형과 비교 함수라는 두 가지뿐입니다. 기본적으로 요소 유형만 제공하면 되며 비교 함수의 기본값은 std::less입니다.
사용자 지정 비교 기능을 사용하려면 설정할 두 번째 매개 변수로 제공할 수 있습니다. 예를 들어:

std::set<int, std::greater<int>> s; // 这会创建一个按照降序排列的 set

여기에서 std::greater는 집합에 요소를 정렬하는 방법을 알려주는 함수 개체입니다. 그러나 일반적으로 std::less의 기본 동작은 오름차순으로 정렬하기 때문에 이 매개 변수를 제공할 필요가 없습니다.
따라서 꺽쇠 괄호에서 가장 많이 사용되는 것은 요소 유형인 매개변수입니다. 그러나 필요한 경우 두 번째 매개변수를 제공하여 사용자 지정 비교 함수를 정의할 수도 있습니다.

그래서 여기에 오해가 있는데, 세트에 두 개의 매개변수를 넣을 수 있지만 키-값 쌍을 넣을 수 있다는 의미는 아닙니다.

맵과 mutimap의 차이점에 대해 이야기하기

맵의 중국어 이름은 "매핑" 입니다
. 와 의 주요 차이점 std::mapstd::multimap키(키)의 고유성입니다.

  1. 키 고유성: 에서 std::map키는 하나의 값에만 해당할 수 있습니다 . 이미 존재하는 키를 삽입하려고 하면 새 값을 삽입하지 않고 기존 키에 해당하는 값을 업데이트합니다. 따라서 std::map고유한 키-값 쌍을 유지해야 하는 상황에 적합합니다.
  2. 키의 반복성: 반대로 에서는 std::multimap동일한 키에 대해 여러 값이 허용됩니다. 즉, 동일한 키로 여러 값을 삽입할 수 있으며 각 값이 보존됩니다. 따라서 std::multimap키-값 쌍을 저장해야 하고 중복 키가 허용되는 상황에 적합합니다.
#include <iostream>
#include <map>
#include <string>

int main() {
    
    
    std::multimap<int, std::string> myMultiMap;
    myMultiMap.insert(std::make_pair(1, "Apple"));
    myMultiMap.insert(std::make_pair(2, "Banana"));
    myMultiMap.insert(std::make_pair(1, "Orange")); // 相同的键,不同的值
    myMultiMap.insert(std::make_pair(3, "Apple"));

    for (const auto& pair : myMultiMap) {
    
    
        std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
    }

    return 0;
}

출력 결과:
키: 1, 값: 사과
키: 1, 값: 주황색
키: 2, 값: 바나나
키: 3, 값: 사과

  1. 요소 순서 지정: std::mapstd::multimap다 순서 지정을 제공할 수 있습니다. std::map키 순서에 따라 정렬되는 Red-Black Tree를 사용하여 구현됩니다. red-black 트리를 사용하여 구현 하기도 std::multimap하지만 동일한 키가 존재하도록 허용하므로 정렬 시 동일한 키를 병합하지 않습니다.

정리하면 std::map고유한 키-값 쌍이 필요하고 키별로 정렬해야 하는 경우에 적합하며, std::multimap중복 키를 허용하고 키별로 정렬해야 하는 경우에 적합합니다.

맵에서 키와 값을 결정하는 방법과 키와 값에 액세스하는 방법은 무엇입니까?

std::map 및 std::multimap에서 키와 값은 std::pair 개체의 첫 번째 및 두 번째 멤버로 표시됩니다.
std::map 및 std::multimap 반복자의 경우 ->first를 사용하여 키에 액세스하고 ->second를 사용하여 값에 액세스할 수 있습니다.
다음은 예입니다.

#include <iostream>
#include <map>
#include <string>

int main() {
    
    
    std::map<int, std::string> myMap;
    myMap.insert(std::make_pair(1, "Apple"));
    myMap.insert(std::make_pair(2, "Banana"));
    myMap.insert(std::make_pair(3, "Orange"));

    for (const auto& pair : myMap) {
    
    
        std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
    }

    return 0;
}

출력 결과:
키: 1, 값: Apple
키: 2, 값: Banana
키: 3, 값: Orange

이 예에서 키는 pair.first에 의해 액세스되고 값은 pair.second에 의해 액세스됩니다.

map, mutimap 및 unordered_map의 차이점

std::map, std::multimapstd::unordered_mapC++ 표준 라이브러리의 세 가지 연관 컨테이너이며 다음과 같은 차이점이 있습니다.

  1. 온화:
    • std::map기본적으로 오름차순으로 키별로 정렬된 정렬된 연관 컨테이너입니다.
    • std::multimap또한 키에 따라 정렬된 동일한 키를 사용하여 여러 요소를 삽입할 수 있는 정렬된 연관 컨테이너입니다.
    • std::unordered_map정렬되지 않은 연관 컨테이너이며 요소의 순서는 키 값에 의존하지 않고 해시 함수에 의해 결정됩니다 .
  2. 기본 구현:
    • std::mapstd::multimap일반적으로 요소를 삽입, 삭제 및 찾을 때 좋은 성능을 제공하는 red-black 트리를 사용하여 구현됩니다 .
    • std::unordered_map해시 테이블을 사용하여 구현 되어 평균적인 경우에 일정한 시간 삽입, 삭제 및 조회 작업을 수행합니다.
  3. 키 고유성:
    • std::map키는 고유해야 하며 동일한 키를 가진 요소가 삽입되면 이전 요소가 새 요소로 대체됩니다.
    • std::multimap동일한 키를 가진 여러 요소를 삽입할 수 있습니다.
    • std::unordered_map키는 고유해야 하며 동일한 키를 가진 요소가 삽입되면 이전 요소가 새 요소로 대체됩니다.
  4. 특징:
    • std::map요소에 순서대로 액세스해야 하는 시나리오에 적합 하며 std::multimap요소 순서에 대한 몇 가지 기능을 제공합니다.
    • std::unordered_map요소를 빠르게 찾아야 하는 시나리오 에 적합하며 삽입, 삭제 및 조회 작업의 평균 성능이 좋습니다.

필요와 특정 상황에 따라 적절한 연관 컨테이너를 선택하는 것이 중요합니다.

지도 컨테이너는 컬렉션을 사용합니다.

#include<iostream>
#include<map>
#include<algorithm>
using namespace std;

void printMap(map<int,int>&m)
{
    
    
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
    
    
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}
//自定义排序的仿函数
class MyCompare {
    
    
public:
	bool operator()(int v1, int v2) {
    
    
		return v1 > v2;
	}
};
int main(){
    
    
    //map基础操作指令集(以int为例)
    //1.构造方式
    map<int,int>m; //默认构造
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	printMap(m);

	map<int, int>m2(m); //拷贝构造
	printMap(m2);

	map<int, int>m3;
	m3 = m2; //赋值
	printMap(m3);

    //2.大小和交换
    map<int, int>m21;
	m21.insert(pair<int, int>(1, 10));
	m21.insert(pair<int, int>(2, 20));
	m21.insert(pair<int, int>(3, 30));

	if (m21.empty())
	{
    
    
		cout << "m21为空" << endl;
	}
	else
	{
    
    
		cout << "m21不为空" << endl;
		cout << "m21的大小为: " << m21.size() << endl;
	}

    //交换
    map<int, int>m22;
	m22.insert(pair<int, int>(1, 10));
	m22.insert(pair<int, int>(2, 20));
	m22.insert(pair<int, int>(3, 30));

	map<int, int>m23;
	m23.insert(pair<int, int>(4, 100));
	m23.insert(pair<int, int>(5, 200));
	m23.insert(pair<int, int>(6, 300));

	cout << "交换前" << endl;
	printMap(m22);
	printMap(m23);

	cout << "交换后" << endl;
	m22.swap(m23);
	printMap(m22);
	printMap(m23);
    cout<<"插入删除展示:"<<endl;
    //3.插入和删除
    //插入
	map<int, int> m31;
	//第一种插入方式
	m31.insert(pair<int, int>(1, 10));
	//第二种插入方式
	m31.insert(make_pair(2, 20));
	//第三种插入方式
	m31.insert(map<int, int>::value_type(3, 30));
	//第四种插入方式
	m31[4] = 40; 
	printMap(m31);

	//删除
	m31.erase(m31.begin());
	printMap(m31);

	m31.erase(3);
	printMap(m31);

	//清空
	m31.erase(m31.begin(),m31.end());
	m31.clear();
	printMap(m31);
    //4.查找和统计
    map<int, int>m41; 
	m41.insert(pair<int, int>(1, 10));
	m41.insert(pair<int, int>(2, 20));
	m41.insert(pair<int, int>(3, 30));

	//查找
	map<int, int>::iterator pos = m41.find(3);

	if (pos != m41.end())
	{
    
    
		cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
	}// 这里用pos->first是等价的
	else
	{
    
    
		cout << "未找到元素" << endl;
	}

	//统计
	int num = m41.count(3);
	cout << "num = " << num << endl;
    
    //5.排序
    map<int, int, MyCompare> m51;

	m51.insert(make_pair(1, 10));
	m51.insert(make_pair(2, 20));
	m51.insert(make_pair(3, 30));
	m51.insert(make_pair(4, 40));
	m51.insert(make_pair(5, 50));

	for (map<int, int, MyCompare>::iterator it = m51.begin(); it != m51.end(); it++) {
    
    
		cout << "key:" << it->first << " value:" << it->second << endl;
	}
    return 0;
}

STL의 back_inserter에 대해 이야기

std::back_inserter()는 컨테이너 끝에 요소의 반복자를 삽입하는 함수 템플릿입니다. 컨테이너를 인수로 사용하고 컨테이너 끝에 요소를 삽입할 수 있는 삽입기 반복자를 반환합니다.
다음은 std::back_inserter()의 샘플 코드입니다.

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3};
    
    std::vector<int> destination;
    
    std::copy(nums.begin(), nums.end(), std::back_inserter(destination));
    
    for (const auto& num : destination) {
    
    
        std::cout << num << " ";
    }
    
    return 0;
}

위의 예에서 일부 정수를 포함하는 소스 컨테이너 nums가 있습니다. 빈 대상 컨테이너 대상을 만든 다음 std::copy() 함수를 사용하여 nums의 요소를 대상에 복사합니다.
std::copy() 함수는 소스 컨테이너의 시작 반복자 nums.begin(), 소스 컨테이너의 끝 반복자 nums.end() 및 삽입자 반복자 std::back_inserter( destination)의 세 가지 매개변수를 허용합니다
. 대상 컨테이너의 반복자 매개변수로 std::back_inserter()를 사용하여 요소가 대상 끝에 삽입되도록 합니다. (소스 컨테이너 nums의 요소는 {1, 2, 3}이므로 대상 컨테이너 목적지 끝에 순서대로 삽입됩니다. 따라서 최종 목적지의 요소 순서도 {1, 2입니다. , 3}.) 마지막으로
destination의 요소를 출력하면 nums의 요소와 동일한 것을 확인할 수 있습니다.
std::back_inserter()는 벡터 및 deque와 같은 push_back() 작업을 지원하는 컨테이너에만 적용할 수 있다는 점에 유의해야 합니다. push_back()을 지원하지 않는 컨테이너의 경우 std::back_inserter()를 사용하면 컴파일 오류가 발생합니다.

STL에서 일반적으로 사용되는 알고리즘에 대해 이야기하십시오.

STL(표준 템플릿 라이브러리)을 사용할 때 다양한 작업을 수행하는 데 도움이 되는 몇 가지 일반적으로 사용되는 알고리즘이 있습니다. 자주 사용하는 STL 알고리즘은 다음과 같습니다.

std::sort(): 컨테이너의 요소를 정렬하는 데 사용되며 기본적으로 오름차순으로 정렬됩니다. 비교 기능을 사용자 지정하여 다른 정렬 방법을 구현할 수 있습니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    5, 2, 8, 1, 9};
    
    std::sort(nums.begin(), nums.end());
    
    for (const auto& num : nums) {
    
    
        std::cout << num << " ";
    }
    
    return 0;
}

std::find(): 컨테이너에서 지정된 값의 요소를 찾고 요소의 반복자를 반환합니다. 찾지 못하면 컨테이너의 end() 반복자를 반환합니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    5, 2, 8, 1, 9};
    
    auto it = std::find(nums.begin(), nums.end(), 8);
    
    if (it != nums.end()) {
    
    
        std::cout << "Element found at index: " << std::distance(nums.begin(), it) << std::endl;
        //std::distance() 是一个用于计算两个迭代器之间距离的函数
    } else {
    
    
        std::cout << "Element not found" << std::endl;
    }
    
    return 0;
}

std::copy(): 한 컨테이너의 요소를 다른 컨테이너로 복사하고 대상 컨테이너의 시작 위치를 지정할 수 있습니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> source = {
    
    1, 2, 3, 4, 5};
    std::vector<int> destination;
    
    std::copy(source.begin(), source.end(), std::back_inserter(destination));
    
    for (const auto& num : destination) {
    
    
        std::cout << num << " ";
    }
    
    return 0;
}

std::transform(): 컨테이너의 요소를 변환하고 그 결과를 다른 컨테이너에 저장하면 변환 함수를 지정할 수 있습니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3, 4, 5};
    std::vector<int> squares;
    
    std::transform(nums.begin(), nums.end(), std::back_inserter(squares), [](int num) {
    
    
        return num * num;
    });
    
    for (const auto& square : squares) {
    
    
        std::cout << square << " ";
    }
    
    return 0;
}

std::accumulate(): 컨테이너의 원소를 합산하여 시작값과 연산함수를 지정할 수 있습니다.

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3, 4, 5};
    
    int sum = std::accumulate(nums.begin(), nums.end(), 0);
    
    std::cout << "Sum: " << sum << std::endl;
    
    return 0;
}

std::count(): 지정된 값과 동일한 컨테이너의 요소 수를 계산합니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 2, 3, 2, 4, 2};
    
    int count = std::count(nums.begin(), nums.end(), 2);
    
    std::cout << "Count: " << count << std::endl;
    
    return 0;
}

std::replace(): 지정된 값과 동일한 컨테이너의 요소를 새 값으로 바꿉니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3, 4, 5};
    
    std::replace(nums.begin(), nums.end(), 3, 10);
    
    for (const auto& num : nums) {
    
    
        std::cout << num << " ";
    }
    
    return 0;
}

std::unique(): 컨테이너에서 연속적으로 반복되는 요소를 제거하고 하나만 남깁니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
    
    auto it = std::unique(nums.begin(), nums.end());
    nums.erase(it, nums.end());
    
    for (const auto& num : nums) {
    
    
        std::cout << num << " ";
    }
    
    return 0;
}

std::for_each(): 함수, 함수 개체 또는 람다 식일 수 있는 컨테이너의 각 요소에 대해 지정된 작업을 수행합니다.

#include <iostream>
#include <vector>
#include <algorithm>

void printSquare(int num) {
    
    
    std::cout << num * num << " ";
}

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3, 4, 5};
    
    std::for_each(nums.begin(), nums.end(), printSquare);
    
    return 0;
}

std::binary_search(): 정렬된 컨테이너에서 이진 검색을 수행하여 지정된 값이 존재하는지 확인합니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> nums = {
    
    1, 2, 3, 4, 5};
    
    bool found = std::binary_search(nums.begin(), nums.end(), 3);
    
    if (found) {
    
    
        std::cout << "Element found" << std::endl;
    } else {
    
    
        std::cout << "Element not found" << std::endl;
    }
    
    return 0;
}

멤버 함수 push_back emplace_back의 차이점

push_back() 및 emplace_back()은 컨테이너 끝에 요소를 추가하는 데 사용되는 두 가지 함수입니다.

push_back(): 컨테이너 끝에 객체를 추가하는 데 사용되는 멤버 함수입니다. 추가할 요소의 값 또는 참조인 하나의 인수를 사용합니다. 컨테이너가 동적 배열(예: std::vector)인 경우 push_back()은 컨테이너 끝에 새 메모리를 할당하고 요소를 새 위치로 복사하거나 이동합니다.

사용 예:

std::vector<int> myVector;
myVector.push_back(10); // 添加元素 10 到 myVector 的末尾

emplace_back(): 이것은 또한 컨테이너의 끝에 새 객체를 생성하는 데 사용되는 멤버 함수입니다. 새 개체를 생성하기 위해 생성자에서 사용할 여러 매개 변수를 허용합니다. push_back()과 달리 emplace_back()은 요소를 복사하거나 이동할 필요가 없지만 컨테이너의 메모리에서 직접 새 객체를 구성합니다.

사용 예:

std::vector<std::string> myVector;
myVector.emplace_back("Hello"); // 在 myVector 的末尾构造一个新的 std::string 对象

emplace_back()의 장점은 컨테이너의 메모리에 직접 새 객체를 생성하기 때문에 객체의 불필요한 복사 또는 이동을 방지한다는 것입니다. 이는 사용자 지정 클래스와 같이 구성하는 데 비용이 많이 드는 개체에 특히 유용합니다. 그러나 emplace_back()은 내부에서 객체를 구성하므로 인수는 컨테이너에 저장된 객체 유형의 생성자와 일치해야 합니다.
push_back()을 사용하든 emplace_back()을 사용하든 컨테이너 끝에 요소를 추가할 수 있습니다. 선택하는 기능은 필요와 상황에 따라 다릅니다.

STL에서 유사하지만 다른 기능을 가진 일부 멤버 함수에 대해 이야기하십시오.

push_back() 대 삽입():

push_back()은 컨테이너 끝에 요소를 삽입하는 데 사용됩니다.

insert()는 컨테이너의 모든 위치에 하나 이상의 요소를 삽입할 수 있습니다.

pop_back() 대 지우기():

pop_back()은 컨테이너의 마지막 요소를 제거하는 데 사용됩니다.

erase()는 컨테이너에서 하나 이상의 요소를 삭제할 수 있으며 삭제할 위치를 지정하거나 반복자를 사용하여 삭제할 범위를 지정할 수 있습니다.

앞() 대 시작():

front()는 컨테이너의 첫 번째 요소에 액세스하는 데 사용됩니다.

begin()은 컨테이너의 첫 번째 요소를 가리키는 반복자를 반환합니다.

백() 대 엔드():

back()은 컨테이너의 마지막 요소에 액세스하는 데 사용됩니다.

end()는 컨테이너의 끝(즉, 마지막 요소를 지나)을 가리키는 반복자를 반환합니다.

크기() 대 비어 있음():

size()는 컨테이너의 요소 수를 반환합니다.

empty()는 컨테이너가 비어 있는지 확인하여 부울 값을 반환합니다.

for_each 변환의 두 순회 알고리즘 간의 차이점에 대해 이야기하십시오.

for_each 및 transform은 목적과 사용 방법이 다른 STL의 두 가지 순회 알고리즘입니다.

각각:

목적: for_each는 컨테이너의 각 요소에 대해 지정된 작업을 수행하는 데 사용되지만 컨테이너의 요소 값은 변경하지 않습니다.

사용법: 함수 객체(또는 함수 포인터)를 매개변수로 받아들이고 함수 객체는 컨테이너의 각 요소에 적용됩니다. 이 함수 개체의 매개 변수 유형은 컨테이너 요소의 유형과 일치해야 합니다. 함수 개체는 일반 함수, 함수 개체 클래스의 인스턴스 또는 람다 식일 수 있습니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

void printElement(int value) {
    
    
    std::cout << value << " ";
}

int main() {
    
    
    std::vector<int> numbers = {
    
    1, 2, 3, 4, 5};
    std::for_each(numbers.begin(), numbers.end(), printElement); // 输出:1 2 3 4 5
    return 0;
}

변환:

목적: transform은 컨테이너의 각 요소에 대해 지정된 작업을 수행하고 결과를 다른 컨테이너에 저장하여 새 컨테이너를 생성하는 데 사용됩니다.

사용법: 두 개의 반복자 범위와 대상 컨테이너의 반복자를 매개변수로 사용하고 함수 개체를 사용합니다. 이 함수 개체의 매개 변수 유형은 소스 컨테이너 요소의 유형과 일치해야 하며 반환 값 유형은 대상 컨테이너 요소 유형과 일치해야 합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int square(int value) {
    
    
    return value * value;
}

int main() {
    
    
    std::vector<int> numbers = {
    
    1, 2, 3, 4, 5};
    std::vector<int> squaredNumbers;

    std::transform(numbers.begin(), numbers.end(), std::back_inserter(squaredNumbers), square);

    // 输出原始容器和新容器的内容
    for (int num : numbers) {
    
    
        std::cout << num << " "; // 输出:1 2 3 4 5
    }

    std::cout << std::endl;

    for (int num : squaredNumbers) {
    
    
        std::cout << num << " "; // 输出:1 4 9 16 25
    }

    return 0;
}

요약하면 for_each는 컨테이너의 요소에 대해 일부 작업을 수행하는 데 사용되고 transform은 컨테이너의 요소에 대한 일부 작업을 수행하고 새 컨테이너를 생성하는 데 사용됩니다.

find find_if 인접_find binary_search count count_if와 다른 검색 알고리즘의 차이점에 대해 이야기하십시오.

find, find_if, 인접_find, binary_search, count 및 count_if는 STL에서 일반적인 검색 알고리즘으로 컨테이너에서 요소를 찾거나 특정 조건을 충족하는 요소의 개수를 세는 데 사용됩니다. 차이점은 아래에 설명되어 있습니다.

찾다:

목적: find는 컨테이너에서 지정된 값의 요소를 찾는 데 사용됩니다.

사용법: 두 개의 반복자 범위와 찾을 값을 매개변수로 사용하고 찾은 요소를 가리키는 반복자를 반환하거나 찾지 못한 경우 컨테이너의 끝을 반환합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    auto it = std::find(numbers.begin(), numbers.end(), 3);

    if (it != numbers.end()) {
    
    
        std::cout << "Found: " << *it << std::endl; // 输出:Found: 3
    } else {
    
    
        std::cout << "Not found" << std::endl;
    }

    return 0;
}

find_if:

목적: find_if는 컨테이너에서 지정된 조건을 충족하는 요소를 찾는 데 사용됩니다.

사용법: 두 개의 반복자 범위와 조건자 함수 개체를 매개변수로 사용하고 찾은 요소를 가리키는 반복자를 반환하거나 찾지 못한 경우 컨테이너의 끝을 반환합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

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

    auto it = std::find_if(numbers.begin(), numbers.end(), isEven);

    if (it != numbers.end()) {
    
    
        std::cout << "Found: " << *it << std::endl; // 输出:Found: 2
    } else {
    
    
        std::cout << "Not found" << std::endl;
    }

    return 0;
}

인접_찾기:

목적: 인접_찾기는 컨테이너에서 인접한 반복 요소를 찾는 데 사용됩니다.

사용법: 두 개의 반복자 범위를 인수로 사용하고 발견된 첫 번째 인접 반복 요소를 가리키는 반복자를 반환하거나 찾지 못한 경우 컨테이너의 끝을 반환합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    auto it = std::adjacent_find(numbers.begin(), numbers.end());

    if (it != numbers.end()) {
    
    
        std::cout << "Found: " << *it << std::endl; // 输出:Found: 2
    } else {
    
    
        std::cout << "Not found" << std::endl;
    }

    return 0;
}

바이너리 검색:

목적: binary_search는 정렬된 컨테이너에서 지정된 값의 요소에 대한 이진 검색에 사용됩니다.

사용 방법: 두 개의 반복자 범위와 찾을 값을 매개 변수로 사용하고 값을 찾았는지 여부를 나타내는 부울을 반환합니다.

참고: 컨테이너는 binary_search를 사용하기 전에 순서대로 되어 있어야 합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    bool found = std::binary_search(numbers.begin(), numbers.end(), 3);

    if (found) {
    
    
        std::cout << "Found" << std::endl;
    } else {
    
    
        std::cout << "Not found" << std::endl; // 输出:Not found
    }

    return 0;
}

세다:

목적: count는 컨테이너에서 지정된 값의 발생 횟수를 계산하는 데 사용됩니다.

사용법: 두 개의 반복기 범위와 매개변수로 계산할 값을 사용하고 값의 발생 횟수를 반환합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    int numTwos = std::count(numbers.begin(), numbers.end(), 2);

    std::cout << "Number of twos: " << numTwos << std::endl; // 输出:Number of twos: 3

    return 0;
}

count_if:

목적: count_if는 지정된 조건을 충족하는 컨테이너의 요소 수를 계산하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위와 술어 함수 개체를 매개 변수로 받아들이고 조건을 만족하는 요소의 수를 반환합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

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

    int evenCount = std::count_if(numbers.begin(), numbers.end(), isEven);

    std::cout << "Number of even elements: " << evenCount << std::endl; // 输出:Number of even elements: 2

    return 0;
}

sort random_shuffle merge reverse와 다른 정렬 알고리즘의 차이점에 대해 이야기하세요.

sort, random_shuffle, merge 및 reverse는 컨테이너의 요소를 정렬하고 재정렬하는 데 사용되는 STL의 일반적인 정렬 및 재정렬 알고리즘입니다. 차이점은 아래에 설명되어 있습니다.

종류:

목적: 정렬은 일반적으로 컨테이너의 요소를 오름차순으로 정렬하는 데 사용됩니다(다른 정렬 방법을 달성하기 위해 비교 기능을 사용자 정의할 수도 있음).

사용법: 두 개의 반복자 범위를 매개변수로 받아들이고 요소를 비교하여 컨테이너의 요소를 정렬합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>


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

    std::sort(numbers.begin(), numbers.end());

    // 输出排序后的结果:1 2 3 4 5
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

랜덤_셔플:

목적: random_shuffle은 컨테이너의 요소를 무작위로 재배열하고 원래 순서를 방해하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위를 매개변수로 받아들이고 임의의 알고리즘을 통해 컨테이너의 요소를 재정렬합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    std::random_shuffle(numbers.begin(), numbers.end());

    // 输出随机排列后的结果,例如可能是:3 2 1 5 4
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

합병:

목적: 병합은 두 개의 정렬된 컨테이너를 새로운 정렬된 컨테이너로 병합하는 데 사용됩니다.

사용법: 두 개의 정렬된 반복자 범위와 대상 컨테이너의 반복자를 인수로 받아들이고 두 입력 범위를 대상 컨테이너로 병합합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> numbers1 = {
    
    1, 3, 5};
    std::vector<int> numbers2 = {
    
    2, 4, 6};
    std::vector<int> mergedNumbers(6);

    std::merge(numbers1.begin(), numbers1.end(), numbers2.begin(), numbers2.end(), mergedNumbers.begin());

    // 输出合并后的结果:1 2 3 4 5 6
    for (int num : mergedNumbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

뒤집다:

목적: reverse는 컨테이너의 요소를 역순으로 정렬하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위를 매개변수로 받아들이고 컨테이너의 요소를 역순으로 정렬합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    std::reverse(numbers.begin(), numbers.end());

    // 输出逆序后的结果:5 4 3 2 1
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

요약하면, 이러한 정렬 및 재정렬 알고리즘은 STL에서 다른 기능을 제공하며 컨테이너의 요소를 정렬, 섞거나 역순으로 정렬하기 위한 요구 사항에 따라 적절한 알고리즘을 선택할 수 있습니다.

copy, replace, replace_if, swap 및 기타 복사 대체 알고리즘의 차이점에 대해 이야기하십시오.

copy, replace, replace_if 및 swap은 컨테이너의 요소를 복사 및 교체하는 데 사용되는 STL의 일반적인 복사 및 교체 알고리즘입니다. 차이점은 아래에 설명되어 있습니다.

복사:

목적: copy는 한 컨테이너의 요소를 다른 컨테이너로 복사하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위와 대상 컨테이너의 반복자를 매개 변수로 받아들이고 원본 컨테이너의 요소를 대상 컨테이너에 복사합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> source = {
    
    1, 2, 3, 4, 5};
    std::vector<int> destination(5);

    std::copy(source.begin(), source.end(), destination.begin());

    // 输出目标容器的内容:1 2 3 4 5
    for (int num : destination) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

바꾸다:

목적: replace는 컨테이너의 지정된 모든 값을 다른 값으로 바꾸는 데 사용됩니다.

사용법: 두 개의 반복자 범위와 교체할 값, 교체할 값을 매개변수로 받아 지정된 모든 값을 교체할 값으로 교체합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

    std::replace(numbers.begin(), numbers.end(), 2, 99);

    // 输出替换后的结果:1 99 99 3 4 99
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

교체_만약:

목적: replace_if는 특정 조건을 충족하는 컨테이너의 모든 요소를 ​​다른 값으로 대체하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위와 조건자 함수 개체 및 대체 값을 매개 변수로 받아들이고 조건을 충족하는 요소를 대체 값으로 대체합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

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

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

    std::replace_if(numbers.begin(), numbers.end(), isEven, 0);

    // 输出替换偶数后的结果:1 0 3 0 5
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

교환:

목적: 스왑은 두 컨테이너 또는 요소의 값을 교환하는 데 사용됩니다.

사용 방법: 두 개의 컨테이너 또는 요소를 매개변수로 사용하고 해당 값을 교환합니다.

참고: 스왑은 실제 요소 내용이 아닌 포인터만 스왑하기 때문에 컨테이너에 효율적입니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    int a = 10;
    int b = 20;

    std::swap(a, b);

    std::cout << "a: " << a << ", b: " << b << std::endl; // 输出:a: 20, b: 10

    return 0;
}

요약하면 이러한 복사 및 교체 알고리즘은 STL에서 다른 기능을 제공하며 요구 사항에 따라 요소 복사 및 교체 작업을 수행하기 위해 적절한 알고리즘을 선택할 수 있습니다. 동시에 스왑 알고리즘을 사용하여 두 컨테이너 또는 요소의 값을 효율적으로 교환할 수도 있습니다.

누적, 채우기 및 기타 산술 생성 알고리즘의 차이점에 대해 이야기하십시오.

누적 및 채우기는 STL의 산술 생성 알고리즘이며 컨테이너의 수치 계산 및 채우기 작업에 사용됩니다. 차이점은 아래에 설명되어 있습니다.

축적하다:

목적: 누적은 컨테이너의 요소를 누적하거나 일부 이진 연산을 기반으로 누적 계산을 수행하는 데 사용됩니다.

사용 방법: 두 개의 반복자 범위와 초기 값을 매개변수로 받아들이고 지정된 이진 연산을 사용하여 컨테이너에 요소를 누적합니다.

예:

#include <iostream>
#include <vector>
#include <numeric> // 包含accumulate算法

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

    int sum = std::accumulate(numbers.begin(), numbers.end(), 0);

    std::cout << "Sum: " << sum << std::endl; // 输出:Sum: 15

    return 0;
}

위 예제의 단순 누적 외에도 누적은 사용자 지정 이진 연산을 사용하여 컨테이너의 모든 요소의 곱을 계산하는 것과 같은 누적 계산을 수행할 수 있습니다.

#include <iostream>
#include <vector>
#include <numeric> // 包含accumulate算法

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

    int product = std::accumulate(numbers.begin(), numbers.end(), 1, std::multiplies<int>());

    std::cout << "Product: " << product << std::endl; // 输出:Product: 120

    return 0;
}

채우다:

목적: 채우기는 컨테이너의 모든 요소를 ​​지정된 값으로 설정하는 데 사용됩니다.

사용방법 : 2개의 반복자 범위와 채울 값을 매개변수로 받아 컨테이너의 모든 요소를 ​​지정된 값으로 설정합니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> numbers(5);

    std::fill(numbers.begin(), numbers.end(), 42);

    // 输出填充后的结果:42 42 42 42 42
    for (int num : numbers) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

set_intersection, set_union, set_difference 및 기타 집합 알고리즘의 차이점에 대해 이야기하십시오.

set_intersection, set_union 및 set_difference는 교집합, 합집합 및 차이 연산을 위해 정렬된 컨테이너(일반적으로 정렬됨)에서 작동하는 STL의 설정 알고리즘입니다. 차이점은 아래에 설명되어 있습니다.

set_intersection:

목적: set_intersection은 정렬된 두 컨테이너의 교집합을 계산하는 데 사용됩니다. 즉, 두 컨테이너에서 공통 요소를 찾는 데 사용됩니다.

사용법: 두 개의 입력 컨테이너와 대상 컨테이너의 반복자를 매개변수로 사용하고 두 입력 컨테이너의 교집합을 대상 컨테이너에 복사합니다.

참고: 전제는 두 입력 컨테이너가 순서대로 있어야 한다는 것입니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> set1 = {
    
    1, 2, 3, 4, 5};
    std::vector<int> set2 = {
    
    3, 4, 5, 6, 7};
    std::vector<int> intersection(5);

    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), intersection.begin());

    // 输出交集的结果:3 4 5
    for (int num : intersection) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

set_union:

목적: set_union은 순서가 지정된 두 컨테이너의 합집합을 계산하는 데 사용됩니다. 즉, 두 컨테이너의 모든 고유 요소를 새 컨테이너로 병합하는 데 사용됩니다.

사용법: 두 개의 입력 컨테이너와 대상 컨테이너의 반복자를 매개변수로 사용하고 두 입력 컨테이너의 합집합을 대상 컨테이너에 복사합니다.

참고: 전제는 두 입력 컨테이너가 순서대로 있어야 한다는 것입니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> set1 = {
    
    1, 2, 3, 4, 5};
    std::vector<int> set2 = {
    
    3, 4, 5, 6, 7};
    std::vector<int> unionSet(10);

    std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), unionSet.begin());

    // 输出并集的结果:1 2 3 4 5 6 7
    for (int num : unionSet) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

세트_차이:

목적: set_difference는 정렬된 두 컨테이너 간의 차이를 계산하는 데 사용됩니다. 즉, 첫 번째 컨테이너에는 있지만 두 번째 컨테이너에는 없는 요소를 찾는 데 사용됩니다.

사용 방법: 두 개의 입력 컨테이너와 대상 컨테이너의 반복자를 매개 변수로 받아들이고 두 입력 컨테이너의 차이점을 대상 컨테이너에 복사합니다.

참고: 전제는 두 입력 컨테이너가 순서대로 있어야 한다는 것입니다.

예:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    
    
    std::vector<int> set1 = {
    
    1, 2, 3, 4, 5};
    std::vector<int> set2 = {
    
    3, 4, 5, 6, 7};
    std::vector<int> difference(5);

    std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(), difference.begin());

    // 输出差集的结果:1 2
    for (int num : difference) {
    
    
        std::cout << num << " ";
    }

    return 0;
}

요약하면 set_intersection, set_union 및 set_difference는 순서가 지정된 컨테이너에 대한 설정 작업을 위해 STL에서 사용되는 알고리즘입니다. 특정 요구 사항에 따라 적절한 알고리즘을 선택하여 교집합, 합집합 또는 차이를 계산할 수 있습니다.

STL의 공간 구성자에 대해 이야기하십시오.

STL(标准模板库)的空间配置器是用于分配和管理内存的组件它负责在需要时分配内存,并在不再需要时释放内存,以支持容器(如vector、list、map等)和其他STL组件的动态存储需求。
STL的空间配置器使用了一种称为"allocator"的设计模式。它通过提供allocate()和deallocate()等函数来分配和释放内存,使得容器可以根据需要动态地分配和释放内存空间。
STL的空间配置器通常使用底层的内存分配函数(如malloc()和free())来执行实际的内存分配和释放操作。它还可以管理内存池,以提高内存分配的效率。
空间配置器还提供了一些其他功能,如构造和析构对象、获取内存块的大小等。这些功能使得容器可以在内存中存储和管理对象,并在需要时按需构造和析构对象。
总之,STL的空间配置器是用于分配和管理内存的组件,它是STL实现动态存储需求的重要部分。它提供了一种灵活和可扩展的方式来处理内存分配和释放,以支持各种容器和其他STL组件的使用。

以Vector为例,讲一下STL的空间配置器如何工作的

空间配置器是C++标准库中的一种内存管理工具,用于管理动态分配的内存块。下面以vector为例,简要介绍空间配置器的工作原理:

1)内存分配:当vector需要分配内存来存储元素时,它会调用空间配置器的allocate函数来请求一块足够大的内存空间。空间配置器会根据需要的内存大小,使用底层的内存分配函数(如malloc()或new)向操作系统申请内存。

2)内存管理:空间配置器会将所分配的内存空间进行管理,通常会记录已分配和未分配的内存块的状态。这样,当vector需要增加或减少元素时,空间配置器可以快速定位到可用的内存块。

3) 메모리 해제: 벡터가 더 이상 특정 메모리 블록을 필요로 하지 않으면 공간 구성자의 할당 해제 기능을 호출하여 메모리 블록을 공간 구성자에게 반환합니다. 공간 할당자는 다음에 할당될 때 재사용할 수 있도록 메모리 블록을 사용 가능한 것으로 표시합니다.

공간 구성자의 특정 구현은 컴파일러와 운영 체제 간에 다를 수 있습니다. 다른 공간 할당자는 메모리 할당 및 해제의 효율성을 향상시키기 위해 다른 메모리 관리 전략 및 알고리즘을 사용할 수 있습니다. 예를 들어 공간 할당자는 메모리 풀 또는 기타 기술을 사용하여 빈번한 메모리 할당 및 할당 해제 작업을 줄일 수 있습니다.

Space Configurator의 2계층 구조에 대해 이야기합니다.

空间配置器的两层结构是指在STL中,空间配置器被设计为两个层次的结构,分别是第一级配置器(first-level allocator)和第二级配置器(second-level allocator)。
1)第一级配置器是一个简单的分配器,它负责处理较大的内存分配请求。它使用的是全局的::operator new()和::operator delete()函数来执行内存的分配和释放。这些全局函数通常是直接调用底层的内存分配函数(如malloc()和free())来完成实际的内存操作。
2)第二级配置器是一个更复杂的分配器,它负责处理较小的内存分配请求。它使用了一个内存池(memory pool),即一个已经预先分配好的大块内存区域。当需要分配内存时,第二级配置器会从内存池中获取一块足够大小的内存块,并将其分配给请求者。如果内存池中的内存块不足,第二级配置器会调用第一级配置器来执行更大的内存分配。
分层原因:第一级配置器和第二级配置器之间的划分是为了提高内存分配的效率。较大的内存分配请求可以直接使用第一级配置器,避免了内存池的管理开销。而较小的内存分配请求则由第二级配置器处理,它利用内存池的高效分配机制来加速内存的分配和释放。
需要注意的是,具体的实现可能会有所不同,不同的编译器和实现可能采用不同的策略和机制来实现空间配置器的两层结构。但总体思想是相似的,即通过两级结构来处理不同大小的内存分配请求,以提高内存分配的效率。

讲一下内存池

内存池是一种内存管理技术,它是在程序启动时预先分配一块连续的内存区域,并在程序运行过程中使用这个内存区域来分配和释放内存。内存池的目的是减少频繁的内存分配和释放操作,提高内存管理的效率。
内存池的工作原理如下:

1) 미리 할당된 메모리: 프로그램이 시작되면 메모리 풀은 운영 체제에서 더 큰 메모리 영역을 요청합니다. 이 메모리 영역은 일반적으로 연속적이며 프로그램의 메모리 요구 사항을 충족하기에 충분히 큽니다.

2) 메모리 할당: 프로그램이 메모리를 할당해야 할 때 메모리 풀은 미리 할당된 메모리 영역에서 충분한 크기의 메모리 블록을 가져와 프로그램에 할당합니다. 메모리 풀이 운영 체제와 자주 통신할 필요가 없기 때문에 이 프로세스는 일반적으로 운영 체제에서 직접 메모리를 요청하는 것보다 빠릅니다.

3) 메모리 해제: 프로그램이 더 이상 메모리 블록을 필요로 하지 않으면 메모리 블록을 운영 체제에 직접 해제하는 대신 메모리 풀로 반환할 수 있습니다. 메모리 풀은 다음에 할당될 때 재사용할 수 있도록 이 메모리 블록을 사용 가능한 것으로 표시합니다.

메모리 풀의 이점은 다음과 같습니다.

1) 메모리 조각화 감소: 메모리 풀은 연속적인 메모리 영역을 사용하므로 메모리 조각화를 줄일 수 있습니다. 이는 메모리 풀의 메모리 블록이 밀접하게 배열되어 조각화되지 않기 때문입니다.

2) 메모리 할당 효율성 향상: 메모리 풀은 빈번한 메모리 할당 작업을 피하고, 큰 메모리 영역을 미리 할당함으로써 메모리 할당 오버헤드를 줄이고 메모리 할당 효율성을 높일 수 있습니다.

3) 메모리 사용 제어: 메모리 풀은 메모리 누수 및 초과 할당 문제를 방지하기 위해 프로그램에서 사용하는 총 메모리 양을 제한할 수 있습니다. 메모리 풀의 크기를 미리 할당하면 프로그램의 메모리 사용량을 제어할 수 있습니다.

메모리 풀이 모든 상황에 적합한 것은 아닙니다. 메모리 할당 및 할당 해제가 빈번하고 크기가 고정되지 않은 상황에서는 메모리 풀이 제대로 작동하지 않을 수 있습니다. 또한 메모리 풀의 구현은 스레드 안전성 및 메모리 관리의 복잡성과 같은 요소도 고려해야 합니다. 따라서 메모리 풀을 사용할 때 사례별로 절충 및 평가가 이루어져야 합니다.

펑터에 대해 알아보자

펑터에 대해 이야기할 때 실제로는 함수처럼 호출할 수 있는 특수한 유형의 개체에 대해 이야기하고 있습니다. 펑터는 함수 호출 operator operator()를 오버로드하는 클래스 또는 구조체입니다. operator()를 오버로드하면 functor를 코드에서 함수로 사용하여 매개 변수를 수락하고 결과를 반환할 수 있습니다.
펑터의 장점 중 하나는 유연성입니다. 객체이기 때문에 함수나 알고리즘에 인수로 전달하거나 컨테이너에 저장할 수 있습니다. 이를 통해 사용자 지정 작업 논리를 보다 직관적이고 재사용 가능한 방식으로 캡슐화하고 필요할 때 호출할 수 있습니다.
다음은 추가 펑터를 만들고 사용하는 방법을 보여주는 간단한 예입니다.

class AddFunctor
{
    
    
public:
    int operator()(int a, int b)
    {
    
    
        return a + b;
    }
};

int main()
{
    
    
    AddFunctor add;
    int result = add(3, 4); // 调用仿函数
    // result = 7
    return 0;
}

단항 술어와 이진 술어의 차이점은 무엇입니까?

단항 및 이진 술어는 알고리즘 및 기타 기능에서 조건부 판단을 수행하는 데 사용되는 특수한 유형의 기능 객체입니다. 단항 조건자는 하나의 인수를 취하고 부울 값을 반환하는
함수 개체입니다 . 일반적으로 단일 요소에 대한 조건부 판단에 사용됩니다. 예를 들어, 정수가 짝수인지 확인하기 위해 단항 술어를 사용할 수 있습니다.

struct IsEven
{
    
    
    bool operator()(int num)
    {
    
    
        return num % 2 == 0;
    }
};

int main()
{
    
    
    IsEven isEven;
    bool result = isEven(4); // 调用一元谓词
    // result = true
    return 0;
}

위의 예에서 IsEven은 함수 호출 연산자 operator()를 오버로드하고 int 유형의 매개 변수를 허용하며 숫자가 짝수인지 여부를 나타내는 부울 값을 반환하는 단항 술어 클래스입니다. IsEven 개체 isEven을 생성하여 함수를 호출하고 매개 변수를 전달하고 결과를 얻는 것처럼 사용할 수 있습니다. 이진 조건자는 두 개의 인수를 사용 하고 부울 값을 반환하는
함수 개체입니다 . 일반적으로 두 가지 요소에 대한 조건부 판단에 사용됩니다. 예를 들어 이진 술어를 사용하여 두 문자열의 길이를 비교할 수 있습니다.

struct CompareLength
{
    
    
    bool operator()(const std::string& str1, const std::string& str2)
    {
    
    
        return str1.length() < str2.length();
    }
};

int main()
{
    
    
    CompareLength compare;
    bool result = compare("apple", "banana"); // 调用二元谓词
    // result = true
    return 0;
}

위의 예에서 CompareLength는 함수 호출 operator operator()를 오버로드하고 const std::string& 유형의 두 매개 변수를 사용하고 첫 번째 문자열의 길이를 나타내는 부울 값을 반환하는 이진 술어 클래스입니다. 두 번째 문자열의 길이. CompareLength 객체 비교를 생성하면 함수를 호출하고 매개변수를 전달하고 결과를 얻는 것처럼 사용할 수 있습니다.
요약하면, 단항 술어는 하나의 매개변수를 받아 단일 요소에 대한 조건 판단에 사용되는 함수 객체이고, 이진 술어는 두 개의 매개변수를 받아 두 요소에 대한 조건 판단에 사용되는 함수 객체입니다. 사용자 지정 조건에 따라 작동하는 알고리즘 및 기타 기능에 자주 사용됩니다.

내장 함수 객체는 무엇이며 functor와의 관계는 무엇입니까?

내장 함수 객체: 내장 함수 객체는 함수처럼 사용할 수 있는 미리 정의된 객체이며 일반적으로 표준 라이브러리 functional 에 정의됩니다 . 이러한 기본 제공 함수 개체는 산술 연산자, 비교 연산자, 논리 연산자 등과 같은 기본 제공 연산자에 대한 함수 래퍼를 제공합니다.
사실 모든 내장 함수 개체는 특정 유형의 함수자입니다.

Functor: C++에서 functor는 클래스 정의에 연산자()가 오버로드된 클래스입니다. 그러한 클래스의 객체는 함수처럼 호출될 수 있으므로 "펑터"라는 이름이 붙습니다. 간단히 말해서 펑터는 함수처럼 동작하는 객체입니다.

내장 함수 개체: 표준 라이브러리에서 제공하는 미리 정의된 함수입니다. 이러한 펑터는 일반적으로 기본 산술 연산, 비교 및 ​​논리 연산을 포함하여 헤더 파일에 정의됩니다.

따라서 내장 함수 객체는 미리 정의된 functor의 일종으로 functor의 특수한 경우라고 할 수 있습니다. 따라서 내장 함수 객체와 펑터의 관계는 특수한 경우와 일반 함수의 관계입니다. 즉, 모든 내장 함수 객체는 펑터이지만 모든 펑터가 내장 함수 객체는 아니며 사용자가 펑터를 사용자 정의할 수 있습니다. .

산술 함수자 관계형 함수자 논리 함수자 소개

산술 함수: 더하기, 빼기, 곱하기, 나누기 등과 같은 기본 산술 연산을 위해 정의된 함수입니다. C++ 표준 라이브러리에서는 헤더 파일에서 std::plus, std::minus, std::multiplies 및 std::divides와 같은 산술 함수를 찾을 수 있습니다.

관계형 펑터: 이러한 펑터는 같음, 같지 않음, 보다 작음, 보다 큼, 보다 작거나 같음 및 크거나 같음과 같은 비교 작업을 수행하는 데 사용됩니다. 마찬가지로 C++ 헤더 파일에서 std::equal_to, std::not_equal_to, std::less, std::greater, std::less_equal 및 std::greater_equal과 같은 관계형 함수를 찾을 수 있습니다.

논리 함수: 이 함수는 논리 AND, 논리 OR, 논리 NOT 등과 같은 논리 연산에 사용됩니다. C++ 헤더 파일에서 std::logical_and, std::logical_or 및 std::logical_not과 같은 논리 함수를 찾을 수 있습니다.

다음은 C++ 내장 함수 개체(산술 함수자, 관계형 함수자, 논리 함수자)를 사용하는 몇 가지 예입니다.

산술 함수:

#include <iostream>
#include <functional>

int main() {
    
    
    std::plus<int> plus_obj;
    std::minus<int> minus_obj;
    std::cout << "10 + 5 = " << plus_obj(10, 5) << std::endl;
    std::cout << "10 - 5 = " << minus_obj(10, 5) << std::endl;
    return 0;
}

출력:
10 + 5 = 15
10 - 5 = 5

관계형 함수:

#include <iostream>
#include <functional>

int main() {
    
    
    std::less<int> less_obj;
    std::greater<int> greater_obj;
    std::cout << "Is 10 < 5 ? " << (less_obj(10, 5) ? "true" : "false") << std::endl;
    std::cout << "Is 10 > 5 ? " << (greater_obj(10, 5) ? "true" : "false") << std::endl;
    return 0;
}

출력:
10 < 5 ?거짓
10 > 5 ?참

논리 함수:

#include <iostream>
#include <functional>

int main() {
    
    
    std::logical_and<bool> and_obj;
    std::logical_or<bool> or_obj;
    std::cout << "true AND false = " << (and_obj(true, false) ? "true" : "false") << std::endl;
    std::cout << "true OR false = " << (or_obj(true, false) ? "true" : "false") << std::endl;
    return 0;
}

출력:
true AND false = false
true OR false = true

Supongo que te gusta

Origin blog.csdn.net/weixin_46274756/article/details/131936573
Recomendado
Clasificación