[필기정리]Day23 - 컬렉션 프레임워크 문제

SW/Java

2020. 7. 10. 10:57

Q.

1. 프레임워크(Framework) ?

A. 잘 정의된 구조나 골격

 

2. 자바에서 말하는 프레임워크?

A. 잘 정의된 구조의 클래스 틀

 

3. 자료구조(Data Structures)?

A. 자료구조는 데이터의 저장과 관련이 있는 학문으로서, 

   검색 등 다양한 측면을 고려하여 효율적인 데이터의 저장 방법을 연구하는 학문.

 

4. 알고리즘(Algorithms)

A. 알고리즘은 저장된 데이터의 일부 또는 전체를 대상으로 진행하는 각종 연산을 연구하는 학문.

 

5. 자료구조에서 정형화하고 있는 데이터의 저장방식 예시

A. 배열(Array), 리스트(List), 스택(Stack), 큐(Queue), 트리(Tree), 해시(Hash) 등

 

6. 알고리즘 예시

A. 정렬(Sort), 탐색(Search), 최대(Max) 최소(Min) 검색

 

7. 컬렉션?

A. 컬렉션은 데이터의 저장, 그리고 이와 관련있는 알고리즘을 구조화한 프레임워크이다. 

   쉽게는 자료구조와 알고리즘을 클래스로 구현해놓은 것 정도로 생각해도 좋다.

   때문에 컬렉션 클래스들을 가리켜 ‘컨테이너 클래스’라고도 한다.

 

8. 컬렉션 프레임 워크의 인터페이스 구조

A.

        Collection<E>               Map<K,V>

              ↑

      ┌     ┴     ┐

Set<E> List<E> Queue<E>

 

9. 컬렉션이 프레임워크인 이유?

A. 인터페이스 구조를 기반으로 클래스들이 정의되어 있기 때문에 프레임워크라 하는 것이다.

 

10. List<E> 인터페이스와 이를 구현하는 제네릭 클래스는?

A. ArrayList<E>, LinkedList<E>

 

11. List<E> 인터페이스를 구현하는 제네릭 클래스들이 갖는 두 가지 특성은?

A. ① 동일한 인스턴스의 중복저장을 허용한다.
  ② 인스턴스의 저장순서가 유지된다.

 

12. List<E>를 구현한 ArrayList를 이용하여

① 11, 22, 33 을 저장한다.

저장한 값을 전부 출력한다.

③ 첫번째 값을 삭제한다.(11을 삭제한다.)

④ 저장한 값을 전부 출력한다.

A.

import java.util.ArrayList;

class IntroArrayList
{
	public static void main(String[] args)
	{
		ArrayList<Integer> list=new ArrayList<Integer>();
		
		/* 데이터의 저장 */
		list.add(new Integer(11));
		list.add(new Integer(22));
		list.add(new Integer(33));
		
		/* 데이터의 참조 */
		System.out.println("1차 참조");
		for(int i=0; i<list.size(); i++)
			System.out.println(list.get(i));
		
		/* 데이터의 삭제 */
		list.remove(0);
		System.out.println("2차 참조");
		for(int i=0; i<list.size(); i++)
			System.out.println(list.get(i));	
	}
}

 

13. 문제 22-1 [ArrayList<E> 클래스의 용량(버퍼) 설정]

ArrayList<E> 클래스는 저장되는 데이터의 수가 증가함에 따라서,

용량(데이터 저장 가능한 용량)이 자동으로 증가하는 클래스이다.

 

그런데 용량을 증가시키는 과정에서 수반되는 연산으로 인해 때로는 성능에 부담이 되기도 한다.

때문에 대략 500여 개의 데이터가 저장 될 것이 예상되는 상황에서는 점진적으로 용량을 500으로 늘리기 보다,

처음부터 용량을 500으로 잡음으로 인해서 불필요한 연산을 줄일 필요도 있다.

 

물론 ArrayList<E>의 메소드 중에는 저장용량의 설정을 위한 메소드가 존재한다.

따라서 여러분은 API 문서를 참조하여 이 메소드를 찾기 바란다.

그리고 다음 조건을 만족시키는 코드를 각각 구성해 보기 바란다.

 

- Integer 인스턴스를 저장할 수 있는 ArrayList<E>를 생성하고 저장용량을 500으로 늘린다.

