Java TreeSet 이진 트리 구조





결과

결과






코드

package pk;

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

public class Test {

	public static void main(String[] args) {
		TreeSet<Integer> ts = new TreeSet<Integer>();
		
		ts.add(8); ts.add(8); ts.add(3);
		ts.add(6); ts.add(7); ts.add(2);
		ts.add(9); ts.add(1); ts.add(5);
		
		// 이진 트리 : 부모보다 작은것은 왼쪽, 큰 것은 오른쪽에 저장 
		System.out.println("가장 작음 : " + ts.first());	// 가장 왼쪽
		System.out.println("가장 큼 : " + ts.last());	// 가장 오른쪽
		System.out.println("10이하 가장 가까움 : " + ts.floor(10));	// 미만은 lower 메소드
		System.out.println("10이상 가장 가까움 : " + ts.ceiling(10)); // 초과는 higher 메소드
		
		System.out.println("가장 작은 값 삭제 : " + ts.pollFirst());
		System.out.println("가장 큰 값 삭제 : " + ts.pollLast());
		
		
		Iterator<Integer> it = ts.iterator();
		System.out.print("\n오름차순 정렬 : ");
		while(it.hasNext()) System.out.print(it.next() + " ");
		
		it = ts.descendingIterator();
		System.out.print("\n내림차순 정렬 : ");
		while(it.hasNext()) System.out.print(it.next() + " ");
		
		
		System.out.print("\n\n=== 특정 범위 값들 가져오기 ===");
		NavigableSet<Integer> nav = ts.headSet(5, true); // true : 이하, false : 미만
		it = nav.iterator();
		System.out.print("\n5 이하 값들 : ");
		while(it.hasNext()) System.out.print(it.next() + " ");
		
		
		nav = ts.tailSet(5, false); // true : 이상, false : 초과
		it = nav.iterator();
		System.out.print("\n5 초과 값들 : ");
		while(it.hasNext()) System.out.print(it.next() + " ");
		
		
		nav = ts.subSet(3, true, 7, true); // true : 범위값도 포함, false = 미포함
		it = nav.iterator();
		System.out.print("\n3이상 7이하 값들 : ");
		while(it.hasNext()) System.out.print(it.next() + " ");
	}

}




TreeSet : 이진 트리 구조를 갖는다.

(부모 노드보다 작으면 왼쪽, 크면 오른쪽 자식 노드의 위치)


ㄴ 따라서 [왼쪽 자식 노드 -> 부모 노드 -> 오른쪽 자식 노드 ] 순으로 값을 읽기만 하여도 오름차순으로 정렬된 값들을 얻어올 수 있게 된다.

이와 같은 구조 때문에 검색을 빠르게 할 수 있다.


ㄴ TreeSet은 Set이 들어가 있어 알수 있듯이 이진 트리 구조의 Set 컬렉션으로 중복된 값을 가질 수 없다.





메소드



삽입, 삭제 등 : Set 컬렉션으로 동일한 메소드를 사용한다.

링크

[JAVA/심화] - Java HashSet - 집합 삽입, 삭제, 탐색





E first() : 가장 작은 값

- 가장 작은 값, 즉 이진트리에서 가장 왼쪽의 값이다.





E last() : 가장 큰 값

- 가장 큰 값, 즉 이진트리에서 가장 오른쪽 값이다.





E floor(E e) : 인수보다 이하의 객체(값)

- 인수의 해당하는 값이 없다면 그보다 이하의 값들 중 가장 가까운 값을 리턴한다.


- 미만의 값을 구하고자 한다면 lower() 메소드를 사용하면 된다.





E ceiling(E e) : 인수보다 이상의 객체(값)

- 인수의 해당하는 값이 없다면 그보다 이상의 값들 중 가장 가까운 값을 리턴한다.


- 단, 존재하지 않을 경우 null을 리턴한다.


- 초과의 값을 구하고자 한다면 higher() 메소드를 사용하면 된다.





E pollFirst() / E pollLast = First 값 제거 / Last 값 제거

- 해당하는 값을 리턴해준 후 제거한다.






정렬



- 오름차순 : 이진 트리 구조상 이미 정렬이 되어져 있으므로 iterator() 메소드로 가져오면 오름차순으로 정렬되어 있다.




- 내림차순 : descendingIterator() 메소드를 사용하여서 Iterator<E>의 가져오면 내림차순으로 정렬된다.





범위 검색



NavigableSet<E> headSet(E e, boolean b) : 인수 값보다 작은 값들 검색

