본문 바로가기

Java/Java 2

[Java] 6. 자료구조와 컬렉션프레임워크

반응형

1. 자료구조

: 프로그램에서 데이터를 처리하기 위해 만든 구조

-> Array, List, Map, [Tuple, Dictionary]

 

1) 배열 (Array)

-하나의 변수명으로 여러개의 데이터를 처리가능

-데이터를 순차적으로 저장 [0부터 시작하는 인덱스로 접근]

 

  • 고정된 크기
  • 데이터의 위치를 모르는 경우 효율이 떨어짐.
  • 모두 동일한 자료형인 데이터
  • 배열 중간에 값을 추가 -> 기존 데이터를 모두 이동해야 한다.

-> 따라서 배열보다 List를 더 많이 사용

 

2) 리스트 (List)

-배열과 유사한 순차적 자료구조

-배열의 모든 문제점을 해결한 자료구조

 

  • 고정되지 않은 크기
  • 다양한 데이터 핸들링 방법
  • 서로 다른 타입의 데이터 가능하지만 -> 관리가 어려워 보통은 동일한 타입
  • 배열 중간에 값을 추가하거나 삭제하기 쉬움.
  • 특정 데이터가 포함 여부 확인 가능 -> 검색을 위해서는 별도 구현이 필요.

리스트의 종류

 

(1) Linked List

-불연속적으로 존재하는 데이터를 서로 연결할 수 있는 방법을 제공

 

(2) Double Linked List

-이전과 다음 데이터 정보를 모두 가지고 있는 형태

-> 자바의 경우 LinkedList 클래스가 제공되는데 Double Circular Linked List(순환구조가 추가된 Double Linked List) 형태를 구현

 

 

 

3) 맵(Map)

:Key:Value(키:값)의 쌍으로 저장하는 방식의 자료구조

실제 데이터가 저장되는 형태는 내부구조에 따르며 사용하는 쪽에서는 내부구조에 대해 신경쓸 필요가 없는 형태

 

  • 데이터를 저장할 때 해당 데이터를 찾기 위한 Key를 부여.
  • Key값을 알면 언제든 쉽게 데이터를 찾을 수 있음.
  • Value 에 객체형이 들어갈 수 있어 복잡한 데이터 처리가 가능.

->  학생들의 성적을 관리하는 자료구조를 만들때 학생별 성적을 List 로 만들고 학번을 Key 로 하는 Map 을 만들어 List 를 저장하면 학번을 통해 손쉽게 성적관리가 가능

 

4) 이터레이터 (Iterator)

: 서로다른 자료구조(Vector, ArrayList, LinkedList)의 데이터를 동일한 방법으로 다음 데이터에 접근하는 방법을 제공하는 인터페이스

 


2. 컬렉션 프레임워크

자바에서 데이터를 저장하는 클래스들을 표준화한 설계 구조

 

 

 

인터페이스 설 명 특 징 대표 구현 클래스
List 순서가 있는 데이터의 집합. 데이터의 중복을 허용 ArrayList, LinkedList
Set 순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않음 HashSet, LinkedHashSet
Map 키(key)와 값(value)의 쌍으로 이루어진 데이터 집합. 순서 유지 X, 키 중복 X, 값 중복 O HashMap, LinkedHashMap, Properties

 

Collection 인터페이스

: List와 Set의 상위 인터페이스

 

-> Collection 인터페이스의 메서드만 사용가능 [구현클래스와 상관없이 동일한 방법으로 데이터 핸들링 가능]

 

-> 타입이 다른 경우 일관된 처리가 어려워 타입 파라미터 사용

Collection<String> c = new HashSet<>();
  • 순서가 없고 데이터 중복을 허용하지 않는 자료구조인 HashSet 객체 생성.
  • 저장되는 데이터는 문자열로 한정.
  • 원래는 new HashSet<String>(); 이지만 타입추론을 통해 생략 가능.

 

컬랙션 객체의 생성

-> java.util 패키지

 

컬랙션 객체

- 참조변수 선언 : 상위 인터페이스 타입을 사용

- 객체 생성 : 필요에 따라 구체적인 클래스들을 사용

 

List<Type_Name> (list_Name) = new ArrayList<>();

 

Collection<String> c1 = new HashSet<>();
//객체   : HashSet 생성
//데이터 : add() 통해 삽입

Collection<String> c2 = Arrays.asList("three", "four"); 
//객체  : 두 개의 데이터를 가지는 List 생성

Collection<String> c3 = Collections.singleton("five");
//객체  : 데이터가 하나인 유일한 인스턴스를 보장하는 Set 생성

 

컬랙션에 데이터 추가 및 삭제

데이터 추가 : add(), addAll() 메서드

 

add() : 지정된 타입의 데이터 하나씩 추가

addAll() 컬렉션 타입 추가하기 위해 개별 원소를 꺼내어 추가

