본문 바로가기

기초 문법 알아보기 Java

컬렉션 프레임웍 Collection Framework : ArrayList, LinkedList

728x90

ArrayList

ArrayList는 List 인터페이스를 구현하기 때문에 데이터의 저장순서가 유지되고 중복을 허용한다는 특징을 갖는다.

ArrayList는 Object배열을 이용해서 데이터를 순차적으로 저장한다. Object 배열을 이용하기 때문에 모든 종류의 객체를 담을 수 있다.

 

1) 데이터 추가

  1. boolean add(E e) : 리스트의 끝에 데이터 e를 추가합니다. 
  2. void add(int index, E element) : index의 위치에 데이터 element를 추가합니다. 
  3. boolean addAll(Collection<? extends E> c) : 리스트의 끝에 컬렉션 c의 모든 데이터를 추가합니다. 
  4. boolean addAll(int index, Collection<? extends E> c) : index의 위치에 컬렉션 c의 모든 데이터를 추가합니다.

 

2) 데이터 삭제

  1. void clear( ) : 리스트의 모든 데이터를 삭제합니다. 
  2. E remove(int index) : index의 위치에 있는 데이터를 삭제합니다. 
  3. boolean remove(Object o) : 리스트에서 Object o와 처음 일치하는 데이터를 삭제합니다. 
  4. boolean removeAll(Collection<?> c) : 리스트에서 컬렉션 c와 일치하는 모든 데이터를 삭제합니다. 
  5. boolean retainAll(Collection<?> c) : 리스트에서 컬렉션 c와 일치하는 데이터만 남기로 나머지는 삭제합니다. 

 

3) 데이터 확인

  1. int size( ) : 리스트의 데이터 개수를 반환합니다.  
  2. boolean isEmpty( ) : 리스트가 비어있는지 여부를 반환합니다. (비어있을 경우 true)
  3. boolean contains(Object o) : 리스트에 Object o가 포함되어 있는지 여부를 반환합니다. (포함된 경우 true)
  4. int indexOf(Obejct o) : 리스트에서 Object o와 처음 일치하는 데이터의 index 정보를 반환합니다. (없을경우 -1 반환)
  5. int lastIndexOf(Obejct o) : 리스트에서 Object o와 마지막으로 일치하는 데이터의 index 정보를 반환합니다. (없을경우 -1 반환)

 

4) 데이터 반환

  1. E get(int index) : 리스트에서 index의 위치에 있는 데이터를 반환합니다. 
  2. Object[ ] toArray( ) : 리스트의 모든 데이터가 포함된 Object 배열을 반환합니다.  
  3. <T> T[ ] toArray(T[ ] a) : 리스트의 모든 데이터를 배열 a에 담은 후 배열 a를 반환합니다. 

 

5) 데이터 변경

  1. E set(int index, E element) : index의 위치에 있는 데이터를 element로 변경합니다. 

 

6) 기타

  1. void trimToSize( ) : 리스트의 현재 size로 capacity를 조절합니다. 

출처: https://kadosholy.tistory.com/118 

 

import java.util.*;

class ArrayListEx1{
	public static void main(String[] args){
    	ArrayList list1 = new ArrayList(10);
        list1.add(new Integer(5));
        list1.add(new Integer(4));
        list1.add(new Integer(2));
        list1.add(new Integer(0));
        list1.add(new Integer(1));
        list1.add(new Integer(3));
        
        ArrayList list2 = new ArrayList(list1.subList(1,4));
        print(list1,list2);
        // 출력 : 
        // list1:[5, 4, 2, 0, 1, 3]
        // list2:[4, 2, 0]
        
        Collection.sort(list1); // list1과 list2를 정렬한다.
        Collection.sort(list2);
        print(list1, list2);
        // 출력 : 
        // list1:[0, 1, 2, 3, 4, 5]
        // list2:[0, 2, 4]
        
        System.out.println("list1.containAll(list2) : " + list1.containsAll(list2));
        // 출력 :
        // list1.containAll(list2) : true
        
        list2.add("B");
        list2.add("C");
        list2.add("A");
        print(list1,list2);
        // 출력 : 
        // list1:[0, 1, 2, 3, 4, 5]
        // list2:[0, 2, 4, A, B, C]
        
        list2.set(3, "AA");
        print(list1, list2);
        // 출력 : 
        // list1:[0, 1, 2, 3, 4, 5]
        // list2:[0, 2, 4, AA, B, C]
        
        // list1에서 list2와 겹치는 부분만 남기고 나머지는 삭제한다.
        System.out.println("list1.retainAll(list2) : "+list.retainAll(list2));
        print(list1,list2);
        // 출력 :
        // list1.retainAll(list2) : true
        // list1:[0, 2, 4]
        // list2:[0, 2, 4, AA, B, C]
        
        // list2에서 list1에 포함된 객체들을 삭제한다.
        for(int i=list2.size()-1;i>=0;i--){
        	if(list1.contains(list2.get(i)))
            	list2.remove(i);
        }
        print(list1,list2);
        // 출력 :
        // list1:[0, 2, 4]
        // list2:[AA, B, C]
    }
    static void print(ArrayList list1, ArrayList list2){
    	System.out.println("list1:"+list1);
        System.out.println("list2:"+list2);
        System.out.println();
    }
}

 

import java.util.*;

