Array VS ArrayList VS LinkedList

코난·2023년 10월 8일
0

CS 면접 정리

목록 보기
2/67

Array

Array의 특징

  • 논리적 저장 순서와 물리적 저장 순서가 일치함
  • 인덱스로 해당 원소에 접근 가능
  • random access 가능
  • 삭제 또는 삽입 과정에서는 시간 복잡도가 커짐
  • 선언시 크기로 크기 고정
  • 같은 타입 데이터를 여러개 나열한 선형 자료구조

Array 사용이 유리한 상황

  • 데이터 개수가 확실하게 저장되어 있을 때
  • 삽입/삭제 작업이 적을때
  • 배열에 저장된 데이터를 검색하는 작업이 많을 때

배열 회전 프로그램

기본 회전 프로그램

<새로운 배열을 사용하는 경우>

public static void l_rotation(int arr[], int count) {
	int[] newArr = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
    	newArr[(arr.length - (count - i)) % arr.length] = arr[i];
    }
    arr = newArr;
}

<새로운 배열을 사용하지 않는 경우>

public static void l_rotations(int arr[], int count) {
	for (int i = 0; i < count; i++) {
    	int temp = arr[0];
        for (int j = 0; j < arr.length - 1; j++) {
        	arr[j] = arr[j + 1];
        }
        arr[j] = temp;
    }
}

temp 변수를 활용하여 첫번째 인덱스 값을 저장, arr[n]값을 arr[n - 1]에 넣어주고, arr[n]에는 temp 값을 넣어주면 완성!

저글링 알고리즘

최대공약수 gcd를 이용하여 집합을 나누고, 여러 요소를 한꺼번에 이동시키는 알고리즘

public static int gcd(int a, int b) {
	if (b == 0)
    	return a;
    else
    	return gcd(b, a % b);
}
public static void l_rotations(int arr[], int count) {
	for (int i = 0; i < gcd(count, arr.length); i++) {
    	int temp = arr[i];
        int j = i;
        while (1) {
        	int k = j + count;
            if (k >= arr.length)
            	k = k - arr.length;
            if (k == 1)
            	break;
            arr[j] = arr[k];
            j = k;
        }
        arr[j] = temp;
    }
}

역전 알고리즘

reverse를 이용하여 회전하는 알고리즘

public static void reverseArr(int arr[], int start, int end) {
	while (start < end) {
    	int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        start++;
        end--;
    }
}
public static void l_rotations(int arr[], int count) {
	reverseArr(arr, 0, count - 1);
    reverseArr(arr, count, arr.length - 1);
    reverseArr(arr, 0, arr.length - 1);
}

i * arr[i]의 sum 최대값

arr[i]의 전체합과 i x arr[i]의 전체합을 저장할 변수 선언
가장 큰 sum 값을 최종적으로 저장할 변수 선언
배열을 회전시키면서 i x arr[i]의 전체합 값을 저장하고, 가장 큰 값을 저장해서 출력

public static int maxVal(int arr[]) {
	int arrSum = 0; //arr 전체합
    int curSum = 0; //i*arr[i] 전체합
    
    for (int i = 0; i < arr.length; i++) {
    	arrSum = arrSum + arr[i];
        curSum = curSum + (i * arr[i]);
    } 
    int maxSum = curSum;
    for (int i = 1; i < arr.length; i++) {
    	curSum = curSum + arrSum - arr.length * arr[arr.length - i];
        if (curSum > maxSum)
        	max = curSum;
    }
    return maxSum;
}

arr[i] = i로 재배열

arr[i] = i가 없으면 -1로 채움
arr[i]가 -1이 아니고 arr[i]이 i가 아닐때가 우선 조건
해당 arr[i]값을 변수 x에 저장해두고 arr[x] 값이 -1이 아니고 x가 아닌 동안 반복
arr[x]값을 변수 y에 저장해두고 arr[x]에 위에서 저장해둔 x값을 대입, x값에는 y값을 대입
arr[x]에 x값을 넣어두고 만약 arr[i]가 i가 아니라면 arr[i]에 -1 대입

public static int fix(int arr[]) {
	for (int i = 0; i < arr.length; i++) {
    	if (arr[i] != -1 && arr[i] != i) {
        	int x = arr[i];
            while (arr[x] != -1 && arr[x] != x) {
            	int y = arr[x];
                arr[x] = x;
                x = y;
            }
            arr[x] = x;
            if (arr[i] != i) {
            	arr[i] = -1;
            }
        }
    }
}

LinkedList

LinkedList란?

  • 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료구조
  • 각 노드는 다음 노드를 가리키는 포인터를 포함함
  • 다음 노드를 가리키는 포인터는 다음 노드의 주소를 값으로 가짐
  • 각 노드의 포인터 변수는 다음 노드의 데이터의 주소를 값으로 가짐

LinkedList 사용 이유

배열의 한계를 극복하기 위해 사용하게 되었음

  • 배열의 단점
    • 배열의 크기가 고정되어 있어 미리 요소의 수에 대해 할당을 받아야 함
    • 새로운 요소를 삽입하는 것은 비용이 많이 듦

LinkedList의 장점

  • 동적 크기
  • 삽입/삭제 용이

LinkedList의 단점

  • 임의로 엑세스 허용 불가능. 첫번째 노드부터 순차적으로 요소에 엑세스해야함(이진 검색 수행 불가능 -> 검색 느림)
  • 포인터의 여분의 메모리 공간이 목록의 각 요소에 필요

LinkedList 사용법(JAVA)

import java.util.LinkedList;

LinkedList<Integer> i = new LinkedList<Integer>();