c1.add("one");
c1.addAll(c2);

 

데이터의 삭제 : remove(), removeAll(), retainAll(), clear() 메서드

retainAll() : 인자의 데이터를 제외한 나머지 데이터 모두 삭제

clear() : 모든 데이터를 삭제

c1.remove("one");
c1.remove("c2");
c1.retainAll("four");
c1.clear();

 

컬랙션 데이터 확인 및 변환

: 특정 데이터의 존재 여부 확인 / 크기 확인 가능

c1.isEmpty();
c1.contains("zero");
c1.containsAll(c2);

 

컬랙션 데이터 크기 : size() 메서드

데이터 변환 : toArray() 메서드

-> Object 타입으로 리턴 되므로 특정 타입을 원한다면 해당 객체 생성 코드가 필요하다.

(Type_Name)[] (Object_Name) = (Instance_Name).toArray(new (Type_Name)[(Instance_Name).size()]);

 

int size = c1.size();
Object[] converted1 = c1.toArray();
String[] converted2 = c1.toArray(new String[c1.size()]);

 

컬랙션 데이터 사용

: 컬랙션은 구체적인 구현이 아니므로 직접적인 데이터의 접근을 위해서는 다른 방법이 필요

 

-> List, Set 인터페이스를 이용해 처리 / Collection 인터페이스 타입으로 처리

 

a) 배열로 변환해 for문과 사용

: 순차적으로 데이터를 사용하는 경우 : for문 사용

for(String s : c1) {
    System.out.println(s);			
}

-> 특정 위치의 데이터 : toArray() 메서드를 이용해 배열로 변환해 사용

(배열 데이터는 인덱스로 접근 가능하므로)

 

String[] converted2 = c1.toArray(new String[c1.size()]);
for(int i=0; i < converted2.length; i++) {
    System.out.println(converted2[i]);
}

b) Iterator를 사용
: 다음 데이터에 접근하는 방법을 제공하는 인터페이스

 

Collection 인터페이스는 Iterable 인터페이스를 상속받고, Iterator() 메서드로 Iterator 객체를 구할 수 있습니다.

-> 획득한 데이터를 조작하거나 다른 메서드의 인자로 전달 가능

Iterator iter = c1.iterator();
while(iter.hasNext()) {
    System.out.println(iter.next());
}


c) forEach()를 사용 (-> 함수형 프로그래밍과 람다)

c1.forEach(s -> System.out.println(s));
c1.forEach(System.out::println);

3. List, Set

: List, Set은  Collection 인터페이스 상속받고, List의 구현 클래스는 AbstractList 클래스를 상속 받는다.

 

리스트(List)

: 중복을 허용하고 저장순서가 유지되는 배열

-> Vector, ArraryList, LinkedList

 

메서드 설명
add(), addAll() 새로운 요소를 추가, 위치를 지정하거나 컬렉션 데이터를 한번에 추가하는 것이 가능
get() 지정된 위치(index)에 있는 객체 반환
indexOf() 객체의 위치(index) 반환
lastIndexOf() List의 마지막 요소부터 역방향으로 위치 반환
listIterator() List의 객체에 접근할 수 있는 ListIterator를 반환
remove() 지정된 위치에 있는 객체를 삭제하고 삭제된 객체를 반환
set() 지정된 위치에 객체를 저장
sort() 지정된 Comparator로 List 요소 정렬
subList() 지정된 범위에 있는 객체를 새로운 List로 반환

 

ArrayList, LinkedList

: 일반적인 List 구현 클래스로, 데이터 추가나 삭제가 잦은 경우 속도에 영향이 미친다.

 

->ArrayList : 내부는 배열 구조로 중간에 데이터 추가나 삭제가 불가능

->LinkedList : 중간에 데이터 추가나 삭제 가능

 

# 타입 선언 : 인터페이스 타입

# 객체 생성 : ArrayList나 LinkedList 사용

 

List<String> l1 = new ArrayList<>();
List<String> l2 = Arrays.asList("one", "two"); 
List<String> l3 = List.of("three", "four");

l1.add("five");
l1.allAll(l2);
l1.set(0,"zero");

System.out.println(l1.get(0));

 

LinkedList<String> llist = new LinkedList<>();
llist.addAll(l2);
llist.addAll(1,l3);
llist.add("five");

ArrayList와 LinkedList

-> 요소의 추가와 삭제 방법이 다르다

 

정렬

1) Collections.sort(List <T> list) : 내림차순 정렬, 원소들이 정렬된 결과로 전환

-> 올림차순 정렬 불가 [Comparator를 이용해 추가로 인자 작성시 가능]

Collections.sort(l1);
System.out.println(l1);

 

2) List의 sort(Comparator <? super E> c) 메서드 이용 [Comparator 객체 필요]