class ArrayListEx2{
	public static void main(String[] args){
    	final int LIMIT = 10; // 자르고자 하는 글자의 개수를 지정한다.
        String source = "1234567890abcdefghijABCDEFGHIJ!@#$%^&*()zzz";
        int length = source.length();
        
        List list = new ArrayList(length/LIMIT + 10); // 크기를 여유롭게 잡는다.
        
        for(int i=0;i<length;i+=LIMIT){
        	if(i+LIMIT < length)
            	list.add(source.substring(i,i+LIMIT));
            else
            	list.add(source.substring(i));
        }
        
        for(int i=0; i<list.size();i++){
        	System.out.println(list.get(i));
            // 출력 : 
            // 1234567890
            // abcdefghij
            // ABCDEFGHIJ
            // !@#$%^&*()
            // zzz
        }
    }
}

 

 

LinkedList

배열은 데이터를 읽어 오는데 걸리는 시간(접근시간)이 가장 빠르다는 장점을 가지고 있지만 다음과 같은 단점이 있다.

1. 크기를 변경할 수 없다.

2. 비순차적인 데이터의 추가 또는 삭제에 많은 시간이 소요된다.

이러한 단점을 보안하기 위해서 LinkedList라는 자료구조가 고안되었다. 배열은 모든 데이터가 연속적으로 존재하지만 LinkedList는 불연속적으로 존재하는 데이터를 서로 연결한 형태로 구성되어 있다.

 

배열과 LinkedList

위 그림처럼 LinkedList의 각 Node들은 요소에 대한 참조(주소값)와 데이터로 구성되어 있다.

 

class{
	Node next; // 다음 요소의 주소를 저장
    Object obj // 데이터를 저장
}

 

LinkedList는 이동방향이 단방향이기 때문에 다음 요소에 대한 접근은 쉽지만 이전요소에 대한 접근은 어렵다. 이 점을 보완한 것이 doubly linked list 이다.

doulby-linked list 구조

class{
	Node next; // 다음 요소의 주소를 저장
    Node prev; // 이전 요소의 주소를 저장
    Object obj; // 데이터를 저장
}

 

doubly-linked list보다 접근성이 개선된 것이 doubly-circular linked list이다. 단순히 doulby-linked list의 첫 번째 요소와 마지막 요소를 서로 연결시킨 것이다. 이러한 구조는 TV 채널을 순회하거나 오디오 플레이어같이 데이터를 순차적으로 처리하다 마지막 요소를 만나면 다시 처음으로 돌아가는 어플리케이션에서 사용된다. 

 

doubly-circular lined list 구조

객체생성

LinkedList<Integer> list = new LinkedList<>(); 
LinkedList<Integer> list2 = new LinkedList<Integer>(Arrays.asList(1,2)); // 생성시 초기값 설정

 

LinkedList의 선언은 ArrayList와 동일하지만 ArrayList처럼 초기값을 미리 지정하지 못한다. 배열처럼 미리 공간을 할당하고 사용하는 방식이 아니라 데이터가 추가될 때마다 노드들이 생성되어 동적으로 추가되기 때문이다.

 

요소추가 / 삽입

LinkedList<String> list = new LinkedList<>(Arrays.asList("A","B","C"));
list.addFirst("new"); // 가장 앞에 데이터 추가

 

LinkedList<String> list = new LinkedList<>(Arrays.asList("A,B,C"));
list.addLast("new"); // 가장 뒤에 데이터 추가

 

LinkedList<String> list = new LinkedList<>(Arrays.asList("A","B","C"));
list.add(1,"new"); // index 1 위치에 new 추가

 

객체 삭제

LinkedList list = new LinkedList<>(Arrays.asList("A","B","C"));
list.removeFirse(); // 첫번째 값 제거
list.removeLast(); // 마지막 값 제거
list.remove(1); // index값 제거

 

요소 검색

LinkedList<String> list1 = new LinkedList<>(Arrays.asList("A","B","C"));
LinkedList<String> list2 = new LinkedList<>();
list2.add("A");
list2.add("B");
list2.add("C");

list1.indexOf("B") // 1 앞에서부터 검색
list1.lastIndexOf("D") // -1 뒤에서부터 검색
list1.containsAll(list2) // list1에 list2의 모든노드가 포함되어 있는지 확인

 

요소 순회

LinkedList<String> list = new LinkedList<>(Arrays.asList("A","B","C"));

for(Sting s : list){
	System.out.println(s);
}

Iterator it = list.iterator();
while(it.hasNext()){
	Stirng s = it.next();
    System.out.println(s);
}

ListIterator it = list.listIterator();
while(it.hasNext()){
	System.out.println(it.next());
}
while(it.hasPrevious()){
	System.out.println(it.previous());
}

 

Iterator는 Collection 인터페이스를 구현한 컬렉션에서 모두 사용할 수 있는 반면, ListIterator는 오로지 List 컬렉션에서만 사용 가능하다.

ListIterator는 Iterator 인터페이스를 상속받아 여러 기능을 추가한 인터페이스로서 Iterator는 요소에 접근할 때 단방향만 가능한 반면, ListIterator는 양방향으로 이동이 가능하다.

 

LinkedList 동기화 처리

멀티 쓰레드 환경에서 동시에 컬렉션에 접근하여 문제가 발생하는 것을 막기 위해 동기화 처리된 리스를 반환받아 사용할 수 있다.

list<String> list1 = Collections.synchronizedList(new ArrayList<>());
list<String> list2 = Collections.synchronizedList(new LinkedList<>());