- 위 예시에서는 5를 주어서 5이하의 값들을 검색하였다.


- 2번 째 인자인 b가 

true일 경우 e 이하를 검

false일 경우 e 미만을 검색

한다.





NavigableSet<E> tailSet(E e, boolean b) : 인수 값보다 큰 값들 검색

- 위 예시에서는 5와, false를 주어서 5를 초과하는 값들을 검색하였다.


- 2번 째 인자인 b가 

true일 경우 e 이상을 검색

false일 경우 e 초과를 검색

한다.





NavigableSet<E> subSet(E start, boolean b, E end, boolean b2) 

- 시작 값과 끝 값을 인수로 주어 그 사이 범위의 값들을 리턴한다.


- 2, 4번 째 인자는 동일하게 true면 해당값도 포함이며 false면 미포함이다.









Java Key, Value - HashMap, Hashtable






결과

결과







코드

package pk;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Test {

	public static void main(String[] args) {
		Map<Integer, String> m = new HashMap<>();
		
		m.put(5, "E");	
		m.put(3, "C");	
		m.put(1, "A");	
		m.put(2, "B");	
		m.put(1, "X");	// 동일한 키 존재 시 해당 값 변경
		
		System.out.println("Key 4 존재 ? " + m.containsKey(4) );
		System.out.println("Value C 존재 ? " + m.containsValue("C") );
		System.out.println();
		
		System.out.println("Key 3의 Value : " + m.get(3));
		System.out.println("Key 4의 Value : " + m.get(4));	// 해당 키가 없다면 null 리턴
		System.out.println("길이 : " + m.size());
		
		m.remove(3);	// 삭제
		
		System.out.println();
		// Key
		Iterator<Integer> it = m.keySet().iterator();	// 모든 키를 Set의 넣어 리턴 + iterator
		while(it.hasNext()) {
			System.out.print(it.next() + " ");
		}
		
		System.out.println();
		// Value
		Iterator<String> it2 = m.values().iterator();	// 모든 값을 Collection에 넣어 리턴 + iterator
		while(it2.hasNext()) {
			System.out.print(it2.next() + " ");
		}
	}

}




HashMap : <Key, Value> 쌍의 값을 저장하는 구조이다.

값은 중복될 수도 있지만, 키는 중복 저장이 불가능하다.

만약 기존의 존재하는 키로 추가하였을 때는 해당 키의 값이 변경된다.



HashTable : HashMap과 동일한 구조, 사용방법을 갖는다.

단, HashTable은 스레드의 안전(Thread Safe) 하다.








put(K k, V v) : 추가

- 기존의 존재하는 키를 추가하였을 시 값이 변경된다.





V remove(K k) : 삭제

- 인수로 준 키의 해당하는 쌍을 삭제한다.


- 존재하지 않을 경우 null을 리턴한다.





boolean containsKey(K k) : 키 존재 여부

- 해당 키가 존재하는지 확인한다.





boolean containsValue(V v) : 값 존재 여부

- 해당 값이 존재하는지 확인한다.





V get(K k) : 값 얻기

- 인수로 준 키의 해당하는 값을 리턴한다.


- 존재하지 않는 키일 경우 null을 리턴한다.




int size() : 길이(개수) 리턴




Set<K k> keySet() : 키 Set 리턴





Collection<V v> values() : 값 Collection 리턴










Java Queue(큐) 컬렉션 사용





결과

결과





코드

package pk;

import java.util.LinkedList;
import java.util.Queue;

public class Test {

	public static void main(String[] args) {
		Queue<String> ss = new LinkedList<>();
		
		// ss.add() = ss.offer() 삽입
		// ss.remove() = ss.poll() 삭제
		// ss.element() = ss.peek() 맨앞
		
		System.out.println(ss.offer("가") );
		ss.offer("나");
		ss.offer("다");
		ss.offer("가");
		ss.offer("라");
		
		System.out.println("현재 맨앞 : " + ss.peek());
		System.out.println("'다' 포함 여부 : " + ss.contains("다"));
		

		while(!ss.isEmpty()) {
			System.out.print(ss.poll() + " ");
		}
		
	}

}





Queue(큐) : 선입선출의 구조로서 먼저 들어온 객체가 가장 먼저 나가는 자료구조 이다.

Queue 인터페이스로 구현된 클래스 중 하나가 LinkedList 이며 이를 형변환하여 사용한다.





boolena offer() & add() : 삽입

