쉽게 풀어쓴 C 프로그래밍

Download Report

Transcript 쉽게 풀어쓴 C 프로그래밍

Power Java
제14장 제네릭과 컬렉션
© 2009 인피니티북스 All rights reserved
이번 장에서 학습할 내용
•
•
•
•
•
•
•
•
•
제네릭 클래스
제네릭 메소드
컬렉션
ArrayList
LinkedList
Set
Queue
Map
Collections 클래스
© 2009 인피니티북스 All rights reserved
일반적인 하나의
코드로 다양한
자료형을 처리하는
기법을 살펴봅시다.
제네릭(Generic)이란?
 제네릭(범용) 프로그래밍(generic programming)
 일반적인 코드를 작성하고 이 코드를 다양한 타입의 객체에 대하
여 재사용하는 프로그래밍 기법
 제네릭은 컬렉션 라이브러리에 많이 사용
© 2009 인피니티북스 All rights reserved
기존의 방법
 일반적인 객체를 처리하려면 Object 참조 변수를 사용
 Object 참조 변수는 어떤 객체이던지 참조할 수 있다.
 예제로 하나의 데이터를 저장하는 Store 클래스를 살펴보자.
© 2009 인피니티북스 All rights reserved
기존 방법(코드)
문제점
발생!!
© 2009 인피니티북스 All rights reserved
제네릭을 이용한 버전
C++의 템플릿(template)과 유사
 문자열을 저장하려면 다음과 같이 선언
 Store<String> store = new Store<String>();
 정수를 저장하려면 다음과 같이 선언
 Store<Integer> store = new Store<Integer>();
© 2009 인피니티북스 All rights reserved
제네릭 버전의 사용
© 2009 인피니티북스 All rights reserved
중간 점검 문제
1. 왜 데이터를 Object 참조형 변수에 저장하는 것이 위험할 수 있는가?
2. Store 객체에 Rectangle 객체를 저장하도록 제네릭을 이용하여 생성
하여 보라.
Store<Rectangle> store = new Store<Rectangle>();
3. 타입 매개 변수 T를 가지는 Point 클래스를 정의하여 보라. Point 클
래스는 2차원 공간에서 점을 나타낸다.
Class Point<T> {
T x;
T y;
…
} 2009 인피니티북스 All rights reserved
©
제네릭 메소드(Generic Method)
 메소드에서도 타입 매개 변수를 사용하여서 제네릭 메소드를 정의할
수 있다.
 타입 매개 변수의 범위가 메소드 내부로 제한된다.
반환형
매개변수
배열의 마지막
원소를
반환하는
메소드
© 2009 인피니티북스 All rights reserved
제네릭 메소드의 사용
 String[] language= { "C++", "C#", "JAVA" };
 String last = Array.<String>getLast(language);// last는 “JAVA"
 또는
 String last = Array.getLast(language);
© 2009 인피니티북스 All rights reserved
// last는 “JAVA"
중간 점검 문제
1. 제네릭 메소드 sub()에서 매개 변수 d를 타입 매개 변수를 이용하여
서 정의하여 보라.
public <T> void sub(T d) { … }
2. displayArray()라는 메소드는 배열을 매개 변수로 받아서 반복 루프를
사용하여서 배열의 원소를 화면에 출력한다. 어떤 타입의 배열도 처
리할 수 있도록 제네릭 메소드로 정의하여 보라.
public <T> void displayArray(T[] a) {
for(int i = 0; i<a.length; i++)
System.out.println(a[i]);
}
© 2009 인피니티북스 All rights reserved
컬렉션 (collection)
 컬렉션(collection)은 자바에서 자료 구조를 구현한 클래스
 자료 구조로는 리스트(list), 스택(stack), 큐(queue), 집합(set), 해쉬
테이블(hash table) 등이 있다.
© 2009 인피니티북스 All rights reserved
자바에서의 컬렉션
컬렉션 인터페이스
: 이 인터페이스를 직접 구현하여
자신만의 클래스를 만들어 사용가능
컬렉션
컬렉션 클래스
: 이미 위 인터페이스 중 하나를 구현하고 있는 클래스
: 바로 사용이 가능하다.
© 2009 인피니티북스 All rights reserved
컬렉션 인터페이스
© 2009 인피니티북스 All rights reserved
컬렉션의 역사
 초기 버전: Vector, Stack, HashTable, Bitset, Enumeration이 그것이
다.
 버전 1.2부터는 풍부한 컬렉션 라이브러리가 제공
 인터페이스와 구현을 분리
 (예) List 인터페이스를 ArrayList와 LinkedList 클래스가 구현
