배열

김정민·2020년 12월 12일
0

배열은 메모리 상에 원소를 연속하게 배치한 자료구조이다. 원래 C++에서 사용하는 배열에서는 배열을 선언한 뒤에는 배열의 길이를 변경하는게 불가능하지만, 자료구조라는 관점에서 배열의 길이를 마음대로 늘리거나 줄일 수 있다고 생각해보자.

1. 배열의 성질

  1. O(1)에 k번째 원소를 확인/변경 가능


배열은 그림과 같이 메모리 상에 원소를 연속하게 배치한 자료구조이기 때문에 k번째 원소의 위치를 바로 계산할 수 있다. 시작 주소에서 k칸 만큼만 오른쪽으로 이동하면 되기 때문이다.

  1. 추가적으로 소모되는 메모리의 양(=overhead)가 거의 없음
  1. Cache hit rate가 높음.
    캐시 작동 원리 : https://parksb.github.io/article/29.html
  1. 메모리 상에 연속한 구간을 잡아야 해서 할당에 제약이 걸림

2. 기능

  1. 임의의 위치에 있는 원소를 확인/변경 = O(1)
  1. 끝 부분에 원소 추가/끝 부분에 원소 제거 = O(1)
  1. 임의의 위치에 원소를 추가/제거 = O(N)

임의의 위치에 원소를 추가하거나 제거하는 과정은 O(N)이다. 추가할 때에는, 특정 위치에 원소를 추가하고 그 뒤에 위치한 원소들을 전부 한 칸씩 뒤로 밀어야 한다. 제거 역시 특정 위치에 있는 원소를 제거하고 나서 뒤에 있는 원소들을 전부 한 칸씩 앞으로 당겨와야 하기 때문이다.

그렇기 때문에 추가/제거 하려는 원소의 위치가 배열의 끝 부분에 가까울수록 시간이 줄어들고, 앞에 가까울 수록 시간은 늘어나지만 평균적으로 N/2개의 원소를 움직여야 하니 O(N)이라고 말 할 수 있다.

3. 구현

임의의 위치에 원소를 추가/제거하는 기능 구현

#include <bits/stdc++.h>
using namespace std;

void insert(int idx, int num, int arr[], int& len) {

	for (int i = len; i > idx; i--) {
		arr[i] = arr[i - 1];
	}
	arr[idx] = num;
	len++;
}

void erase(int idx, int arr[], int& len) {
	len--;
	for (int i = idx; i < len; i++) {
		arr[idx] = arr[idx + 1];
	}
}

void printArr(int arr[], int& len) {
	for (int i = 0; i < len; i++) cout << arr[i] << ' ';
	cout << "\n\n";
}

void insert_test() {
	cout << "***** insert_test *****\n";
	int arr[10] = { 10, 20, 30 };
	int len = 3;
	insert(3, 40, arr, len); // 10 20 30 40
	printArr(arr, len);
	insert(1, 50, arr, len); // 10 50 20 30 40
	printArr(arr, len);
	insert(0, 15, arr, len); // 15 10 50 20 30 40
	printArr(arr, len);
}

void erase_test() {
	cout << "***** erase_test *****\n";
	int arr[10] = { 10, 50, 40, 30, 70, 20 };
	int len = 6;
	erase(4, arr, len); // 10 50 40 30 20
	printArr(arr, len);
	erase(1, arr, len); // 10 40 30 20
	printArr(arr, len);
	erase(3, arr, len); // 10 40 30
	printArr(arr, len);
}

int main(void) {
	insert_test();
	erase_test();
}

4. STL vector

레퍼런스 : http://www.cplusplus.com/reference/vector/vector/

vector는 배열과 거의 동일한 기능을 수행하는 자료구조이다. 하지만 크기를 자유자재로 늘이거나 줄일 수 있다는 장점이 있다. vector끼리 = 연산자를 사용하게 되면 deep copy가 일어나 서로에게 영향을 주지 않는다.

또한 vector에 있는 모든 원소를 순회하기 위해 범위 기반 반복문(range-based for loop, C++ 11 이상)을 사용할 수 있다.

5. 관련 문제

알파벳 갯수
https://www.acmicpc.net/problem/10808

문제)
주어진 길이 N의 int 배열 arr에서 합이 100인 서로 다른 위치의 두 원소가 존재하면 1을, 존재하지 않으면 0을 반환하는 함수 func2(int arr[], int N)을 작성하라. arr의 각 수는 0이상 100이하이고 N은 1000이하다.

func2({1, 52, 48}, 3) = 1,
func2({50,42}, 2) = 0,
func2({4,13,63,87}, 4)=1

6. 참고 사이트

https://blog.encrypted.gg/927?category=773649

0개의 댓글