[C++ 스킬 트리] 벡터 클래스 분석 및 시뮬레이션 구현

이미지

헤일로 뿌아입니다. 보통은 주로 C언어, C++, 자료구조 알고리즘 업데이트... 관심있으신 분들은 저를 팔로우 해주세요!

이미지

0. 벡터 소개

벡터 는 다양한 유형의 시퀀스 컨테이너를 수용할 수 있는 동적 배열 컨테이너입니다. 배열이라고 부르는 것은 다음을 의미합니다. **이전 시퀀스 테이블과 유사하게 아래 첨자를 사용하여 액세스할 수도 있습니다. ** 따라서 Vector가 공간을 할당할 때, 시스템에 공간을 신청하는 비용이 상대적으로 높기 때문에 사용하는 만큼 할당한다는 의미가 아니라 더 많이 할당한다는 의미입니다 .

1. 벡터 공통 인터페이스

String은 이전에 각 인터페이스를 자세히 해석했기 때문에 표준 STL에서는 각 인터페이스의 들어오는 매개 변수와 반환 값이 대부분 동일합니다. 따라서 이 장에서는 인터페이스에 중점을 두지 않습니다. Forgotten uu는 [ 문자열 분석] 기사를 볼 수 있습니다 .

벡터의 선언 방법, 여기서 T는 템플릿입니다.

vector<T>v;

1.1생성자 생성자

(생성자) 생성자 선언 인터페이스 설명
벡터() 매개변수 구성 없음
벡터(size_type n, const value_type& val = value_type()) n va 구성 및 초기화
벡터(상수 벡터& x); 복사 공사
벡터(InputIterator 먼저, InputIterator 마지막); 반복자를 사용하여 구성 초기화

Vector 생성자의 사용을 보려면 코드로 직접 이동하십시오.

  1. 기본 생성자:
vector (const allocator_type& alloc = allocator_type());

그중에서 const allocator_type& alloc = allocator_type()은 정렬, 버퍼 풀 등과 같은 특수한 메모리 관리 동작을 구현하기 위해 사용자 지정 할당자를 만드는 데 사용됩니다. C++ 초보자 단계에서는 기본 메모리 할당만 사용하면 됩니다. 전략.

따라서 기본 생성자는 다음과 같이 사용합니다.

vector<T>v;
vector<int>v;
  1. 패딩 생성자:

    vector (size_type n, const value_type& val = value_type(),
                     const allocator_type& alloc = allocator_type());
    

    n개 값으로 컨테이너 채우기

    vector<int>v(5,1);
    
  2. 반복자 생성자를 사용하십시오 .

template <class InputIterator>
         vector (InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type());
vector<int>v(5,3);
vector<int>v1(v.begin(),v.end());

먼저 채우기 구성을 먼저 사용하고 5개의 3을 v에 채웁니다. 그런 다음 반복자 생성자를 사용하고 시작()-끝() 범위의 내용을 v1에 넣습니다.

  1. 복사 생성자 :
vector (const vector& x);

1.2 반복자

반복자의 사용 인터페이스 설명
시작()+종료() 첫 번째 데이터 위치의 iterator/const_iterator 가져오기, 마지막 데이터의 다음 위치 iterator/const_iterator 가져오기
rbegin()+렌드() 마지막 데이터 위치의 reverse_iterator 가져오기, 첫 번째 데이터의 이전 위치의 reverse_iterator 가져오기

**이것은 [begin(), end()]와 [rbegin(), rend()]의 구조도입니다. **이터레이터가 사용되는 모든 시나리오에서 [begin(), end())입니다. 왼쪽 닫기 오른쪽 열기 모드( 즉, 왼쪽으로 갈 수 있지만 오른쪽으로는 갈 수 없음 )

정렬하고 찾기

이 두 함수는 algorithm 에 주어진 함수 입니다.

찾다

InputIterator find (InputIterator first, InputIterator last, const T& val);

지정된 간격으로 val을 찾고, 찾은 후 iterator를 반환 구현은 다음과 같으며 간격을 순회하여 val을 찾습니다.

template<class InputIterator, class T>
  InputIterator find (InputIterator first, InputIterator last, const T& val)
{
    
    
  while (first!=last) {
    
    
    if (*first==val) return first;
    ++first;
  }
  return last;
}
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
cout<<*find(v.begin(),v.end(),3);

출력은 다음과 같습니다. 3

종류

 void sort (RandomAccessIterator first, RandomAccessIterator last);

