Programming Language/Java

[Java] ArrayList와 배열(Array)의 중복 제거

개발왕 금골드 2020. 7. 1. 13:51
반응형

안녕하세요 골드입니다.

 

1. 프레임워크

 

 오늘은 Java의 컬렉션 프레임워크에서 가장 많이 사용하는 것으로 보이는 ArrayList에 대해서 글을 작성하도록 하겠습니다. 먼저 컬렉션 프레임워크(Collections Framework)란 다수의 데이터를 다루기 위한 프로그래밍 방식을 의미합니다. 컬렉션 프레임워크는 다양한 클래스를 제공함으로써 프로그래머에게 많은 도움을 줍니다. 또한 객체지향적 설계를 통해 재사용성이 높다는 장점을 가지고 있습니다.

 

 자바에서 컬렉션 프레임워크는 크게 세 가지의 인터페이스를 정의합니다. List, Set, Map이라는 대표적인 인터페이스들이 존재하는데 각각의 인터페이스들은 그 특징을 가지고 있습니다. ArrayList는 이 중 List에 속한 클래스입니다. List는 데이터를 저장할 때, 중복을 허용하며 순차적으로 저장된다는 특징이 있습니다.

 예를 들면, 첫 번째로 저장한 데이터는 0번째 위치에 저장되고 그 다음은 1번째 ... 이런 식으로 저장된다는 것이 List의 특징입니다.

 

2. ArrayList와 다양한 메서드

 

 

 

 ArrayList의 코드를 보면 안에서 Object형식의 배열로 선언됨을 알 수 있습니다. Object형식은 최상위 부모 클래스입니다. Object형식은 모든 객체를 담을 수 있습니다. ArrayList를 선언하는 방법은 세 가지가 있습니다.

 

ArrayList()

크기가 10인 ArrayList 생성

ArrayList(Collection c)

주어진 컬렉션이 저장된 ArrayList 생성

ArrayList(int initialCapacity)

초기용량을 설정한 ArrayList 생성

 

 컬렉션 프레임워크에 정의된 다양한 인터페이스들은 서로 형변환이 가능하다는 특징이 있습니다. 그렇기 때문에 Collection형식의 매개변수를 가지고 있는 메서드에 List형식이 아닌 Set이나 다른 형식의 데이터를 삽입하여 해당 형식의 데이터를 ArrayList 형식으로 형변환 할 수 있습니다. 

 

 

 

 

 생성자 중 초기용량을 설정하는 생성자입니다. 초기용량을 음수값으로 설정했을 경우 Exception이 발생합니다.

 

다음으로 ArrayList에서 사용하는 몇 가지 메서드를 소개하겠습니다.

 

boolean add(Object o)

ArrayList의 끝에 객체를 추가. 성공한 경우 true를 반환.

void sort(Comparator c)

정렬기준으로 ArrayList를 정렬.

void clear()

ArrayList를 비움.

Object get(int index)

index 위치에 있는 저장된 객체를 반환.

boolean isEmpty()

ArrayList가 비어있는지 확인.

Iterator iterator()

ArrayList의 iterator 객체 반환.

Object remove(int index)

index 위치에 있는 객체 제거.

int size()

ArrayList에 저장된 객체 개수 반환.

 

 sort 메서드는 Comparator 객체를 정의한 후 매개변수로 넘겨주면 정의된 방식대로 ArrayList를 정렬하는 메서드입니다. 기본적으로 Comparator 객체는 오름차순으로 정렬되도록 선언되어 있습니다. 만약 다른 방식으로 정렬하기를 원한다면 compare() 메서드를 재정의하여 사용하는 방법이 있습니다.

 

 iterator 메서드는 해당 Collection의 iterator 객체를 가져오는 메서드입니다. iterator 객체를 사용하여 다음에 읽어올 값이 존재하는지 여부를 알 수 있으며, 해당 값을 가져오거나 제거할 수도 있습니다.

 

