Language/Java

[Java] 자바 컬렉션 프레임워크 - List 컬렉션 클래스

재은초 2024. 4. 14. 19:31
반응형

List 컬렉션 클래스

  • List 인터페이스를 구현한 모든 List 컬렉션 클래스는 1. 요소의 저장 순서가 유지하고, 2. 같은 요소의 중복 저장을 허용하는 특징을 가진다.

ArrayList<E> 클래스

  • ArrayList 클래스는 가장 많이 사용되는 컬렉션 클래스 중 하나다.
  • ArrayList 클래스는 내부적으로 배열을 이용하여 요소를 저장한다.
  • ArrayList 클래스는 배열을 이용하기 때문에 인덱스를 이용해 배열 요소에 빠르게 접근할 수 있다. 하지만 배열은 크기를 변경할 수 없는 인스턴스이므로, 크기를 늘리기 위해서는 새로운 배열을 생성하고 기존의 요소들을 옮겨야 하는 복잡한 과정을 거쳐야 한다. 물론 이 과정은 자동으로 수행되지만, 요소의 추가 및 삭제 작업에 걸리는 시간이 매우 길어지는 단점을 가지게 된다.
ArrayList<Integer> arrList = new ArrayList<Integer>();
 
// add() 메소드를 이용한 요소의 저장
arrList.add(40);
arrList.add(20);
arrList.add(30);
arrList.add(10);
 
// for 문과 get() 메소드를 이용한 요소의 출력
for (int i = 0; i < arrList.size(); i++) {
    System.out.print(arrList.get(i) + " ");
}
 
// remove() 메소드를 이용한 요소의 제거
arrList.remove(1);
 
// Enhanced for 문과 get() 메소드를 이용한 요소의 출력
for (int e : arrList) {
    System.out.print(e + " ");
}
 
// Collections.sort() 메소드를 이용한 요소의 정렬
Collections.sort(arrList);
 
// iterator() 메소드와 get() 메소드를 이용한 요소의 출력
Iterator<Integer> iter = arrList.iterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}
 
// set() 메소드를 이용한 요소의 변경
arrList.set(0, 20);
 
for (int e : arrList) {
    System.out.print(e + " ");
}

// size() 메소드를 이용한 요소의 총 개수
System.out.println("리스트의 크기 : " + arrList.size());

>> 40 20 30 10 
>> 40 30 10
>> 10 30 40 
>> 20 30 40
>> 리스트의 크기 : 3

LinkedList<E> 클래스

  • LinkedList 클래스는 ArrayList 클래스가 배열을 이용하여 요소를 저장함으로써 발생하는 단점을 극복하기 위해 고안되었다.
  • LinkedList 클래스는 내부적으로 연결 리스트(linked list)를 이용하여 요소를 저장한다.
  • 배열은 저장된 요소가 순차적으로 저장되지만, 연결 리스트는 저장된 요소가 비순차적으로 분포되며, 이러한 요소들 사이를 링크(link)로 연결하여 구성한다.

  • 다음 요소를 가리키는 참조만을 가지는 연결 리스트를 단일 연결 리스트(singly linked list)라고 한다.
  • 단일 연결 리스트는 요소의 저장과 삭제 작업이 다음 요소를 가리키는 참조만 변경하면 되므로, 아주 빠르게 처리될 수 있다.
  • 하지만 단일 연결 리스트는 현재 요소에서 이전 요소로 접근하기가 매우 어렵다. 따라서 이전 요소를 가리키는 참조도 가지는 이중 연결 리스트(doubly linked list)가 좀 더 많이 사용된다.
  • LinkedList 클래스도 위와 같은 이중 연결 리스트를 내부적으로 구현한 것이다. 또한, LinkedList 클래스 역시 List 인터페이스를 구현하므로, ArrayList 클래스와 사용할 수 있는 메소드가 거의 같다.

 

 

LinkedList<String> lnkList = new LinkedList<String>();

// add() 메소드를 이용한 요소의 저장
lnkList.add("넷");
lnkList.add("둘");
lnkList.add("셋");
lnkList.add("하나");

// for 문과 get() 메소드를 이용한 요소의 출력
for (int i = 0; i < lnkList.size(); i++) {
    System.out.print(lnkList.get(i) + " ");
}

// remove() 메소드를 이용한 요소의 제거
lnkList.remove(1);

// Enhanced for 문과 get() 메소드를 이용한 요소의 출력
for (String e : lnkList) {
    System.out.print(e + " ");
}

// set() 메소드를 이용한 요소의 변경
lnkList.set(2, "둘");

for (String e : lnkList) {
    System.out.print(e + " ");
}

// size() 메소드를 이용한 요소의 총 개수
System.out.println("리스트의 크기 : " + lnkList.size());

>> 넷 둘 셋 하나
>> 넷 셋 하나
>> 넷 셋 둘
>> 리스트의 크기 : 3

Vector<E> 클래스

  • Vector 클래스는 JDK 1.0부터 사용해 온 ArrayList 클래스와 같은 동작을 수행하는 클래스다. 현재의 Vector 클래스는 ArrayList 클래스와 마찬가지로 List 인터페이스를 상속받는다. 따라서 Vector 클래스에서 사용할 수 있는 메소드는 ArrayList 클래스에서 사용할 수 있는 메소드와 거의 같다.
  • 하지만 현재에는 기존 코드와의 호환성을 위해서만 남아있으므로, Vector 클래스보다는 ArrayList 클래스를 사용하는 것이 좋다.

Stack<E> 클래스

  • Stack 클래스는 List 컬렉션 클래스의 Vector 클래스를 상속받아, 전형적인 스택 메모리 구조의 클래스를 제공한다.
  • 스택 메모리 구조는 선형 메모리 공간에 데이터를 저장하면서 후입선출(LIFO)의 시멘틱을 따르는 자료 구조다. 즉, 가장 나중에 저장된(push) 데이터가 가장 먼저 인출(pop)되는 구조다.

  • Stack 클래스는 스택 메모리 구조를 표현하기 위해, Vector 클래스의 메소드를 5개만 상속받아 사용한다.

  • 더욱 복잡하고 빠른 스택을 구현하고 싶다면 Deque 인터페이스를 구현한 ArrayDeque 클래스를 사용하면 된다.
Deque<Integer> st = new ArrayDeque<Integer>();
Stack<Integer> st = new Stack<Integer>(); // 스택의 생성
//Deque<Integer> st = new ArrayDeque<Integer>();
 
// push() 메소드를 이용한 요소의 저장
st.push(4);
st.push(2);
st.push(3);
st.push(1);

// peek() 메소드를 이용한 요소의 반환
System.out.println(st.peek());
System.out.println(st);

// pop() 메소드를 이용한 요소의 반환 및 제거
System.out.println(st.pop());
System.out.println(st);

// search() 메소드를 이용한 요소의 위치 검색
// ArrayDeque 클래스는 search() 메소드는 지원하지 않음
System.out.println(st.search(4));
System.out.println(st.search(3));

>> 1
>> [4, 2, 3, 1]
>> 1
>> [4, 2, 3]
>> 3
>> 1

List 인터페이스 메소드

  • List 인터페이스는 Collection 인터페이스를 상속받으므로, Collection 인터페이스에서 정의한 메소드도 모두 사용할 수 있다.

 

Reference

반응형