© 2009 인피니티북스 All rights reserved
컬렉션 인터페이스
© 2009 인피니티북스 All rights reserved
Collection
Queue
Set
List
Map
HashSet
ArrayList
HashMap
TreeSet
LinkedList
TreeMap
Stack
HashTable
Vector
Properties
Interface
구현 클래스
© 2009 인피니티북스 All rights reserved
콜렉션 인터페이스가 제공하는 메소드
© 2009 인피니티북스 All rights reserved
List 인터페이스
 List 인터페이스
- 순서를 가지는 원소들의 모임
- 중복된 원소가 허용된다.
- 위치 인덱스를 사용하여 원소에 접근한다. (0부터 시작)
 구현한 클래스 종류
- ArrayList: 리스트를 배열로 구현
- LinkedList: 리스트를 연결리스트로 구현
- Vector: 멀티쓰레드 환경에서 동기화가 지원됨
© 2009 인피니티북스 All rights reserved
배열리스트(ArrayList)
 ArrayList를 배열(Array)의 향상된 버전 또는 가변 크기의 배열이라고
생각하면 된다.
 ArrayList의 생성
// 제네릭 클래스
 ArrayList<String> list = new ArrayList<String>();
 원소 추가
 list.add( "MILK" );
 list.add( "BREAD" );
 list.add( "BUTTER" );
© 2009 인피니티북스 All rights reserved
저장된 것을 가져올 때
String s = list.get(1);
© 2009 인피니티북스 All rights reserved
예제
for (String s : list)
System.out.println(s);
© 2009 인피니티북스 All rights reserved
반복자(iterator)
 반복자(iterator): 반복자는 컬렉션의 원소들을 하나씩 처리하는데
사용  For-each 문이 더 편리함!
Iterator 객체 생성하는 방법
Iterator e = list.iterator();
Iterator 객체 e에 정의된 3 개의 메소드
© 2009 인피니티북스 All rights reserved
반복자
 ListIterator
 List를 구현한 클래스인 ArrayList, LinkedList, Vector에만 사용
 컬렉션의 원소들을 하나씩 처리하는데 사용하지만, 앞으로 검색
이 가능하기도 하며 뒤로도 검색 가능
 컬렉션 객체의 원소를 지니고 있는 Iterator 객체 생성하는 방법
 ListIterator e2 = list.listIterator();
 ListIterator 객체 e2에 정의된 주요 메소드




hasNext()
next()
hasPrevious(): 이전의 원소가 있는지 판단
previous(): 이전의 원소를 돌려줌
© 2009 인피니티북스 All rights reserved
ListIterator 사용 예제
import java.util.*;
public class ArrayListTest {
…
…
System.out.println("[ListIterator Test]");
ListIterator e2 = list.listIterator();
while(e2.hasNext()) {
s = (String)e2.next();
System.out.println(s);
}
while(e2.hasPrevious()) {
s = (String)e2.previous();
System.out.println(s);
}
}
}
© 2009 인피니티북스 All rights reserved
연결리스트(LinkedList)
 빈번하게 삽입과 삭제가 일어나는 경우에 사용
© 2009 인피니티북스 All rights reserved
연결리스트
Linked List
 이중 연결 리스트로 구현됨
 각 원소들은 다음 원소와 이전 원소를 가리키는 링크(link)정
보를 지닌다.
 ArrayList와 사용방법 거의 동일
 거의 동일한 메소드가 정의되어 있으며 효과도 동일
 LinkedList 에만 추가된 메소드
 addFirst(), getFirst(), removeFirst(), removeLast(),
addLast(), getLast()
 ArrayList 를 생성할 시에는 initial capacity를 미리 지정할
수 있는 생성자가 존재하지만(default : 10) LinkedList에는
그러한 생성자가 없다.
 그렇다면 ArrayList와 LinkedList 중 어느 것을 사용하는
것이 좋은 것인가?
© 2009 인피니티북스 All rights reserved
ArrayList vs. LinkedList
 ArrayList vs. LinkedList
 내부 구현 특징
ArrayList: 메모리에 데이터가 일렬로 붙어 있음
LinkedList: 메모리상 위치는 떨어져 있지만 포인터에 의해 연결
되어 있음
 공간적인 측면
ArrayList는 10개의 공간을 initial capacity로 지닌 이후에 2배씩
늘림. 그러므로, 공간의 낭비가 어느 정도 있음
LinkedList는 실행 시 필요에 따라 새로운 원소를 위한 공간을 생
성하므로 공간이 절약됨
 접근 속도 측면 (단순 읽기)
 ArrayList는 인덱스와 함께 원소가 저장되는 구조이기 때문에 접근이