지정된 간격으로 데이터를 정렬합니다. 기본적으로 < 정렬에 사용됩니다. (동일한 요소가 안정적인 정렬을 보장하지 않습니다. 즉, 원본 데이터의 위치가 변경됩니다.)

vector<int>v;
v.push_back(4);
v.push_back(1);
v.push_back(3);
v.push_back(2);
sort(v.rbegin(),v.rend());
for(auto s:v)
    cout<<s;

역방향 반복기를 사용하여 가장 큰 것부터 가장 작은 것까지 정렬합니다.

출력 결과: 4321

1.3 용량 관련 인터페이스

용량 공간 인터페이스 설명
크기 데이터 개수 반환
용량 현재 점유된 공간의 크기를 반환합니다.
비어 있는 반환이 비어 있습니다
크기 조정 크기 변경
예약하다 용량 변경

문자열과 동일하므로 여기서는 자세히 설명하지 않겠습니다.

1.4 관련 인터페이스 수정

수정하다 인터페이스 설명
푸시백 테일 플러그
팝백 꼬리 삭제
끼워 넣다 끼워 넣다
삭제 삭제
교환 두 벡터 공간 교환
운영자[] 배열처럼 액세스

여기서 우리는 지우기와 삽입에 초점을 맞출 필요가 있는데, 그들의 기능은 현재 반복자의 위치를 ​​통해 요소를 삽입하거나 삭제하는 것입니다.

그러나 이전 이터레이터를 직접 사용하는 경우 이터레이터 실패 문제가 발생할 수 있습니다. 근본적인 이유는 더 이상 자신에게 속하지 않는 이터레이터에 액세스했기 때문입니다.

벡터의 기본 원리는 old space가 해제되고 인쇄할 때 여전히 해제 사이에 old space를 사용한다는 것입니다. 붕괴를 실행하는 코드. 해결 방법: 위 작업이 완료된 후 반복자를 통해 벡터의 요소를 계속 작업하려면 다시 할당하기만 하면 됩니다.

2. 벡터 시뮬레이션 구현

Vector는 String과 유사하며 저장 공간의 범위를 나타내는 데 사용되는 세 개의 개인 속성도 있습니다 (STL 소스 코드는 다르게 구현될 수 있지만 아이디어는 동일합니다).

그리고 반복자를 먼저 선언합니다( 단순히 유형 포인터로 볼 수 있음 ).

여기에 이미지 설명 삽입

typedef T* iterator;
typedef const T* const_iterator;
private:
	_start;
	_finish;
	_endofstorage;

2.1 생성자

2.1.1 기본 매개변수 생성자가 없음

vector():
	_start(nullptr),
	_finish(nullptr),
	_endofstorage(nullptr)
{
    
    
    
}

이것은 초기화 목록으로 구성해야 하는 원래 생성자이지만 C++11이 패치된 후에는 개인 속성일 때 기본 매개 변수를 지정할 수 있습니다.

private:
	_start=nullptr;
	_finish=nullptr;
	_endofstorage=nullptr;

이때 기본 생성자는 아무 것도 작성할 필요가 없습니다.

vector():
{
    
    
    
}

2.1.2 매개변수가 있는 기본 생성자

  1. 채워진 모양 생성자:

    vector(size_t n, const T& val = T())
    {
          
          
        resize(n, val);
    }
    vector(int n, const T& val = T())
    {
          
          
        resize(n, val);
    }
    template<class InputIterator>
    vector(InputIterator begin, InputIterator end)
    {
          
          
        while (begin != end)
        {
          
          
            push_back(*begin);
            begin++;
        }
    }
    

    두 번째 형식 매개변수는 기본 매개변수를 제공합니다.C++에서는 각 유형을 클래스로 간주할 수 있습니다. 이때 기본 생성자는 클래스 이름()입니다 .예를 들어

    정수(), 이중(), 문자열()…

    첫 번째와 두 번째는 기본적으로 동일한 작업을 수행하지만 반복자가 추가되었기 때문입니다. 다음 건설 계획을 사용하는 경우

    vector<int>v(1,5);
    

    우리가 준 컨스트럭션 파라미터는 같은 타입의 2개 입니다.첫 번째 타입으로 컨스트럭션을 초기화 하도록 의도했지만, 타입이 같기 때문에 초기화를 위해 이터레이터를 사용하여 세 번째 타입으로 인식되는 경우가 많습니다.

    그래서 int를 따로 다루어야 해서 두 번째가 있습니다.

  2. 구성에 벡터 유형 사용:

    vector(const vector<T>& v)
    {
          
          
        _start = new T[v.capacity()];
        for (size_t i = 0; i < v.size(); i++)
        {
          
          
            _start[i] = v._start[i];
        }
        //_finish = v._finish; 只是令地址相等
        _finish = _start + v.size();
        _endofstorage = _start + v.capacity();
    }
    

    클래스의 멤버 함수에서 클래스의 전용 멤버 변수에 직접 액세스할 수 있습니다 .

    여기서는 Memcpy를 사용할 수 없습니다: memcpy는 메모리를 복사하기 때문에 내장형이면 작업을 완료할 수 있습니다. 사본
    여기에 이미지 설명 삽입

    전체적인 아이디어는: 먼저 시작을 위한 새 공간을 할당한 다음 형식 매개변수의 내용을 차례로 복사하고 마지막으로 길이와 공간 크기를 계산합니다.(여기서 완료는 직접 할당할 수 없는 주소입니다 . )

