헤일로 뿌아입니다. 보통은 주로 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 생성자의 사용을 보려면 코드로 직접 이동하십시오.
- 기본 생성자:
vector (const allocator_type& alloc = allocator_type());
그중에서 const allocator_type& alloc = allocator_type()은 정렬, 버퍼 풀 등과 같은 특수한 메모리 관리 동작을 구현하기 위해 사용자 지정 할당자를 만드는 데 사용됩니다. C++ 초보자 단계에서는 기본 메모리 할당만 사용하면 됩니다. 전략.
따라서 기본 생성자는 다음과 같이 사용합니다.
vector<T>v;
vector<int>v;
-
패딩 생성자:
vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());
n개 값으로 컨테이너 채우기
vector<int>v(5,1);
-
반복자 생성자를 사용하십시오 .
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에 넣습니다.
- 복사 생성자 :
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 매개변수가 있는 기본 생성자
-
채워진 모양 생성자:
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를 따로 다루어야 해서 두 번째가 있습니다.
-
구성에 벡터 유형 사용:
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];
}