- ArrayList<E>에 저장되어 있는 인스턴스 수의 두 배로 저장용량을 늘린다.

A.

public void ensureCapacity(int minCapacity);		// 메소드 원형

ArrayList<Integer> list = new ArrayList<Integer>();
list.ensureCapacity(500);
list.ensureCapacity(list.size()*2);

 

14. 문제12번을 LinkedList<E> 기반으로

A.

import java.util.LinkedList;

class IntroLinkedList
{
	public static void main(String[] args)
	{
		LinkedList<Integer> list=new LinkedList<Integer>();
		
		/* 데이터의 저장 */
		list.add(new Integer(11));
		list.add(new Integer(22));
		list.add(new Integer(33));
		
		/* 데이터의 참조 */
		System.out.println("1차 참조");
		for(int i=0; i<list.size(); i++)
			System.out.println(list.get(i));
		
		/* 데이터의 삭제 */
		list.remove(0);
		System.out.println("2차 참조");
		for(int i=0; i<list.size(); i++)
			System.out.println(list.get(i));	
	}
}

15. ArrayList<E>의 특징

A.

- 저장소의 용량을 늘리는 과정에서 많은 시간이 소요된다. - ArrayList<E>의 단점
- 데이터의 삭제에 필요한 연산과정이 길다. - ArrayList<E>의 단점
- 데이터의 참조가 용이해서 빠른 참조가 가능하다. - ArrayList<E>의 장점

 

16. LinkedList 방식으로 저장하고 출력하기

제네릭 클래스 Box를 설계하고

그 클래스에 item 참조변수와 다음 박스를 가르킬 수 있는 참조변수를 두고 저장하는 메소드

저장한 것을 꺼내는 메소드

 

Box의 인스턴스를 각각 연결하고

첫 번째에는 “First String”

두 번째에는 “Second String”

세 번째에는 “Thrid String” item에 저장

A.

class Box<T>
{
	public Box<T> nextBox;
	T item;

	public void store(T item) { this.item=item; }
	public T pullOut() { return item; }
}

class SoSimpleLinkedListImpl
{
	public static void main(String[] args)
	{
		Box<String> boxHead=new Box<String>();
		boxHead.store("First String");
		
		boxHead.nextBox=new Box<String>();
		boxHead.nextBox.store("Second String");
		
		boxHead.nextBox.nextBox=new Box<String>();
		boxHead.nextBox.nextBox.store("Third String");
		
		Box<String> tempRef;
		
		/* 두 번째 박스에 담긴 문자열 출력 과정 */
		tempRef=boxHead.nextBox;
		System.out.println(tempRef.pullOut());

		/* 세 번째 박스에 담긴 문자열 출력 과정 */
		tempRef=boxHead.nextBox;
		tempRef=tempRef.nextBox;
		System.out.println(tempRef.pullOut());
	}
}

 

17. LinkedList<E> 특징

A.

- 저장소의 용량을 늘리는 과정이 간단하다. LinkedList<E>의 장점
- 데이터의 삭제가 매우 간단하다. LinkedList<E>의 장점 
- 데이터의 참조가 다소 불편하다. LinkedList<E>의 단점

 

18. 문제 22-2 [ArrayList<E> vs. LinkedList<E>]

아래에서 제시하는 상황에 적절한 자료구조를 선택해 보자.

ArrayList<E>LinkedList<E> 둘 중 하나를 선택하면 된다.

 

- 상황1

저장하게 되는 데이터의 수가 대략적으로 예측 가능하며,

빈번한 데이터의 참조가 일어나는 상황에서 유용하게 사용할 수 있는 컬렉션 클래스는 무엇인가?

A. ArrayList<E>

 

- 상황2

저장하게 되는 데이터의 수가 예측 불가능하며,

빈번한 데이터의 저장 및 삭제가 일어나는 상황에서 유용하게 사용할 수 있는 컬렉션 클래스는 무엇인가?

A. LinkedList<E>

 

19. LinkedList를 이용해 “First”, “Second”, “Third”, “Fourth”를 추가하고

반복자를 이용하며 출력하면서 “Third”를 삭제하자.

그리고 다시 반복자를 이용하여 출력하자.