//값 추가
i.add(1);
i.add(2);

//n번째에 값 추가
i.add(1, 4); //index, 넣을 값

//값 수정
i.set(1, 3); //index, 바꿀 값

//첫번째 데이터 삭제
i.removeFirst();

//마지막 데이터 삭제
i.removeLast();

//n번째 데이터 삭제
i.remove(0); //명시하지 않으면 첫번째 데이터 삭제

//모든 데이터 삭제
i.clear();

//LinkedList의 크기
i.size();

ArrayList

ArrayList란?

  • 연속적인 데이터의 리스트
  • 인덱스를 이용하여 요소에 빠르게 접근 가능
  • 배열과 달리 가변적으로 공간 늘리거나 줄이기 가능
  • 삽입/삭제 동작 느림
  • 검색 속도 빠름
  • 객체로 데이터를 다루기에 적은양의 데이터만 사용할 경우 배열에 비해 차지하는 메모리가 커짐

ArrayList 사용법(JAVA)

import java.util.ArrayList;

ArrayList<Integer> i = new ArrayList<>(10);
ArrayList<Integer> i2 = new ArrayList<>(10);

//값 추가
i.add(1);
i.add(2);
i2.add(3);
i2.add(4);

//i에 i2의 데이터 추가
i.addAll(i2);

//n번째에 값 추가
i.add(2, 5);

//n번째 값 수정
i.set(1, 1); //index, 바꿀 값

//n번째 데이터 삭제
i.remove(2);

//모든 데이터 삭제
i.clear();

//값 있는지 검색
i.contains(3);

//값 있는지 검색하고 index 반환(없으면 -1)
i.indexOf(3);

//값 있는지 뒤에서부터 검색하고 index 반환(없으면 -1)
i.lastIndexOf(3);

//n번째 요소 얻기
i.get(3);

//부분 배열 반환
i.subList(0, 3); //0부터 3까지 인덱스의 값 list 형태로 반환

//ArrayList 크기
i.size();

Array VS ArrayList VS LinkedList

간단 비교

  • Array : index로 빠르게 값을 찾는 것이 가능
  • LinkedList : 데이터 삽입 및 삭제 빠름
  • ArrayList : 데이터 검색 빠르나 삽입 및 삭제 느림

array

  • 선언할 때 크기와 데이터 타입을 지정해야 함
  • index가 중요함
  • 크기가 늘거나 최대 사이즈를 모를때 사용 부적합
  • 데이터 삽입 및 삭제도 비효율적
  • 검색은 편함

ArrayList

  • 크기를 정해주지 않아도 됨
  • 순서가 중요함
  • 중간에 데이터 삽입과 삭제시 배열보다 효율적 (크기 안정해져 있어서), but 오래걸림
  • 검색 빠름

LinkedList

  • 한 노드에 연결될 노드의 포인터 위치를 가리키는 방식으로 되어있음
  • 중간에 데이터 삽입과 삭제시 빠름
  • 검색 느림
  • index 없어 처음부터 순차로 검색해야 함

관련 예상 질문

  • Array(List)의 가장 큰 특징과 그로 인해 발생하는 장단점에 대해 설명해주세요
    Array의 가장 큰 특징은 순차적으로 데이터를 저장한다는 점입니다. 데이터에 순서가 있어 index를 통한 접근이 가능합니다. 하지만 순차적으로 존재하기에 요소가 삽입되거나 삭제될 때 그 뒤 모든 요소들을 한 칸씩 밀거나 당겨줘야 하는 단점도 있습니다. 그렇기에 Array는 자주 삭제되거나 추가될 가능성이 있는 데이터를 담기에 적절하지 않습니다.

  • Array를 적용시키면 좋을 데이터의 예를 구체적으로 들어주세요.
    주식 차트에 대한 데이터는 요소가 중간에 새롭게 추가되거나 삭제되지 않으며 날짜별로 주식 가격이 차례로 저장되어야 합니다. 순서가 굉장히 중요하므로 Array와 같이 순서를 보장해주는 자료구조를 사용하는 것이 좋습니다.
    만약 Array를 사용하지 않고 순서가 없는 자료구조를 사용한다면 날짜별 주식 가격을 확인하기 어려우며 매번 전체 자료를 읽어들이고 비교해야 하는 번거로움이 발생합니다.

  • Array와 ArrayList의 차이점에 대해 설명해주세요
    Array는 크기가 고정적이지만 ArrayList는 크기가 가변적입니다. Array는 초기화시 메모리에 할당되어 ArrayList보다 속도가 빠르고, ArrayList는 데이터 추가 및 삭제 시 메모리를 재할당하기 때문에 속도가 Array보다 느립니다.

  • Array와 LinkedList의 장단점에 대해 말해주세요
    Array는 RandomAccess가 가능해 검색시 속도가 빠르다는 장점이 있습니다. 하지만 삽입 또는 삭제 과정에서 각 원소들을 shift 해줘야 하는 비용이 생겨 시간복잡도가 O(n)이 되는 단점이 있습니다.
    이를 해결하기 위해 나온 자료구조가 LinkedList입니다. 각각의 원소들은 자기 자신 다음에 어떤 원소인지만을 기억하고 있기 때문에 이 부분만 다른 값으로 바꿔주면 삽입과 삭제를 O(1)로 해결할 수 있습니다. 하지만 LinkedList는 원하는 위치에 한 번에 접근할 수 없기 때문에 검색이 느리다는 단점이 있습니다.

profile
몸은 커졌어도, 머리는 그대로... 하지만 불가능을 모르는 명탐정 현아! 진실은 언제나 하나!

0개의 댓글