빠름
 LinkedList는 어떤 원소에 접근하기 위하여 맨 처음부터 따라가서 찾
아야 하는 어려움이 있음
© 2009 인피니티북스 All rights reserved
ArrayList vs. LinkedList
 ArrayList vs. LinkedList
 삭제와 삽입 측면
 ArrayList는 삽입시에는 오른쪽 밀림(Shift Right) 연산이 일어나고 삭
제시에는 왼쪽 밀림(Shift Left) 연산이 필요하므로 효율이 좋지 않음
N
0 1 2 3 4 5
0 1 2 3 4 5
A B C D E
A B C D E
A B C D
A B C
A B
C
E
D E
C D E
A B N C D E
A B
D E
A B D
E
A B D E
 LinkedList는 인접 노드의 포인터만 변경하면 되기 때문에 삭제와 삽
입 시간 면에서 유리
© 2009 인피니티북스 All rights reserved
ArrayList vs. LinkedList
 ArrayList vs. LinkedList
 어떤 자료구조?
 검색위주이면 ArrayList가 유리
 삽입 삭제 위주라면 LinkedList가 유리
 최대 데이터 수가 예측 불가라면 LinkedList가 유리
© 2009 인피니티북스 All rights reserved
예제
© 2009 인피니티북스 All rights reserved
배열을 리스트로 변환하기
 List를 일반 배열 자료로 변경하기
 String[] stringArray = list.toArray(new String[list.size()]);
 위에서 toArray의 파라미터로 String 타입의 비어있는 배열 객체를
넣어주어 toArray 메소드로 하여금 만들어야 할 배열의 정확한 타입
과 원소 개수를 알도록 해준다.
 일반 배열 자료를 List로 변경하기
List<String> list = Arrays.asList(new String[size]);
 일반적인 배열을 리스트로 변환한다.
 String[] stringArray = {"AAA", "BBB", "CCC", "DDD"};
 List<String> list = Arrays.asList(stringArray);
© 2009 인피니티북스 All rights reserved
중간 점검 문제
1. ArrayList와 LinkedList의 차이점은 무엇인가?
2. 어떤 경우에 LinkedList를 사용하여야 하는가?
© 2009 인피니티북스 All rights reserved
집합(Set )
 집합(Set)은 원소의 중복을 허용하지 않는다.
 순서에 상관없이 원소 저장
 중복을 허용하지 않음
 List 계열 보다는 호출 가능 메소드의 개수가
적음
Collection 인터페이스에 정의된 정도의
메소드만 지원
대표적인 메소드
add(Object o)
contains(Object o)
isEmpty()
remove(Object o)
size()
iterator()
toArray(Object[] a)
© 2009 인피니티북스 All rights reserved
Set 인터페이스를 구현하는 방법
 HashSet
 HashSet은 해쉬 테이블에 원소를 저장하기 때문에 성능면에서 가
장 우수하다. 하지만 원소들의 순서가 일정하지 않은 단점이 있
다.
 TreeSet
 레드-블랙 트리(red-black tree)에 원소를 저장한다. 따라서 값에
따라서 순서가 결정되며 하지만 HashSet보다는 느리다.
 LinkedHashSet
 해쉬 테이블과 연결 리스트를 결합한 것으로 원소들의 순서는 삽
입되었던 순서와 같다.
© 2009 인피니티북스 All rights reserved
예제
순서가 일정하지 않다!
© 2009 인피니티북스 All rights reserved
대량 연산 메소드
위에서 addAll, retainAll, removeAll 메소드는 원집합인
s1을 변경한다. 원집합의 변경을 원하지 않으면 다음과 같이
코딩한다.
Set<String> union = new HashSet<String>(s1);
union.addAll(s2);
© 2009 인피니티북스 All rights reserved
예제
© 2009 인피니티북스 All rights reserved
© 2009 인피니티북스 All rights reserved
큐(Queue)
 큐는 먼저 들어온 데이터가 먼저 나가는 자료 구조
 FIFO(First-In First-Out)
© 2009 인피니티북스 All rights reserved
Queue 인터페이스
add() vs. offer()
remove() vs. poll()
element() vs. peek()
// 용량초과 시 예외발생 vs. false
// 원소삭제 후 가져옴, 예외 vs. null
// 원소 삭제없이 가져옴, 예외 vs. null
- 자바에서는 스택을 Stack클래스로 구현하여 제공하고 있지만,
큐는 Queue 인터페이스로만 정의해 놓고, 클래스를 제공하지
않았다. 대신 Queue 인터페이스를 구현한 클래스(LinkedList,
PriorityQueue)를 사용하면 된다.
© 2009 인피니티북스 All rights reserved
예제: 카운트 다운 타이머
© 2009 인피니티북스 All rights reserved
우선 순위큐 (priority queue)
 우선 순위큐(priority queue): 우선순위를 가진 항목들을 저장