(반복자가 참조하는 것을 처음으로 옮길려면?)

A. 

import java.util.Iterator;
import java.util.LinkedList;

class IteratorUsage
{
	public static void main(String[] args)
	{
		LinkedList<String> list=new LinkedList<String>();
		list.add("First");
		list.add("Second");
		list.add("Third");
		list.add("Fourth");
		
		Iterator<String> itr=list.iterator();
		
		System.out.println("반복자를 이용한 1차 출력과 \"Third\" 삭제");
		while(itr.hasNext())
		{
			String curStr=itr.next();
			System.out.println(curStr);
			if(curStr.compareTo("Third")==0)
				itr.remove();
		}
		
		System.out.println("\n\"Third\" 삭제 후 반복자를 이용한 2차 출력 ");		
		itr=list.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

20. 다음 메소드를 API에서 참고

- boolean hasNext()

- E next() 

- void remove()

A. 

boolean hasNext() 참조할 다음 번 요소(element)가 존재하면 true를 반환

E next() 다음 번 요소를 반환

void remove() 현재 위치의 요소를 삭제

 

21. 19번 문제에 있는 내용중 list에 있는 내용을 for each 문을 이용하여 출력하시오.

A.

for(String str : list)
	System.out.println(str);

22. Iterable<E> 인터페이스

A. Collection<E> 인터페이스는 Iterable<E> 인터페이스를 상속받는데,  

    Iterable<E>에 정의되어 있는 유일한 메소드가 iterator 이다.

   즉, Collection<E>에 정의되어 있는 iterator 메소드는 인터페이스 간 상속에 의한 것이다.

 

23. 반복자의 의미

A. “컬렉션 클래스의 종류에 상관없이 동일한 형태의 데이터 참조 방식을 유지한다.”
    반복자는 저장된 데이터 전부를 참조할 때 매우 유용하다.

    그리고 ‘데이터 전부의 참조’라는 것은 데이터의 저장방식과는 상관없이 매우 빈번하게 요구되는 기능이다.

    때문에 대부분의 컬렉션 클래스들은 반복자를 반환하는 iterator 메소드를 구현하고 있다.

 

24. 문제 19에서 LinkedList<E>로 구현되어 있는 것을 HashSet<E>로 구현하시오.

A.

import java.util.Iterator;
import java.util.HashSet;

class UsefulIterator
{
	public static void main(String[] args)
	{
		HashSet<String> set=new HashSet<String>();
		set.add("First");
		set.add("Second");
		set.add("Third");
		set.add("Fourth");
		
		Iterator<String> itr=set.iterator();
		
		System.out.println("반복자를 이용한 1차 출력과 \"Third\" 삭제");
		while(itr.hasNext())
		{
			String curStr=itr.next();
			System.out.println(curStr);
			if(curStr.compareTo("Third")==0)
				itr.remove();
		}
		
		System.out.println("\n\"Third\" 삭제 후 반복자를 이용한 2차 출력 ");		
		itr=set.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

25. 제네릭클래스를 이용한 기본 자료형 데이터의 저장.

     LinkedList10, 20, 30을 저장하고 그것을 반복자를 이용하여 출력하시오.

A.

import java.util.Iterator;
import java.util.LinkedList;

class PrimitiveCollection
{
	public static void main(String[] args)
	{
		LinkedList<Integer> list=new LinkedList<Integer>();
		list.add(10);		// Auto Boxing
		list.add(20);		// Auto Boxing
		list.add(30);		// Auto Boxing
		
		Iterator<Integer> itr=list.iterator();
		
		while(itr.hasNext())
		{
			int num=itr.next();		// Auto Unboxing
			System.out.println(num);
		}
	}
}

 

26. List<E> 인터페이스를 구현하는 클래스들과 Set<E> 인터페이스를 구현하는 클래스들의 차이점.

A.

- List<E>를 구현하는 클래스들과 달리 Set<E>를 구현하는 클래스들은

  ① 데이터의 저장순서를 유지하지 않는다.
  ② 데이터의 중복저장을 허용하지 않는다.

 

27. HashSet을 이용하여 ‘First’, ‘Second’, ‘Third’, ‘First’를 저장하고, 저장된 갯수를 출력하자.

    그리고 그 내용을 출력.

    그 후 저장순서를 바꿔서 다시 출력해보자.

A.

import java.util.Iterator;
import java.util.HashSet;

class SetInterfaceFeature
{
	public static void main(String[] args)
	{
		HashSet<String> hSet=new HashSet<String>();

		hSet.add("First");
		hSet.add("Second");
		hSet.add("Third");
		hSet.add("First");
		
		System.out.println("저장된 데이터 수: "+hSet.size());
		
		Iterator<String> itr=hSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

28. HashSet<E> 클래스가 ( )메소드의 호출결과와 ( )메소드의 호출결과를 가지고 동등비교

A. HashSet<E> 클래스가 ( equals ) 메소드의 호출결과와

   ( hashCode ) 메소드의 호출결과를 가지고 동등비교

 

29. Hash<E> 클래스는 해시 알고리즘을 적용하여 데이터를 저장하고 검색한다.

    그럼 그 방식을 어떠한 방법으로 진행하나?

A.

① Object 클래스의 hashCode 메소드의 반환 값을 해시 값으로 활용.
② Object 클래스의 equals 메소드의 반환 값을 이용해서 내용비교.

public int hashCode(); 
public boolean equals(Object obj);


Object 클래스의 hashCode 메소드는 인스턴스가 다르면 구성 내용에 상관없이 

전혀 다른 해시값을 반환하도록 정의되어 있다. 
equals 메소드도 내용비교가 아닌, 참조 값만 비교하도록 정의되어 있다.

 

30. 아래에 있는 HashSetEqualityOne.java 코드를 이용하여 중복 저장을 허용하지 않도록 수정하자.

import java.util.Iterator;
import java.util.HashSet;

class SimpleNumber
{
	int num;
    
	public SimpleNumber(int n)
	{
		num=n;
	}

	public String toString()
	{
		return String.valueOf(num);
	}
}

class HashSetEqualityOne
{
	public static void main(String[] args)
	{
		HashSet<SimpleNumber> hSet=new HashSet<SimpleNumber>();
		hSet.add(new SimpleNumber(10));
		hSet.add(new SimpleNumber(20));
		hSet.add(new SimpleNumber(20));

		System.out.println("저장된 데이터 수: "+hSet.size());
		Iterator<SimpleNumber> itr=hSet.iterator();
        
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

A.

import java.util.Iterator;
import java.util.HashSet;

class SimpleNumber
{
	int num;
	public SimpleNumber(int n)
	{
		num=n;
	}
	public String toString()
	{
		return String.valueOf(num);
	}
	public int hashCode()
	{
		return num%3;
	}
	public boolean equals(Object obj)
	{
		SimpleNumber comp=(SimpleNumber)obj;
		if(comp.num==num)
			return true;
		else
			return false;		
	}
}

class HashSetEqualityTwo
{
	public static void main(String[] args)
	{
		HashSet<SimpleNumber> hSet=new HashSet<SimpleNumber>();
		hSet.add(new SimpleNumber(10));
		hSet.add(new SimpleNumber(20));
		hSet.add(new SimpleNumber(20));
		
		System.out.println("저장된 데이터 수: "+hSet.size());
		
		Iterator<SimpleNumber> itr=hSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

31. [hashCode 메소드와 equals 메소드의 오버라이딩]

다음 클래스의 두 인스턴스를 HashSet<E>에 저장할 때,

두 인스턴스의 데이터(name & age)가 완전히 동일하다면,

하나만 저장되도록 hashCode 메소드와 equals 메소드를 오버라이딩 하자.

import java.util.HashSet;
import java.util.Iterator;

class Person
{
	String name;
	int age;

	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	public String toString()
	{
		return name + "(" + age + "세)";
	}
}

class PersonMain
{
	public static void main(String[] args)
	{
		HashSet<Person> hSet = new HashSet<Person>();
		hSet.add(new Person("이진호", 10));
		hSet.add(new Person("이진호", 20));
		hSet.add(new Person("김명호", 20));
		hSet.add(new Person("김명호", 15));
		hSet.add(new Person("이진호", 20));
		hSet.add(new Person("김명호", 20));

		System.out.println("저장된 데이터 수 : " +  hSet.size());

		Iterator<Person> itr = hSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

인스턴스의 내용비교가 되도록 적절히 오버라이딩 되었다면, 다음의 실행결과를 보여야 한다.

단, 이름과 나이 정보가 출력되는 순서는 hashCode 메소드의 구현에 따라 다를 수 있다.

아니 대부분 다를 것이다.

저장된 데이터 수 : 4  // 예상결과화면
김명호(20세)
김명호(15세)
이진호(10세)
이진호(20세)

이 문제는 다양한 형태의 답이 존재할 수 있다.

따라서 두 가지 이상의 방식을 적용해보기 바란다.

A.

import java.util.HashSet;
import java.util.Iterator;

class Person
{
	String name;
	int age;

	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	public String toString()
	{
		return name + "(" + age + "세)";
	}
	public int hashCode()
	{
		return name.hashCode() + age%7;
	}
	public boolean equals(Object obj)
	{
		Person cmp = (Person)obj;
		if(cmp.name.equals(name) && cmp.age == age)
			return true;
		else
			return false;
	}
}

class PersonMain
{
	public static void main(String[] args)
	{
		HashSet<Person> hSet = new HashSet<Person>();
		hSet.add(new Person("이진호", 10));
		hSet.add(new Person("이진호", 20));
		hSet.add(new Person("김명호", 20));
		hSet.add(new Person("김명호", 15));
		hSet.add(new Person("이진호", 20));
		hSet.add(new Person("김명호", 20));

		System.out.println("저장된 데이터 수 : " +  hSet.size());

		Iterator<Person> itr = hSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

32. TreeSet<E>를 이용하여 1, 2, 4, 3, 2 를 순서대로 저장하고 TreeSet<E>에 저장된 갯수를 출력.

     그리고 반복자를 이용하여 내용들을 출력한다.

A.

import java.util.Iterator;
import java.util.TreeSet;

class SortTreeSet
{
	public static void main(String[] args)
	{
		TreeSet<Integer> sTree=new TreeSet<Integer>();
		sTree.add(1);
		sTree.add(2);
		sTree.add(4);
		sTree.add(3);
		sTree.add(2);
		
		System.out.println("저장된 데이터 수: "+sTree.size());
		
		Iterator<Integer> itr=sTree.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

33. iterator 메소드가 반환하는 반복자는 정렬된 데이터를 ( )으로 참조한다.

A. iterator 메소드가 반환하는 반복자는 정렬된 데이터를 ( 오름차순 )으로 참조한다.

 

34. 정렬의 기준을 프로그래머가 직접 정의할 때 쓰는 Interface?

A.

interface Comparable<T>
{
	int compareTo(T obj);
}

 

35. 위의 ( ) 인터페이스의 compareTo 메소드는 어떤 내용을 근거로 정의되어야 하나?

A. Comparable<T> 인터페이스

- 인자로 전달된 obj가 작다면 양의 정수를 반환해라.
- 인자로 전달된 obj가 크다면 음의 정수를 반환해라.
- 인자로 전달된 obj와 같다면 0을 반환해라.

 

36. TreeSet<E>( ) 메소드의 호출결과를 참조하여 정렬을 하기 때문에,

     TreeSet<E>에 저장되는 인스턴스는 반드시 ( ) 인터페이스를 구현하고 있어야 한다.

A. TreeSet<E>는 ( compareTo ) 메소드의 호출결과를 참조하여 정렬을 하기 때문에,

    TreeSet<E>에 저장되는 인스턴스는 반드시 ( Comparable<T> ) 인터페이스를 구현하고 있어야 한다.

 

37. 다음 클래스를 TreeSet<E> 클래스를 이용하여 나이를 오름차순으로 출력하시오.

    (입력 ex) (“Lee”, 24), (“Hong”, 29), (“Choi”, 21) )

A.

import java.util.Iterator;
import java.util.TreeSet;

class Person implements Comparable<Person>
{
    String name;
    int age;

    public Person(String name, int age)
    {
        this.name=name;
        this.age=age;
    }
    public void showData()
    {
    	System.out.printf("%s %d \n", name, age);
    }
    public int compareTo(Person p)
    {
        if(age>p.age)
            return 1;
        else if(age<p.age)
            return -1;
        else	
            return 0;
    }
}

class ComparablePerson 
{
	public static void main(String[] args)
	{
		TreeSet<Person> sTree=new TreeSet<Person>();
		sTree.add(new Person("Lee", 24));
		sTree.add(new Person("Hong", 29));
		sTree.add(new Person("Choi", 21));
		
		Iterator<Person> itr=sTree.iterator();
		while(itr.hasNext())
			itr.next().showData();
	}
}

 

38. 위의 클래스를 TreeSet<E> 클래스를 이용하여 이름을 알파벳순으로 출력하시오.

A.

import java.util.Iterator;
import java.util.TreeSet;

class Person implements Comparable<Person>
{
    String name;
    int age;

    public Person(String name, int age)
    {
        this.name=name;
        this.age=age;
    }
    public void showData()
    {
    	System.out.printf("%s %d \n", name, age);
    }
    public int compareTo(Person p)
    {
        return name.compareTo(p.name);
    }
}

class ComparablePerson 
{
	public static void main(String[] args)
	{
		TreeSet<Person> sTree=new TreeSet<Person>();
		sTree.add(new Person("Lee", 24));
		sTree.add(new Person("Hong", 29));
		sTree.add(new Person("Choi", 21));
		
		Iterator<Person> itr=sTree.iterator();
		while(itr.hasNext())
			itr.next().showData();
	}
}

 

39. 문자열을 사전편찬 순서가 아닌, 길이 순으로 정렬해서 TreeSet<E>에 저장하고 싶다.

     String 클래스의 Wrapper 클래스를 일단 다음과 같이 정의하였다.

     문자열의 길이 순으로 출력되게 하시오.

     다음의 문자열 값을 갖는 인스턴스를 생성

    “Orange”, “Apple”, “Dog”, “Individual”

    // 만약 toString()을 오버라이딩 안한다면

A.

import java.util.TreeSet;
import java.util.Iterator;

class MyString implements Comparable<MyString>
{
	String str;
	
	public MyString(String str)
	{
		this.str=str;
	}
	
	public int getLength()
	{
		return str.length();
	}
	
	public int compareTo(MyString mStr)
	{
		if(getLength()>mStr.getLength())
			return 1;
		else if(getLength()<mStr.getLength())
			return -1;
		else
			return 0;
		
		/*
		 * return getLength()-mStr.getLength();
		 */
	}
	
	public String toString()
	{
		return str;
	}
}

class ComparableMyString
{
	public static void main(String[] args)
	{
		TreeSet<MyString> tSet=new TreeSet<MyString>();		
		tSet.add(new MyString("Orange"));
		tSet.add(new MyString("Apple"));
		tSet.add(new MyString("Dog"));
		tSet.add(new MyString("Individual"));
		
		Iterator<MyString> itr=tSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

40. 오름차순의 반복자를 반환하는 iterator.

    그럼 내림차순의 반복자를 반환하는 메소드는?

A. 

Iterator<E> descendingIterator()  
// Returns an iterator over the elements in this set in descending order.

 

41. TreeSet<String> 인스턴스! 사전편찬 순서 말고, 길이 순으로 문자열을 정렬해라.

     이러한 유형의 요구를 위해 정의된 것이 ( )인터페이스이다.

A. TreeSet<String> 인스턴스! 사전편찬 순서 말고, 길이 순으로 문자열을 정렬해라.
    이러한 유형의 요구를 위해 정의된 것이 ( Comparator<T> )인터페이스이다.

interface Comparator<T>
{
	int compare(T obj1, T obj2);
	boolean equals(Object obj);
}

위의 인터페이스 중에서 equals 메소드는 신경 쓰지 않아도 된다. 

이 인터페이스를 구현하는 모든 클래스는 Object 클래스를 상속하기 때문에, 

Object 클래스의 equals 메소드가 위의 equals 메소드를 구현하는 꼴이 되기 때문이다.

 

42. 문제39를 문제 41의 인터페이스를 이용하여 코딩하시오.

A.

import java.util.TreeSet;
import java.util.Iterator;
import java.util.Comparator;

class StrLenComparator implements Comparator<String>
{
	public int compare(String str1, String str2)
	{
		if(str1.length()> str2.length())
			return 1;
		else if(str1.length()< str2.length())
			return -1;
		else
			return 0;
		
		/*
		 * return str1.length()-str2.length();
		 */
	}
}

class IntroComparator
{
	public static void main(String[] args)
	{
		TreeSet<String> tSet=new TreeSet<String>(new StrLenComparator());		
		tSet.add("Orange");
		tSet.add("Apple");
		tSet.add("Dog");
		tSet.add("Individual");
		
		Iterator<String> itr=tSet.iterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

43. TreeSet<E>를 이용하여 문제42에 있는 내용을 역순으로 출력되도록 예제를 변경해 보자.

    단, StrLenComparator 클래스는 변경되면 안된다. (API 참조)

    TreeSet<E> 클래스에 정의되어 있는 descendingIterator라는 메소드도

    iterator 메소드와 마찬가지로 반복자를 반환한다.

    단, iterator 메소드는 오름차순으로 검색하는 반복자를 반환하는 반면,

    descendingIterator는 내림차순으로 검색하는 반복자를 반환한다.

    따라서 다음의 코드를 삽입하면 내림차순으로 출력되는 문자열을 확인할 수 있다.

Iterator<String> rItr = tSet.descendingIterator();
while(rite.hasNext())
	System.out.println(rItr.next());

A.

import java.util.TreeSet;
import java.util.Iterator;
import java.util.Comparator;

class StrLenComparator implements Comparator<String>
{
	public int compare(String str1, String str2)
	{
		if(str1.length()> str2.length())
			return 1;
		else if(str1.length()< str2.length())
			return -1;
		else
			return 0;
		
		/*
		 * return str1.length()-str2.length();
		 */
	}
}

class IntroComparator
{
	public static void main(String[] args)
	{
		TreeSet<String> tSet=new TreeSet<String>(new StrLenComparator());		
		tSet.add("Orange");
		tSet.add("Apple");
		tSet.add("Dog");
		tSet.add("Individual");
		
		Iterator<String> itr=tSet.descendingIterator();
		while(itr.hasNext())
			System.out.println(itr.next());
	}
}

 

44. ( )를 구현하는 컬렉션 클래스들이 value만 저장하는 구조였다면,

    ( )를 구현하는 컬렉션 클래스들은 value를 저장할 때,

    이를 찾는데 사용되는 key를 함께 저장하는 구조이다.

A. ( Collection<E> )를 구현하는 컬렉션 클래스들이 value만 저장하는 구조였다면,

   ( Map<K, V> )를 구현하는 컬렉션 클래스들은 value를 저장할 때,

   이를 찾는데 사용되는 key를 함께 저장하는 구조이다.

 

45. Map<K, V> 인터페이스를 구현하는 대표적인 클래스

A.  HashMap<K, V>, TreeMap<K, V>

 

46. HashMap을 이용하여

    3, "나삼번"

    5, "윤오번"

    8, "박팔번" 을 입력하고,

각각을 출력한 후에

5번을 삭제하고, 5번을 출력해보자.

A.

import java.util.HashMap;

class IntroHashMap
{
	public static void main(String[] args)
	{
		HashMap<Integer, String> hMap=new HashMap<Integer, String>();

		hMap.put(new Integer(3), "나삼번");		
		hMap.put(5, "윤오번");	
		hMap.put(8, "박팔번");	
		
		System.out.println("6학년 3반 8번 학생: "+hMap.get(new Integer(8)));
		System.out.println("6학년 3반 5번 학생: "+hMap.get(5));
		System.out.println("6학년 3반 3번 학생: "+hMap.get(3));
		
		hMap.remove(5);		/* 5번 학생 전학 감 */
		System.out.println("6학년 3반 5번 학생: "+hMap.get(5));		
	}
}

 

47. Hash<K, V>를 구현하는 컬렉션 클래스들의 특징.

A.

- value에 상관없이 중복된 key의 저장은 불가능하다.
- value는 같더라도 key가 다르면 둘 이상의 데이터 저장도 가능하다.

HashSet<E>가 해시 알고리즘을 기반으로 구현되어 있듯이, 

HashMap<K, V> 역시 해시 알고리즘을 기반으로 구현되어 있다. 

따라서 HashSet<E>의 장점인 ‘매우 빠른 검색속도’는 HashMap<K, V>에도 그대로 반영이 된다. 

마찬가지로 TreeMap<K, V> 역시 ‘트리’ 자료구조를 기반으로 구현이 되어 있다. 

따라서 데이터는 정렬된 상태로 저장이 된다.

 

48. navigableKeySet 메소드가 호출되면,

    인터페이스 ( )를 구현하는 인스턴스의 참조 값이 반환된다.

    ( ) 인터페이스는 Set<E> 인터페이스를 상속받는다.

    즉, navigableKeySet 메소드가 반환하는 인스턴스를 대상으로 반복자를 얻기 위해서

    iterator 메소드의 호출해야 한다.

    그리고 이렇게 해서 얻은 반복자로, 저장된 모든 key에 접근이 가능하다.

   

    TreeMap<K, V>의 전체 데이터 검색

    TreeMap<K, V>Collection<E>가 아닌 ( )를 구현하는 컬렉션 클래스이니,

    저장되어 있는 전체 데이터를 검색하는 방식에 차이가 있음은 당연한 일이다.

 

    그리고 TreeMap<K, V>에 저장된 전체 데이터의 참조 과정에서

    호출한 navigableKeySet 메소드가 반환하는 인스턴스가 Set<E> 인터페이스를 구현한다.

    key는 중복이 불가능하기 때문에 집합의 성격을 띤다.

    때문에 이러한 key를 저장하는 인스턴스는 Set<E> 인터페이스를 구현하고 있는 것이다.

 

A. navigableKeySet 메소드가 호출되면, 

   인터페이스 ( NavigableSet<E> )를 구현하는 인스턴스의 참조 값이 반환된다.
   NavigableSet<E> 인터페이스는 ( Set<E> ) 인터페이스를 상속받는다.

   즉, navigableKeySet 메소드가 반환하는 인스턴스를 대상으로 반복자를 얻기 위해서

   iterator 메소드의 호출해야 한다.

   그리고 이렇게 해서 얻은 반복자로, 저장된 모든 key에 접근이 가능하다.
   

   TreeMap<K, V>의 전체 데이터 검색
   TreeMap<K, V>는 Collection<E>가 아닌 ( Map<K, V> )를 구현하는 컬렉션 클래스이니,

   저장되어 있는 전체 데이터를 검색하는 방식에 차이가 있음은 당연한 일이다.

 

   그리고 TreeMap<K, V>에 저장된 전체 데이터의 참조 과정에서

   호출한 navigableKeySet 메소드가 반환하는 인스턴스가 Set<E> 인터페이스를 구현한다.

   key는 중복이 불가능하기 때문에 ‘집합’의 성격을 띤다.

   때문에 이러한 key를 저장하는 인스턴스는 Set<E> 인터페이스를 구현하고 있는 것이다.

 

49. TreeMap을 이용하여

     1, “data1”

     3, “data3”

     5, “data5”

     2, “data2”

     4, “data4” 을 저장하고

    모든 데이터를 오름차순 출력

    모든 데이터를 내림차순 출력을 하시오.

A.

import java.util.TreeMap;
import java.util.Iterator;
import java.util.NavigableSet;

class IntroTreeMap
{
	public static void main(String[] args)
	{
		TreeMap<Integer, String> tMap=new TreeMap<Integer, String>();

		tMap.put(1, "data1");		
		tMap.put(3, "data3");	
		tMap.put(5, "data5");	
		tMap.put(2, "data2");	
		tMap.put(4, "data4");	
		
		NavigableSet<Integer> navi=tMap.navigableKeySet();
		
		System.out.println("오름차순 출력...");
		Iterator<Integer> itr=navi.iterator();
		while(itr.hasNext())
			System.out.println(tMap.get(itr.next()));
		
		System.out.println("내림차순 출력...");
		itr=navi.descendingIterator();
		while(itr.hasNext())
			System.out.println(tMap.get(itr.next()));	
	}
}

 

//Tip : ArrayList<E>

위에 코드에 사용된 'E'는 요소를 뜻하는 'Element'의 약자로

'E' 대신 어떤 다른 문자를 사용해도 상관없지만 소스코드 내에서 같은 문자를 일관되게 사용해야 한다.

이는 마치 메서드의 매개변수 이름을 다르게 해도 메서드 내에서만 같은 이름을 사용하면 문제 없는 것과 같다.

'E'Object 타입이다.

728x90