- 객체를 삽입한다.






E poll() & remove() : 삭제

- 맨앞의 객체를 삭제한며 리턴해준다.


- 큐가 비어있을 경우 poll()을 사용하여 삭제를 시도하면 null을 리턴하지만 

remove() 사용하면 Exception을 발생시켜 종료한다.





E peek() & element() : 맨앞 가져오기

- 맨앞의 객체를 리턴해준다.


- 큐가 비어있을 경우 peek()를 사용한다면 null을 리턴해주지만 

element() 사용한다면 Exception을 발생시켜 종료한다.





boolean contains(E e) : 객체 찾기


- 인수로 준 객체가 존재한다면 true 아니면 false를 리턴한다.






Java Stack(스택) 컬렉션 사용





결과

결과





코드

package pk;

import java.util.Stack;

public class Test {

	public static void main(String[] args) {
		Stack<String> ss = new Stack<>();
		
		ss.push("가");
		ss.push("나");
		ss.push("다");
		ss.push("가");
		ss.push("라");
		
		System.out.println("현재 맨위 : " + ss.peek());
		System.out.println("'가' 순서 : " + ss.search("가"));
		System.out.println("'라' 순서 : " + ss.search("라"));
		
		while(!ss.empty() ) {
			System.out.print(ss.pop() + " ");
		}
		
	}

}




Stack : 후입선출의 구조로서 나중에 들어온 값이 가장 먼저 나가는 자료구조이다.





E push(E e) : 객체 삽입

- 인수로 준 객체를 스택의 삽입한다.


- 리턴형은 E로 삽입한 객체를 리턴한다.





E peek() : 객체를 가져옴

- 스택에서 객체를 갖고온다.

후입선출의 구조이므로 가장 위에 있는 값, 즉 가장 마지막으로 들어온 값을 리턴한다.


- pop과는 다르게 꼭대기 값을 가져오기만 한다.





E pop() : 객체를 삭제

- 가장 꼭대기의 객체를 삭제한다.


- 리턴형은 E로서 삭제한 객체를 리턴한다.


ㄴ 객체를 가져옴 = peek()

ㄴ 객체를 가져옴 + 삭제 = pop()





int serach(E e) : 객체를 찾음

- 꼭대기부터 인수로 준 객체를 스택에서 찾는다.


- 찾는 다면 해당 객체의 순서를 리턴한다.

여기서 순서란 꼭대기(=1) 부터 아래로 내려갈수록 1씩 증가한다.


즉, 스택의 들어온 역순이며 해당 객체와 동일한 객체가 다수 존재하면 꼭대기와 가장 가까운 객체의 순서를 리턴한다.


만약 객체가 없을경우 -1을 리턴한다.









Java HashSet - 집합 삽입, 삭제, 탐색





결과

결과





코드

package pk;

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

public class Test {

	public static void main(String[] args) {
		HashSet<String> ss = new HashSet<String>();
		
		ss.add("가");
		ss.add("나");
		ss.add("다");
		ss.add("라");
		ss.add("가");
		
		for(String s : ss) {
			System.out.print(s + " ");
			if(s.equals("라")) ss.remove(s);
		}
		
		System.out.println();
		Iterator<String> it = ss.iterator();
		while(it.hasNext()) {
			String s = it.next();
			System.out.print(s + " ");
			if(s.equals("다")) it.remove();
		}
		
		System.out.println();
		for(String s : ss) {
			System.out.print(s + " ");
		}
		System.out.println();
		System.out.println("길이 : " + ss.size());
		System.out.println("'가' 포함 여부 : " + ss.contains("가"));
		
	}

}




HashSet : 저장 순서가 유지되지 않으며 동일한 값을 1개만 저장할 수 있다.

중복이 없고, 순서가 없으므로 집합으로 볼 수 있다.

ex) 결과 1라인을 보면 중복이 허용안되며 순서도 무작위인걸 확인 가능하다.





boolean add(E e) : 원소 추가

- 리턴형이 boolean형으로 저장이 완료되면 true를, 중복된 원소라 저장이 실패한다면 false를 리턴한다.




boolean remove(Object o) : 원소 제거

- 성공적으로 제거하면 true를 실패하면 false를 리턴한다.




isEmpty() : 비었는지 검사




size() : 개수를 구함




boolean contains(Object o) : 포함 여부 확인

- 인수로 준 객체가 존재하는지 검사한다.




iterator() : iterator 객체를 얻음




탐색

1. for each문을 사용