하는 큐 (heap 사용)
 FIFO 순서가 아니라 우선 순위가 높은 데이터가 먼저 나가게
된다. (무작위로 삽입 되었더라도 정렬된 상태로 추출)
remove() 호출 시 가장 작은 원소가 추출된다.
 가장 일반적인 큐: 스택이나 FIFO 큐를 우선 순위큐로 구현할
수 있다.
Job Scheduling
© 2009 인피니티북스 All rights reserved
예제
© 2009 인피니티북스 All rights reserved
맵(Map)
 사전과 같은 자료 구조
 키(key)에 값(value)이 매핑된다.
© 2009 인피니티북스 All rights reserved
맵(Map)
 Map 인터페이스의 개념
 사전과 같은 자료 구조
 키(key)에 값(value)이 매핑된다.
 중복된 키를 가질 수 없다.
 키가 제시되면 값을 돌려준다.
 예
 Key: 학생 객체의 학번, Value: 학생 객체
 Map을 구현한 클래스
 HashMap
 TreeMap
 트리구조에 데이터를 정렬
 만약 키들을 정렬된 순서로 돌려받을 필요가 있을 때 사용
 LinkedHashMap
© 2009 인피니티북스 All rights reserved
Map
 Map 사용 방법
 데이터 저장 방법
 Map<String, Student> freshman = new HashMap<String, Student>();
 Student kim = new Student("20090001", "김준표", "서울 서초구");
 Freshman.put("2009001", kim);
 객체 추출 방법
 String s = "2009001";
 st = freshman.get(s);
47
© 2009 인피니티북스 All rights reserved
예제
© 2009 인피니티북스 All rights reserved
© 2009 인피니티북스 All rights reserved
Map
 Map 사용 예제 2
WordFreq.java
import java.util.*;
public class WordFreq {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<String, Integer>();
String[] sample = { "to", "be", "or", "not", "to", "be", "is", "a", "problem" };
// 문자열에 포함된 단어의 빈도를 계산한다.
for (String a : sample) {
for (String a : sample) {
Integer freq = m.get(a);
int freq = m.get(a);
m.put(a, (freq == 0) ? 1 : freq + 1);
m.put(a, (freq == null) ? 1 : freq + 1);
}
}
Runtime 시 에러. Why?
System.out.println(m.size() + " 단어가 있습니다.");
System.out.println(m.containsKey("to"));
System.out.println(m.isEmpty());
System.out.println(m);
}
}
50
© 2009 인피니티북스 All rights reserved
// 7
// true
// false
// {not=1, to=2, …}
Collections 클래스
 Collections 클래스의 유용한 기능 및 정적 메소드
 Sorting
 Collections.sort(List list)
 리스트의 정렬에 사용(ArrayList, LinkedList, Vector)
 배열  리스트로 변경 후 사용!!!
 Shuffling
 Collections.shuffle(List list, Random rnd)
 리스트내의 원소를 섞는데 사용
 Searching
 Collections.binarySearch(List list, Object key)
 리스트내에서 특정 원소가 있는지 검사하여 그 위치의 인덱스를 돌려줌
51
© 2009 인피니티북스 All rights reserved
Collection 클래스
 Collections 클래스 사용 정렬 예제 1
Sort.java
import java.util.*;
public class Sort {
public static void main(String[] args) {
String[] sample = { "i", "walk", "the", "line" };
List<String> list = Arrays.asList(sample); // 배열을 리스트로 변경
Collections.sort(list);
System.out.println(list);
역순정렬:
}
Collections.sort(list,Colle
ctions.reverseOrder())
}
[i, line, the, walk]
52
© 2009 인피니티북스 All rights reserved
Collection 클래스
 Collections 클래스 사용 정렬 예제 2-1
SortTest.java
import java.util.*;
class Student implements Comparable<Student> {
int number;
String name;
}
public Student(int number, String name) {
this.number = number;
this.name = name;
public interface Comparable<T> {
}
public int compareTo(T o);
public String toString() {
}
return name;
}
public int compareTo(Student s) {
public int compareTo(Student s) {
return number - s.number;
return name.compareTo(s.name);
}
}
53
이름으로 정렬
© 2009 인피니티북스 All rights reserved
Collection 클래스
 Collections 클래스 사용 예제 2-2