예를 들면 다음과 같습니다.

 

ArrayList list = new ArrayList(10);

list.add(1);

list.add(2);

list.add(3);

 

Iterator it = list.iterator();

 

while(it.hasNext()) { //iterator 객체로 읽어올 값이 있는지 확인합니다.

     Object obj = it.next(); //해당 값을 obj 변수에 담습니다.

     System.out.print(obj + " "); //출력합니다.

}

 

실행결과

1 2 3

이 출력될 것입니다.

 

3. 용량(capacity)과 크기(size)

ArrayList는 배열의 크기를 늘릴 수 있습니다.

 

예를 들어

ArrayLits list = new ArrayList(5);

list.add("a");

list.add("b");

list.add("c");

라는 코드가 있다면 이 ArrayList의 용량은 5이고 크기는 3입니다.

용량은 ArrayList에 변수를 얼마나 담을 수 있는지 나타내는 수이고,

크기는 변수가 얼마나 있는지를 나타내는 값이기 때문입니다.

 

 

 

 

 

그런데 만약 여기서 trimToSize() (빈 공간을 없애서 용량과 크기를 맞추는 메서드)를 사용하거나 용량보다 더 많은 변수를 담기 위해 코드를 작성한다면 해당 배열의 용량을 변경해야 합니다. 하지만 배열은 용량을 변경할 수 없습니다.

 

그럼 ArrayList는 내부적으로 어떻게 작동하느냐?

배열을 복사합니다.

배열의 용량을 늘이거나 줄이는 것은 불가능하기 때문에 해당 용량보다 정해진 만큼 크거나 작게 배열을 복사해서 마치 용량을 늘이거나 줄인 것처럼 보이게 만드는 것입니다. 

 

 

 

 

(만약 용량이 부족할 경우 자동적으로 크기를 2배 늘려서 용량을 확보합니다.)

 

list가 trimToSize()를 하기 전에 가리키고 있었던 배열은 이후에 자바의 가비지 컬렉터에 의해서 제거됩니다. 중요한 점은 이러한 작업들은 효율을 상당히 떨어뜨린다는 단점이 있습니다. 그렇기 때문에 초기에 생성할 때 충분한 용량의 인스턴스를 생성한 후 사용하는 것이 좋습니다. 

 

4. 배열의 중복 제거

알고리즘 문제를 풀다 보면 배열의 중복을 제거해야하는 상황이 종종 있습니다.

 문제뿐만 아니라 종종 이런 상황이 있습니다. 배열은 수정이 불가능하기 때문에 새로운 배열이나 다른 자료구조를 사용해서 중복을 삭제하고 복사해야합니다. 저는 ArrayList를 사용하겠습니다.

 

 

 ArrayList에 contains메서드를 사용합니다. list에 특정 값이 존재하는지 여부를 파악한 후 없으면 list에 add메서드로 값을 추가하고 있으면 아무 일도 일어나지 않습니다. print 메서드로 찍어보면 중복이 제거된 것을 볼 수 있습니다.

 

지금까지 ArrayList라는 자료구조에 대해서 살펴봤습니다.

 ArrayList는 분명 데이터를 읽고 저장하는데 효율이 좋고 순차적으로 데이터를 추가, 삭제하는 데 빠르지만 용량을 변경하는 과정에서 효율이 떨어진다는 점과 데이터의 추가와 삭제가 불리하다는 단점이 있습니다. 물론 그럼에도 불구하고 변경이 가능하다는 점은 일반 배열과는 또 다른 ArrayList만에 특징이라고 할 수 있겠습니다. 다양한 자료구조를 가지고 있는만큼 적절한 곳에 적절한 자료구조를 사용할 수 있도록 공부해야겠습니다.

 

여기까지 골드였습니다.

감사합니다.

 

참고자료 :
남궁성 Java의 정석 3판 도우출판 p578, p584, p589

반응형