Array 배열
Array 배열
정의
메모리 상에 원소를 연속하게 배치한 자료구조
성질
메모리에 연속하게 배치
임의접근 Random-Access
특정 위치를 알고 싶다면? 그냥 시작 위치에서 데이터 크기 * 위치를 더해주면 바로 알 수 있음
메모리 상에 ‘연속하게’ 위치해 있으니까
Like 영화관에서 지인들과 나란히 좌석을 예매할 때
다른 지인이 더 온다면, 나란히 않기 위해서 연속된 자리를 찾아 이동해야 함
더 많은 지인이 올 수록, 예매는 비용도 커지고 이동도 힘들어짐
실패할 수도 있음! 연속된 자리가 없다면 ! (메모리가 부족하면 실패할 수 있는 건 당연하지만, 여기서 말하고자 하는건 ‘연속된’ 메모리 공간이 없다면!)
배열에 새 원소를 추가하는 일은 쉽지 않은 일
미리 충분한 좌석을 예매한다면
추가할 일이 생기지 않는 다면 메모리 낭비 (배열에서 쓰지도 않지만, 다른 쪽에서도 못씀)
만약에 지인이 미리 예매해둔 양보다 많아진다면 어차피 다시 예매해야 함
좋은 해결책이지만, 완벽하지는 않음
-> 연결 리스트
- O(1)에 k번째 원소를 확인/변경 가능
- 추가적으로 소모되는 메모리의 양(=overhead)가 거의 없음
- Cache hit rate가 높음
메모리 상에 연속한 구간을 잡아야 해서 할당에 제약이 걸림
- 자료구조로써의 배열, 길이를 마음대로 늘리거나 줄이는게 가능하다고 생각
시간복잡도
- 임의의 위치에 있는 원소를 확인/변경, O(1)
- 원소를 끝에 추가, O(1)
- 마지막 원소를 제거, O(1)
- 임의의 위치에 원소를 추가/제거, O(N)
사용
C++ Array
컴파일 시간에 크기가 결정되고 더 이상 크기의 변경이 불가능한 정적 배열
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Declaration & Definition & Init
int a[21]; // [21]: Index 색인/Subscript 첨자
int b[21][21];
int c[21] = { 1, 2, 3 }; // { 1, 2, 3, 0, 0 }
int d[] = { 1, 2, 3 };
int d[] { 1, 2, 3 }; // Universal Initialization
// 1. memset
#include <cstring>
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
// 2. for
for (int i = 0; i < 21; i++)
a[i] = 0;
for (int i = 0; i < 21; i++)
for (int j = 0; j < 21; j++)
b[i][j] = 0;
// 3. fill
#include <algorithm>
fill(a, a + 21, 0);
for (int i = 0; i < 21; i++)
fill(b[i], b[i] + 21, 0);
C++ STL vector
실행시간에 크기를 변경할 수 있는 동적 배열
메모리 연속하게 저장
크기를 자유자재로 늘리거나 줄이거나
그래프의 인접 리스트라는 것을 저장할 때에는 vector를 쓰는게 많이 편해서 vector가 필요하게 되지만,
그 전까지는 사실 굳이 배열대신 vector를 써야하는 상황은 없다.
생성과 소멸을 하는데 상당한 시간이 소요된다. (성능)
1
2
3
4
5
6
7
8
9
10
// Declaration & Definition & Init
#include <vector>
vector<int> v1;
vector<int> v1 = { 0, 0, 0 };
vector<int> v1 { 0, 0, 0 };
vector<int> v1(1); // { 0 };
vector<int> v1(size); // 변수, 동적 생성 시
vector<int> v1(3, 4); // { 4, 4, 4 };
vector<int> v1.assign(3, 4); // { 4, 4, 4 };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Use
v1.size();
v1.push_back(1);
v1.pop_back();
v1.clear();
// iterator
v1.begin(); // 시작 주소
v1.end(); // 끝 주소 + 1
v1.rbegin(); // (끝 주소)를 시작으로
v1.rend(); // (시작 주소 + 1) 을 끝으로
v1.insert(v1.begin() + 1, 1); // { 0, 3, 0 };
v1.erase(v1.begin() + 1); // { 1, 2, 4 };
// Deep Copy (이것은 연산자 중복 정의)
v1 = v2;
// 요소의 개수와 값이 모두 일치하면 true (이것 역시 연산자 중복 정의)
(v1 == v2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Traversal
// 1. range-based for loop (since C++11)
for (int e: v1)
for (int& e: v1)
// & <- list, map, set 등에서도 모두 사용할 수 있는
// 2. for (not bad)
for (int i = 0; i < v1.size(); i++)
// 2-1. ***WRONG***
// size()가 unsigned int이기 때문에,
// 빈 vector의 size() 0에서 -1을 해버리면
// (unsigned int)0 - (int)1 = 4294967295
for (int i = 0; i <= v1.size() - 1; i++)
C++ STL array
일부 함수를 제공하는 정적 배열
1
2
3
4
// Declaration & Definition & Init
#include <array>
array<int, 3> a { 1, 2, 3 };
1
2
3
4
5
6
7
// Use
a.size();
a.fill(1);
a.empty();
a.at();
a.front();
a.back();
메모
- @ TODO
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.