2. Iterator를 사용

ㄴ boolean hasNext() : 가져올 객체가 있는지 없는지 검사한다.

ㄴ E next() : 한칸 다음으로 이동 후 그 객체 값을 리턴한다.


ex) 0 "가" "나 "다" "라"

이러한 set이 있다면 처음 next()를 실행하였을 경우 0에서 "가" 로 이동한 후 "가"를 리턴하게 된다.






+) 추가


- HashSet은 객체를 비교할 시 hashCode()와 equals() 메소드들을 재정의하여 조건을 지정해 주어야 한다.



링크

[JAVA/심화] - Java HashSet 합집합, 차집합, 교집합, 부분집합






Java 제네릭(Generic) 타입 




- Java API Document를 보면 많은 제네릭 타입을 사용하고 있으므로 이를 이해하고 있어야만 정확히 이해하고, 사용할 수 있다.

https://docs.oracle.com/javase/8/docs/api/



- 제네릭 타입은 "<>" 부호를 사용하며 타입을 인수로 받을 수 있도록 한다.



- 제네릭 타입을 사용함으로써 타입 검사를 강화함으로써 에러를 줄일 수 있다.

또한, 캐스팅(타입 변환)을 없애주므로 성능을 향상시킬 수 있다.






결과

결과





코드

package pk;

public class Test<T, S> {
	T num;
	S[] count;
	
	public Test(T n, int size) {
		this.num = n;
		this.count = (S[]) new Object[size];
	}
	
	void getC() {
		System.out.print(num + ". ");
		for(S i : count) {
			System.out.print(i + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		Test<Integer, String> t = new Test<Integer, String>(1, 3);
		Test<Integer, Integer> t2 = new Test<>(3, 4);
		t.getC();
		t2.getC();
	}

}



- 제네릭 타입은 클래스<T, S> 이렇게 쓰곤 한다. (보통 대문자로 표기한다.)


- 제네릭 타입은 멤버 변수 타입을 지정하거나 메소드 리턴형을 지정할 때나 다 사용할 수 있다.


- 21라인 : int형을 지정하고자 하면 Integer를 사용해야 한다.


- 9라인 : 제네릭 타입 배열을 초기화 해줄 때는 Object 객체형으로 생성한 후 강제 형변환으로 변환해주어야 한다.

(Object는 모든 객체의 최상위 부모이다.)


- 22라인 : 뒤쪽을 보면 21라인과 달리 "<>" 속 값을 생략할 수도 있다.






제네릭 타입 제한


- 제네릭 타입<?> : 모든 클래스나 인터페이스가 올 수 있다.



- 제네릭 타입<? extends 클래스> : 상위 클래스 제한

해당 클래스 및 해당 클래스의 자식 클래스만이 올 수 있다.



- 제네릭 타입<? super 하위타입> : 하위 클래스 제한

해당 클래스 및 해당 클래스의 부모 클래스만이 올 수 있다.







Java Pattern 문자열 검증하기





결과

결과





코드

public static void main(String[] args) {
		String sec1 = "(010|02)-\\d{3,4}-\\d{4}";
		String phone = "010-1234-5678";
		
		if(Pattern.matches(sec1, phone)) {
			System.out.println("전화번호가 양식에 맞습니다.");
		}
		else {
			System.out.println("전화번호가 양식에 맞지 않습니다.");
		}
		
		String sec2 = "\\w+@\\w+\\.\\w+";
		String sec3 = "\\w+@\\w+\\.\\w+(\\.\\w+)?";
		String email = "abcde@abcde.co.kr";
		
		
		System.out.println("이메일이 양식에 " + (Pattern.matches(sec2, email) ? "맞습니다." : "맞지 않습니다.") );
		System.out.println("이메일이 양식에 " + (Pattern.matches(sec3, email) ? "맞습니다." : "맞지 않습니다.") );
		
	}





Pattern 클래스 : 문자열 검증

- 이메일이나 전화번호 등 특정 형식(양식)이 정해져있는 값을 입력 받았을 때 올바른 양식대로 값을 입력하였는지 확인하기 위하여 사용한다.


- java.util.regex.Pattern 을 import 한다.


- Pattern 클래스의 matches 메소드의 표현식과 검증할 문자열을 주어 검사한다.



- 정규 표현식 기호들

 기호

의미 

\d

한 개의 숫자

\w

한 개의 영어 또는 수잦

\s

공백

[a-z]

a~z 중 한개의 문자

ex) [0-9] : 0~9 중 한 개

?

없거나 또는 한 개

*

없거나 또는 한 개 이상

+

한개 이상

( )

수식처럼 묶기

|

파이프 문자(OR)

{ }

{n} : 정확히 n개만 있다.

{n,} : 최소 n개는 있다.

{n, m} : n개 이상 m개 이하이다.



- 정규 표현식 기호를 사용하여 정규 표현식을 만들 때 이는 문자열이므로 문자열 안에서 \를 표현하기 위하여 '\\' 처럼 2번을 써주어야 한다.

'.'을 사용해 줄 때도 '\.' 처럼 작성해주어야 한다.



- 괄호로 묶은 다음 ? 를 준다면 괄호 내의 내용이 없거나 한개 라는 의미이다.

위 결과를 보면 검사할 이메일의 형식이 '.co.kr' 으로 2번의 '.'과 문자들이 사용된다.

따라서 ( )와 ?를 사용하여 맨 뒤에 '.kr' 처럼 '.'이 한번더 사용하여도 검사의 통과되도록 할 수 있다.





Java Date, Calendar, SimpleDateFormat 시간 구하기





결과

결과





코드

public static void main(String[] args) {
		Date date = new Date();
		System.out.println("시간 확인 : " + date.toString());
		
		SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd, hh:mm:ss, E요일, 올해D일째");
		System.out.println("시간 확인(포맷팅) : " + sf.format(date) + "\n");
		
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);		// 년도
		int month = cal.get(Calendar.MONTH) + 1;	// 월 0~11
		int day = cal.get(Calendar.DAY_OF_MONTH);	// 일
		int yoil = cal.get(Calendar.DAY_OF_WEEK);	// 요일
		int hour = cal.get(Calendar.HOUR_OF_DAY);	// 시 0~23
		int min = cal.get(Calendar.MINUTE);	// 분
		int sec = cal.get(Calendar.SECOND);	// 초
		String[] yo = {"일", "월", "화", "수", "목", "금", "토"};
		// Calendar.SUNDAY : 1 ~ Calendar.SATURDAY : 7
		
