Computer Science/Data Structure

[실전 알고리즘] 배열

do_hyuk 2024. 1. 3. 14:30

지금까지 프로그래밍 언어의 관점에서 배열을 다뤘었기 때문에 자료구조로써의 배열을 익힐 필요가 있어 공부하였다.

 

1. 정의와 성질

배열의 정의

배열이란 메모리 상에 원소를 연속하게 배치한 자료구조를 말한다.

C++에서는 이미 선언된 배열의 길이를 변경하는게 불가능하지만, 자료구조로써의 배열에서는 길이를 마음대로 늘리거나 줄일 수 있다고 생각하겠다.

 

배열의 성질

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

- 시작 주소에서 k칸 만큼 오른쪽으로 가면 되기 때문

 

2. 추가적으로 소모되는 메모리의 양(=overhead)가 거의 없음

- 다른 자료구조와는 다르게 추가적으로 소모되는 메모리 양이 거의 없슴

 

3. Cache hit rate가 높음

- 메모리 상에 데이터들이 붙어있으니까 Cache hit rate가 높다.

 

4. 메모리 상에 연속한 구간을 잡아야 해서 할당에 제약이 걸림

- 메모리 상에 연속한 구간을 잡아야 하니 할당에서 다소 제약이 있다.


2. 기능과 구현

O(1)

- 임의의 위치에 있는 원소를 확인하고 변경하는 연산

- 원소를 끝에 추가하는 연산

- 마지막 원소를 제거하는 것

 

O(N)

- 임의의 위치에 원소를 추가하는 과정

   (위치가 끝에 가까울수록 시간은 줄어들고, 앞에 가까울수록 시간은 늘어나지만 평균 N/2이니 O(N)이라고 해도 상관없다.)

 

- 임의의 위치에 있는 원소를 제거

   (임의의 위치에 있는 원소를 제거하면 그 이후에 있던 모든 원소들을 한 칸씩 땡겨와야 한다.)

#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[i+1] = arr[i] 방식은 Out of Range 예외가 발생할 수 있기에 사용 X
    }
    arr[idx] = num;
    len++;
}

// 구현해보기
void erase(int idx, int arr[], int& len){
  	int i;
    for(i=idx+1; i<len; i++){
    	arr[i-1] = arr[i]
    }
    arr[i] = 0;
    len--;
}

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();
}

배열 전체를 특정 값으로 초기화시킬 때에는 세 가지 방식이 있다.

첫 번째로 제일 코드가 짧은 방법으로 cstring 헤더에 있는 memset 함수를 사용하는 방식이다.

하지만 이 함수는 실수할 여지가 굉장히 많기 때문에 비추천한다.

 

두 번째로는 그냥 for문을 돌면서 값을 하나하나 다 바꾸는 방식이고, 코드가 조금 투박하지만 실수할 여지가 없기에

무난하고 좋은 방법이다.

 

마지막으로 algorithm 헤더의 fill 함수를 이용하는 것이고, fill 함수는 실수할 여지도 별로 없고,

코드도 짧기에 가장 추천 드린다.

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

using namespace std;

int main(){
	vector<int> v(8);
    
    // 1번째 위치부터 4번째 위치까지 1로 할당
    fill(v.begin(), v.begin()+4, 1)
    
    return 0;
}

 

 

 

출처 - BarkingDog