SortTest.java
public class SortTest {
public static void main(String[] args) {
Student array[] = { new Student(20090002, "이철수"),
new Student(20090001, "김철수"),
new Student(20090003, "박철수") };
List<Student> list = Arrays.asList(array);
Collections.sort(list);
System.out.println(list);
}
}
[김철수, 이철수 , 박철수]
// 번호순
이름으로!!!!
54
© 2009 인피니티북스 All rights reserved
성과 이름으로!!!!
Collection 클래스
 Collections 클래스 사용 섞기 예제 3
import java.util.*;
public class Shuffle {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++)
list.add(i);
Collections.shuffle(list, new Random(System.currentTimeMillis()));
System.out.println(list);
}
}
55
© 2009 인피니티북스 All rights reserved
Shuffle.java
Collection 클래스
 Collections 클래스 사용 탐색 예제 4
import java.util.*;
public class Search {
public static void main(String[] args) {
int key = 50;
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 100; i++)
list.add(i);
int index = Collections.binarySearch(list, key);
System.out.println("탐색의 반환값 =" + index);
}
}
탐색의 반환값 =50
56
© 2009 인피니티북스 All rights reserved
Search.java
Collection 클래스
 Collections 클래스의 다른 메소드
 Object min(Collection coll), Object max(Collection coll)
 컬렉션에서 최대값과 최소값을 찾는다.
 void reverse(List list)
 list 원소들의 순서를 반대로 바꾼다.
 void fill(List list, Object obj)
 list에 지정된 obj로 원소를 채운다.
 void copy(List dest, List src)
 src리스트의 원소들을 dest 리스트에 복사한다.
 void swap(List list, int i, int j)
 list의 지정된 두 위치의 원소를 바꾼다.
57
© 2009 인피니티북스 All rights reserved
Exercise
3. 다음은 Stack 클래스의 일부분이다.
1) int 대신에 제네릭 타입으로 표시하라.
class Stack<T> {
private T[] stack;
public void push(T data) {…}
public T pop() {…}
}
2) String 타입의 데이타를 가지는 Stack 객체를 생성하는 문장.
Stack<String> stack = new Stack<String>();
© 2009 인피니티북스 All rights reserved
LAB.
2. 카드 게임 프로그램을 컬렉션 라이브리를 이용하여 작성하라.
(1) 카드를 나타내는 Card 클래스를 작성한다. 하나의 카드는 무늬(suit)와
숫자(number)를 가진다. 생성자, ToString 메소드 정의하라.
(2) 카드 데크를 나타내는 CardDeck 클래스를 작성하라. CardDeck은 총
52 개의 Card 객체를 저장하여야 한다. ArrayList를 사용하여
카드들을 저장하라. 생성자에서 모든 카드를 생성하라.
(3) CardDeck 클래스에 카드를 섞는 메소드 shuffle()을 콜렉션 클래스의
정적메소드 shuffle()을 이용하여 정의하라.
(4) CardDeck 클래스에 Deck의 처음에서 카드를 제거하여서 반환하는
메소드인 deal()을 작성하라.
(5) 카드 경기자를 나타내는 Player 클래스를 구현하라. Player 클래스도
카드의 리스트를 가져야 한다.(ArrayList 사용할 것)
(6) Player는 카드를 얻어서 자신의 리스트에 추가하는 메소드
getCard()를 정의하라. 또한 자신의 카드를 보여주는 showCards()
메소드를 작성하라.
(7) main() 함수를 가지는 클래스 CardGame을 작성하라. CardDeck
클래스의 객체를 생성하고, Deck의 카드를 섞은 다음 Player 객체를 두
명 생성한다. 카드를 7장 씩 분배하고 각자의 카드를 화면에 표시하라.
© 2009 인피니티북스 All rights reserved
© 2009 인피니티북스 All rights reserved
private static String getHandValue(Player hand){
if(hand.isRoyalFlush() == true)
return "Royal Flush";
if(hand.isStraightFlush() == true)
return "Straight Flush";
if(hand.isFourOfAKind() == true)
return "Four of a Kind";
if(hand.isFullHouse() == true)
return "Full House";
if(hand.isFlush() == true)
return "Flush";
if(hand.isStraight() == true)
return "Straight";
if(hand.isThreeOfAKind() == true)
return "Three of a Kind";
if(hand.isTwoPair() == true)
return "Two Pair";
if(hand.isPair() == true)
return "Pair";
return "Nothing";
}
© 2009 인피니티북스 All rights reserved
Q&A
© 2009 인피니티북스 All rights reserved