		System.out.println("Cal 얻은 값 : " + year + "년" + month + "월" + day + "일 " +
		yo[yoil-1] + "요일 " + hour + "시" + min + "분" + sec + "초");
	}





Date : 날짜 표현 클래스

- 생성자가 여러개 있지만 대부분 비권장(Deprecated) 되어 사용 않는다.


- Date()를 생성하면 컴퓨터의 현재 날짜를 읽어 Date 객체를 생성한다.


- toString() 메소드를 사용하면 날짜를 문자열로 얻을 수 있다.


- 문자열을 특정한 포맷으로 얻고자 한다면 SimpleDateFormat을 사용한다.





SimpleDateFormat : 날짜 포맷 클래스

- 특정 포맷 문자열로 Date 객체의 날짜와 시간을 얻고자할 때 사용한다.


- 문자열 포맷은 SimpleDateFormat 객체를 생성할 때 생성자에서 지정해주며 포맷 기호들을 사용하여서 작성한다.


문자

설명

문자

설명

y

년도

M

d

D

올해 기준 일

H

시(0~23)

h

시(1~12)

k

시(1~24)

K

시(0~11)

m

s

E

요일

a

오전 / 오후

W

이번달 몇 번째 주

w

올해 몇 번째 주





Calendar : 이름처럼 달력을 표현하는 클래스

- 지역이나 나라마다 날짜를 계산하는 방법이 다르므로 Calendar는 인스턴스를 생성할 수 없도록 추상 클래스로되어 있다.


- Calendar cal = Calendar.getInstance(); 로 한다면 현재 OS의 설정된 시간을 갖는 객체를 얻을 수 있다.


- Calendar.MONTH 는 리턴값이 0~11로서 0부터 시작하므로 결과의 1을 더해주어야 원하는 값을 얻을 수 있다.


- Calendar.DAY_OF_WEEK는 요일을 얻을 수 있으며 리턴형은 int이다. 

값을 확인해보면 Calendar.SUNDAY : 1 ~ Calendar.SATURDAY : 7 이다.

따라서 위 코드에서는 요일을 갖는 문자열 배열을 만들어 간단하게 표현하였다.


- Calendar.HOUR = 0~11 이며 Calendar.HOUR_OF_DAY = 0~23 이므로 HOUR을 사용하고자 한다면 따로 AM/PM을 표시해주어야 한다.







+ Recent posts