-> 별도 클래스로 만든 요소 타입 사용시 Comparable 인터페이스 구현하고 compareTo() 메서드 구현

-> 또는, sort() 메서드의 인자 부분에 직접 내부 익명 클래스로 구현

l1.sort(new Comparator<Object>() {
    @Override
    public int compare(Object o1, Object o2) {
        return o2.toString().compareTo(o1.toString());
    }
});
  • 여기서는 올림차순 정렬로 두번째 인자.compareTo() 결과를 리턴
  • 내림차순의 경우 첫번째 인자.compareTo() 결과를 리턴
  • compare() 결과는 같으면 0, 자신이 크면 양수, 인자가 크면 음수를 리턴.

3) stream api 이용

l1.stream().sorted((o1, o2) -> o2.toString().compareTo(o1.toString())).forEach(System.out::println);
  • List 객체를 stream() 메서드를 이용해 스트림으로 변환한 다음 sorted() 메서드를 사용.
  • sorted() 는 람다식을 이용해 Comparator 를 구현
  • 변환된 스트림은 forEach() 를 이용해 출력.

 

Set

: List와 유사한 자료구조로, 중복허용되지 않고 순서유지안되는 자료구조

 

-> 대표적인 구현클래스 : HashSet, LinkedHashSet, EnumSet, TreeSet, CopyOnWriteArraySet

[가장 자주 쓰이는 클래스 : HashSet, 순서가 필요한 경우 : LinkedHashSet, TreeSet]

 

 

 

메서드 설명
add(), addAll() 기존에 없는 새로운 요소를 추가, 컬렉션 데이터를 한번에 추가하는 것도 가능
clear() 모든 요소를 삭제
contains(), containsAll() 인자의 객체를 포함하고 있는지 확인, 컬렉션 전체를 비교할수도 있음
isEmpty 요소가 하나도 없는지 확인
iterator() 현재 Set의 객체에 접근할 수 있는 Iterator를 반환
remove(), removeAll() 특정 객체를 삭제하거나 컬렉션 전체를 삭제
size() Set 에 저장된 요소의 크기를 반환
toArray() 현재 Set의 요소를 배열로 반환

 

 

HashSet, LinkedHashSet

: 데이터가 중복되지 않는 자료구조

-> LinkedHashSet : 데이터가 입력된 순서로 저장

 

#타입 선언 : 인터페이스 타입

객체 생성   : HashSet / LinkedHashSet

 

(Interface_Type)<Type_Name> (Intance_Name) = new (Implement_Class_Name)<>();
Set<String> s1 = new HashSet<>();
Set<String> s2 = Set.of("three","four");

s1.addAll(Arrays.asList("one","two"));
s1.addAll(s2);
s1.add("five");
s1.add("two"); // 기존에 있으므로 새로 추가 안됨
s1.remove("five");
boolean check = s1.contains("one");

LinkedHashSet : 생성 클래스만 다르다.

LinkedHashSet<String> lset = new LinkedHashSet<>();
lset.addAll(Arrays.asList("one","two","three","four"));
lset.add("five");

 

Iterator가 필요한 경우 객체를 가지고 와서 사용 가능

Iterator<String> iter = lset.iterator();
while(iter.hasNext()) {
    System.out.println(iter.next());
}

 

TreeSet

: Sorted 인터페이스를 구현한 클래스로 중복 불가능한, 오름차순으로 데이터 정렬하는 자료구조

Set<Integer> tset = new TreeSet<>();
tset.addAll(Arrays.asList(50,10,60,20));

 

내림차순 정렬시 -> 스트림 api 사용

tset.stream().sorted((o1, o2) -> o2.toString().compareTo(o1.toString())).forEach(System.out::println);

04. Map

: 순차가 아니라, Key와 Value의 쌍으로 데이터 관리하는 자료구조

 

자체 인터페이스로 여러가지의 구현클래스를 가진다

-> HashMap

  • Map은 Collection 인터페이스를 상속하지 않음.
  • Key 집합은 Set 으로 볼 수 있음.
  • Value 집합은 Collection 으로 볼 수 있음.

 

Map<String,String> map = new HashMap<>();
map.put("109875","홍길동");
map.put("109894","김사랑");
System.out.println(map.get("109894")); // 김사랑
  • 타입 파라미터로 Key,Value 의 타입을 지정
  • 문자열 이외 클래스 타입도 가능
  • 필요한 데이터를 찾기 위해서는 Key 를 인자로 사용

 

 

메서드 설명
put(), putAll() 새로운 요소를 추가, 데이터를 한번에 추가하는 것도 가능
get() 특정 Key 에 해당하는 값을 가지고 옴
remove Map 요소 삭제
entrySet key 와 value 값 모두를 Entry 객체로 반환
keySet key 요소만 Set 객체로 반환
size 크기를 반환
values value 요소만 Collection 타입으로 반환

 

반응형