2.2 소멸자

요청된 모든 공간을 시스템에 반환합니다.

~vector()
{
    
    
    if (_start)
    {
    
    
        delete[]_start;
        _start = _finish = _endofstorage = nullptr;
    }
}

2.3 반복자

iterator begin()
{
    
    
    return _start;
}
iterator end()
{
    
    
    return _finish;
}
const_iterator begin()const
{
    
    
    return _start;
}
const_iterator end()const
{
    
    
    return _finish;
}

2.4 용량 관련 인터페이스

size_t capacity()const
{
    
    
    return _endofstorage - _start;
}
size_t size()const
{
    
    
    return _finish - _start;
}

크기 조정():

 void resize(size_t n, const T& val)
        {
    
    
            if (n < size())
            {
    
    
                _finish = _start + n;
            }
            else
            {
    
    
                reserve(n);
                while (_finish != _start + n)
                {
    
    
                    *_finish = val;
                    _finish++;
                }
            }
        }
 void reserve(size_t n)
        {
    
    
            if (n > capacity())
            {
    
    
                size_t sz = size();
                T* tmp = new T[n];
                if (_start)
                {
    
    
                    memcpy(tmp, _start, sizeof(T) * size());
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + sz;
                _endofstorage = _start + n;
            }
        }

이것은 string 클래스와 거의 동일하므로 너무 많은 설명이 필요하지 않습니다.

2.5 스왑()

void swap(vector<T>v)
{
    
    
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_endofstorage, v._endofstorage);
}

2.6연산자 =

vector<T>& operator= (const vector<T>& v)
{
    
    
    swap(v);
    return *this;
}

2.7 푸시백()

void push_back(const T& x)
{
    
    
    if (_finish == _endofstorage)
    {
    
    
        reserve(capacity() == 0 ? 1 : capacity() * 2);
    }
    *_finish = x;
    _finish++;
}

2.8 삽입()

iterator insert(iterator pos, const T& val)
{
    
    
    assert(pos < _finish&& pos >= _start);
    if (_finish == _endofstorage)
    {
    
    
        size_t newpos = pos - _start;
        reserve(capacity() == 0 ? 1 : capacity() * 2);
        pos = _start + newpos;
    }
    iterator end = _finish - 1;
    while (end >= pos)
    {
    
    
        *(end + 1) = end;
        end--;
    }
    *pos = val;
    ++_finish;
    return pos;

}

2.9 지우기()

iterator erase(iterator pos)
{
    
    
    assert(pos < _finish&& pos >= _start);
    iterator it = pos + 1;
    while (it != _finish)
    {
    
    
        *(it - 1) = *it;
        it++;
    }
    _finish;
    return pos;
}

2.10 팝백()

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

2.11 연산자 []

T& operator[](size_t pos)
{
    
    
    assert(pos < size());

    return _start[pos];
}

const T& operator[](size_t pos) const
{
    
    
    assert(pos < size());

    return _start[pos];
}

pos < _finish&& pos >= _start);
반복자 it = pos + 1;
while (it != _finish)
{ *(it - 1) = *it; 그것++; } _완료; 반환 위치; }






## 2.10 pop_back()

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

2.11 연산자 []

T& operator[](size_t pos)
{
    
    
    assert(pos < size());

    return _start[pos];
}

const T& operator[](size_t pos) const
{
    
    
    assert(pos < size());

    return _start[pos];
}

추천

출처blog.csdn.net/qq_62839589/article/details/131859153