728x90
반응형
컬렉션 프레임워크
- 널리 알려진 자료구조를 바탕으로 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련 인터페이스와 클래스들을 포함시켜 놓은 java.util 패키지
- 주요 인터페이스 : List, Set, map
List 컬렉션
- 객체를 인덱스로 관리하기 때문에 객체를 저장하면 인덱스가 부여되고 인덱스로 객체를 검색, 삭제할 수 있는 기능을 제공.
ArrayList
- ArrayList에 객체를 추가하면 내부 배열에 객체가 저장되고 제한 없이 객체를 추가할 수 있음.
- 객체의 번지를 저장. 동일한 객체를 중복 저장 시 동일한 번지가 저장. (null 저장 가능)
- ArrayList 컬렉션에 객체를 추가 시 인덱스 0번부터 차례대로 저장.
- 특정 인덱스의 객체를 제거하거나 삽입하면 전체가 앞/뒤로 1씩 당겨지거나 밀림.
- 빈번한 객체 삭제와 삽입이 일어나는 곳에선 바람직하지 않음.
ArrayList 예제
package collectionEx.board;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Board {
private String subject;
private String writer;
private String content;
}
package collectionEx.board;
import java.util.ArrayList;
import java.util.List;
public class BoardEx {
public static void main(String[] args) {
List<Board> boardList = new ArrayList<Board>();//Board는 게시물 1개를 말한다. boardList는 여러개의 게시물을 저장하는 저장소.
boardList.add(new Board("맛있는 점심1", "이주환1", "선배! 마라탕 사주세여!"));
boardList.add(new Board("맛있는 점심2", "이주환2", "탕후루도 같이~?"));
boardList.add(new Board("맛있는 점심3", "이주환3", "그럼 제가 선배 맘에"));
boardList.add(new Board("맛있는 점심4", "이주환4", "탕탕!! 후루후루!!"));
boardList.add(new Board("맛있는 점심5", "이주환5", "탕탕!! 후루루루루루~~"));
int boardSize = boardList.size();
System.out.println(boardSize);
//특정 인덱스를 지정하여 객체 가져오기
Board board = boardList.get(2);
System.out.println(board.getSubject() + "\t" + board.getWriter() + "\t" + board.getContent());
System.out.println("=================================================");
//boardList의 모든 게시글 다 출력해보기
//1. index를 이용하기
for (int i = 0; i < boardList.size(); i++) {
Board board1 = boardList.get(i);
System.out.println(board1.getSubject() + "\t" + board1.getWriter() + "\t" + board1.getContent());
}
System.out.println("=================================================");
//2. enhanced for 문 활용하여 모든 객체 출력하기
for (Board b : boardList){
System.out.println(b.getSubject() + " " + b.getWriter() + " " + b.getContent());
}
Integer[][][] data_list = {
{
{1, 2, 3},
{4, 5, 6}
},
{
{7, 8, 9},
{10, 11, 12}
}
};
System.out.println(data_list[0][1][1]);
System.out.println(data_list[1][1][2]);
String dataset[] = {
"Braund, Mr. Owen Harris",
"Cumings, Mrs. John Bradley (Florence Briggs Thayer)",
"Heikkinen, Miss. Laina",
"Futrelle, Mrs. Jacques Heath (Lily May Peel)",
"Allen, Mr. William Henry",
"Moran, Mr. James",
"McCarthy, Mr. Timothy J",
"Palsson, Master. Gosta Leonard",
"Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg)",
"Nasser, Mrs. Nicholas (Adele Achem)",
"Sandstrom, Miss. Marguerite Rut",
"Bonnell, Miss. Elizabeth",
"Saundercock, Mr. William Henry",
"Andersson, Mr. Anders Johan",
"Vestrom, Miss. Hulda Amanda Adolfina",
"Hewlett, Mrs. (Mary D Kingcome) ",
"Rice, Master. Eugene",
"Williams, Mr. Charles Eugene",
"Vander Planke, Mrs. Julius (Emelia Maria Vandemoortele)",
"Masselmani, Mrs. Fatima",
"Fynney, Mr. Joseph J",
"Beesley, Mr. Lawrence",
"McGowan, Miss. Anna",
"Sloper, Mr. William Thompson",
"Palsson, Miss. Torborg Danira",
"Asplund, Mrs. Carl Oscar (Selma Augusta Emilia Johansson)",
"Emir, Mr. Farred Chehab",
"Fortune, Mr. Charles Alexander",
"Dwyer, Miss. Ellen",
"Todoroff, Mr. Lalio"
};
int count = 0;
for (String s : dataset){
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'M') {
count++;
break;
}
}
}
System.out.println(count);
int num = 0;
for (int i = 0; i < dataset.length; i++) {
if (dataset[i].indexOf("M") >= 0){
num++;
}
}
System.out.println(num);
int number = 0;
for (String s : dataset){
if (s.indexOf("M") >= 0){
number++;
}
}
System.out.println(number);
}
}
Vector
- 동기화된 메서드로 구성되어 있어 멀티 스레드가 동시에 Vector() 메서드를 실행할 수 없음.
- 멀티 스레드 환경에서는 안전하게 객체를 추가 또는 삭제할 수 있음.
LinkedList
- 떨어진 곳에 존재하는 데이터를 화살표(포인터)로 연결해서 관리하는 데이터 구조.
- 인접 객체를 체인처럼 연결해서 관리. 객체 삭제와 삽입이 빈번한 곳에서 ArrayList보다 유리.
- 노드(Node) : 데이터의 저장 단위(데이터 값, 포인터)로 구성.
- 포인터(Pointer) : 각 노드 안에서, 다음이나 이전의 노드와의 연결정보를 가지고 있는 공간.
- 장점 : 미리 데이터 공간을 할당하지 않아도 됨. 빈번한 데이터의 추가, 삭제 시 효율적으로 관리 용이.
- 단점 : 연결을 위한 별도의 공간 할당이 필요하므로 공간 효율이 좋지는 않음. 연결 정보를 찾는 시간이 필요하여 접근 속도가 느림.
LinkedList 예제
package collectionEx.list;
public class SingleLinkedListEx {
public static void main(String[] args) {
Node<Integer> node1 = new Node<Integer>(1);
Node<Integer> node2 = new Node<Integer>(2);
node1.next = node2;
Node<Integer> head = node1;
SingleLinkedList<Integer> myList = new SingleLinkedList<>();
myList.addNode(1);
myList.addNode(2);
myList.addNode(3);
// System.out.println(myList.head.next.data);
myList.addNodeInside(5, 1);
// myList.printAll();
myList.delNode(3);
myList.printAll();
}
}
package collectionEx.list;
public class Node <T>{
public Node<T> next;
T data;
public Node(T data){
this.data = data;
}
}
package collectionEx.list;
public class SingleLinkedList <T>{
public Node<T> head = null;
public class Node<T>
{
T data;
Node<T> next = null;
public Node(T data){
this.data = data;
}
}
public void addNode(T data){
if (head == null){
head = new Node<T>(data);
} else {
Node<T> node = this.head;
while (node.next != null){
node = node.next;
}
node.next = new Node<T>(data);
}
}
public void printAll(){
if (head != null){
Node<T> node = this.head;
System.out.println(node.data);
while (node.next != null){
node = node.next;
System.out.println(node.data);
}
}
}
public Node<T> search(T data){
if (this.head == null){
return null;
} else {
Node<T> node = this.head;
while (node != null){
if (node.data == data){
return node;
} else {
node = node.next;
}
}
return null;
}
}
public void addNodeInside(T data, T isData){
Node<T> searchNode = this.search(isData);
if (searchNode == null){
this.addNode(data);
} else {
Node<T> nextNode = searchNode.next;
searchNode.next = new Node<T>(data);
searchNode.next.next = nextNode;
}
}
public boolean delNode(T isData){
if (this.head == null){
return false;
} else {
Node<T> node = this.head;
if (node.data == isData){
this.head = this.head.next;
return false;
} else {
while (node.next != null){
if (node.next.data == isData){
node.next = node.next.next;
return true;
}
node = node.next;
}
return false;
}
}
}
}
ArrayList와 LinkedList의 작업 속도 비교
package collectionEx.list;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.SimpleTimeZone;
public class DiffEx {//ArrayList와 LinkedList 객체 추가 성능평가
public static void main(String[] args) {
List<String> list1 = new ArrayList();
List<String> list2 = new LinkedList();
//시작 시간과 끝 시간을 저장할 변수 선언
long startTime;
long endTime;
//ArrayList와 LinkedList의 작업 속도 비교
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list1.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.printf("%-15s %8s ns \n", "ArrayList 걸린 시간 : ", endTime - startTime);
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list2.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.printf("%-15s %8s씬ns \n", "LinkedList 걸린 시간 : ", endTime - startTime);
//ArrayList 걸린 시간 : 5535667 ns
//LinkedList 걸린 시간 : 879750 ns
//LinkedList가 훨 빠른 것을 알 수 있음.
//ArrayList는 0번 인덱스에 새로운 객체가 추가되면서 기존 객체의 인덱스를 한 칸씩 미루는 작업을 해야 하므로, 전체 작업 시간이 오래 걸림.
}
}
Queue
- 줄을 서는 행위와 같은 가장 먼저 들어간 데이터를 가장 먼저 꺼낼 수 있는 구조(FIFO -> 안외워지면 구급차는 급하니까 삐뽀삐뽀..ㅎ)
- Enqueue : 큐에 데이터를 넣는 기능.[ add(value), offer(value)]
- Dequeue : 큐의 데이터를 꺼내는 기능.[ poll(value), remove(value)]
- 큐 클래스에서 데이터 생성을 하기 위해서는 java.util.LinkedList 사용.
- 멀티태스킹 - 프로세스 스케쥴링 방식을 구현할 때 사용됨.
package collectionEx.list;
import java.util.ArrayList;
public class MyQueue <T>{
private ArrayList<T> queue = new ArrayList<T>();
public void enqueue(T item){
queue.add(item);
}
public T dequeue(){
if (queue.isEmpty()){
return null;
}
return queue.remove(0);
}
public boolean isEmpty(){
return queue.isEmpty();
}
public static void main(String[] args) {
MyQueue<Integer> myQueue = new MyQueue<Integer>();
myQueue.enqueue(1);
myQueue.enqueue(2);
myQueue.enqueue(3);
myQueue.enqueue(4);
myQueue.enqueue(5);
System.out.println(myQueue.dequeue());
System.out.println(myQueue.dequeue());
System.out.println(myQueue.dequeue());
System.out.println(myQueue.dequeue());
System.out.println(myQueue.dequeue());
}
}
Set 컬렉션
- Set 컬렉션은 저장 순서가 유지되지 않음.
- 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있음(수학의 집합 개념)
HashSet
- 동등 객체(hashCode()메서드의 리턴값이 같고, equals() 비교시 true가 리턴되는 것)를 중복 저장하지 않음.
- 다른 객체라도 hashCode() 메서드의 리턴값이 같고, equals() 메서드가 true를 리턴하면 동일한 객체라고 판단하고 중복 저장하지 않음.
- iterator() 메서드는 반복자를 얻어 Set 컬렉션의 객체를 하나씩 가져옴.
package set;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Member {
public String name;
public int age;
@Override
public int hashCode() {
return name.hashCode() + age;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Member member){
return member.name.equals(name) && member.age == age;
} else {
return false;
}
}
}
package set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetEx01 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
//객체 저장
set.add("신세계");
set.add("신세계");
set.add("신세계1");
System.out.println(set.size());
System.out.println("================================");
Set<Member> memberList = new HashSet<>();
memberList.add(new Member("ssg", 20));
memberList.add(new Member("ksg", 20));
memberList.add(new Member("lsg", 20));
memberList.add(new Member("msg", 20));
//회원을 반복자 Iterator 를 이용해서 가져오기
Iterator<Member> iterator = memberList.iterator();
while (iterator.hasNext()){
//회원 한명 가져오기
Member member = iterator.next();
System.out.println(member.name + "\t" + member.age);
if (member.name.equals("ksg")) iterator.remove();
}
System.out.println("================================");
//회원을 반복자 Iterator 를 이용해서 가져오기
Iterator<Member> iterator1 = memberList.iterator();
while (iterator1.hasNext()){
//회원 한명 가져오기
Member member = iterator1.next();
System.out.println(member.name + "\t" + member.age);
if (member.name.equals("ssg")) iterator1.remove();
}
System.out.println("================================");
memberList.removeIf(member -> "msg".equals(member.getName()));//이렇게도 삭제 가능.
System.out.println("================================");
//회원을 enhanced fot 를 이용해서 가져오기
for (Member member : memberList){
System.out.println(member.name + "\t" + member.age);
}
System.out.println(memberList.size());
}
}
Map 컬렉션
- 키(key)와 값(value)으로 구성된 엔트리 객체를 저장.
- 키는 중복 저장할 수 없지만 값은 중복 저장할 수 있음.
- 기존에 저장된 키와 동일한 키로 값을 저장하면 새로운 값으로 대치.
HashMap
- 키로 사용할 객체가 hashCode() 메서드의 리턴값이 같고 equals() 메서드가 true를 리턴할 경우, 동일한 키로 보고 중복 저장을 허용하지 않음.
package mapEx;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class HashMapEx {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
//객체 저장
map.put(1, "김미란");
map.put(2, "최미란");
map.put(3, "박미란");
map.put(4, "이미란");
map.put(5, "고미란");
map.put(6, "고미란");
System.out.println(map.size());
System.out.println("======================");
Integer key = 1;
String value = map.get(key);
System.out.println(value);
//keySet 컬렉션을 이용하여 반복자를 통해 키와 값을 가져오기
Set<Integer> keySet = map.keySet();
Iterator<Integer> keyIterator = keySet.iterator();
while (keyIterator.hasNext()){
Integer key1 = keyIterator.next();
String value1 = map.get(key1);
System.out.println("key : " + key1 + "\t" + "value : " + value1);
}
//엔트리set 컬렉션으로 반복해서 키와 값을 가져오기
Set<Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Entry<Integer, String>> entryIterator = entrySet.iterator();
while (entryIterator.hasNext()){
Entry<Integer, String> entry = entryIterator.next();
Integer key2 = entry.getKey();
String value2 = entry.getValue();
System.out.println("key : " + key2 + "\t" + "value : " + value2);
}
map.remove(1);
map.remove(2, "최미란");
}
}
HashTable
- 동기화된 메서드로 구성되어 있어 멀티 스레그다 동시에 HashTable의 메서들을 실행 불가.
- 멀티 스레드 환경에서도 안전하게 객체를 추가, 삭제할 수 있음.
Properties
- Properties는 HashTable의 자식 클래스. 키와 값을 String 타입으로 제한한 컬렉션.
- 주로 확장자가 .properties인 프로퍼티 파일을 읽을 때 사용.
- 프로퍼티 파일은 키와 값이 = 기호로 연결괸 텍스트 파일(ISO 8859 - 1 문자셋, 한글은 \u+유니코드)
- Properties 객체를 생성하고, load() 메서드로 프로퍼티 파일의 내용을 메모리로 로드.
package mapEx;
import java.util.Properties;
public class PropertiesEx {
public static void main(String[] args) throws Exception {
//Properties 컬렉션 생성
Properties properties = new Properties();
//Properties 클래스를 기준으로 database.properties 를 읽어온다.(상대경로)
//Class 객체의 getResourceAsStream 메서드는 주어진 상대 경로의 리소스 파일을 읽어와 InputStream을 리턴해준다.
properties.load(PropertiesEx.class.getResourceAsStream("database.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
System.out.println(driver);
System.out.println(url);
}
}
Tree 구조
- 노드(Node)와 브랜치(branch)를 이용해서, 사이클이 이루어지지 않도록 구성한 데이터 구조.
- Node : 트리에서 데이터를 저장하는 기본 요소.(데이터와 연결된 다른 노드에 대한 브랜치 정보 포함)
- Root Node : 트리에서 맨 상위의 노드.
- Level : 최상위 노브(Root Node)를 Level 0으로 하고, 하위 브랜치로 연결된 노드의 깊이를 나타냄.
- Parent Node : 한 노드의 상위 레벨에 연결된 노드.
- Child Node : 한 노드의 하위 레벨에 연결된 노드.
- Leaf Node(Termianl Node) : Child Node가 없는 노드.
- Sibling Node(Brother Node) : 동일한 Parent Node를 가지는 노드.
- Depth : 트리에서 Node가 가질 수 있는 최대 Level.
- 트리 중 이진트리 형태가 가장 많이 이용되는데, 탐색(검색) 알고리즘 구현을 위해 사용됨.
- 이진트리 : 노드의 최대 브랜치가 2개인 트리.
- 이진탐색트리(Binary Search Tree) : 이진트리에 왼쪽 노드는 부모 노드보다 작은 값, 오른쪽 노드는 부모노드보다 큰 값으로 트리 구성.
- 주요 용도 : 데이터 검색(탐색)
- 장점 : 탐색 속도를 개선 가능.
package tree;
public class BinaryTreeEx {
public static void main(String[] args) {
NodeMgmt myTree = new NodeMgmt();
myTree.insertNode(2);
myTree.insertNode(3);
myTree.insertNode(4);
myTree.insertNode(5);
System.out.println("HEAD : " + myTree.head.value);
System.out.println("HEAD RIGHT : " + myTree.head.right.value);
System.out.println("HEAD RIGHT RIGHT : " + myTree.head.right.right.value);
System.out.println("HEAD RIGHT RIGHT RIGHT : " + myTree.head.right.right.right.value);
}
}
package tree;
public class NodeMgmt {
Node head = null;
public class Node{
Node left;
Node right;
int value;
public Node(int data){
this.value = data;
this.left = null;
this.right = null;
}
}
public boolean insertNode(int data){
//1. Node가 하나도 없을 때
if (this.head == null){
this.head = new Node(data);
} else { //2. Node가 하나 이상 들어가 있을 때
Node findNode = this.head;
while(true){
//2-1. 현재 Node의 왼쪽에 Node가 들어가야 할떄
if (data < findNode.value){
if (findNode.left != null){
findNode = findNode.left;
} else {
findNode.left = new Node(data);
break;
}
} else { //2-2. 현재 Node의 오른쪽에 Node가 들어가야 할떄
if (findNode.right != null){
findNode = findNode.right;
} else {
findNode.right = new Node(data);
break;
}
}
}
}
return false;
}
}
TreeSet
- 이진 트리를 기반으로 한 Set 컬렌션.
- 여러 개의 노드가 트리 형태로 연결된 구조. 루트 노드에서 시작해 각 노드에 최대 2개의 노드를 연결할 수 있음.
- TreeSet에 객체를 저장하면 부모 노드의 객체와 비교해서 낮은 것은 왼쪽 자식 노드에, 높은 것은 오른쪽 자식 노드에 저장.
package tree.treeSet;
import java.util.NavigableSet;
import java.util.TreeSet;
public class TreeSetEx {
public static void main(String[] args) {
//랜덤한 학생 점수를 TreeSet 구조에 저장 관리 해보자
TreeSet<Integer> scores = new TreeSet<>();
//학생 점수를 저장함과 동시에 정렬 완성
scores.add(88);
scores.add(98);
scores.add(75);
scores.add(95);
scores.add(80);
scores.add(60);
//정렬된 점수를 하나씩 가져오기
for (Integer score : scores){
System.out.print(score + " ");
}
System.out.println();
//특정 점수를 가져오기
System.out.println("최저 점수 : " + scores.first());
System.out.println("최고 점수 : " + scores.last());
System.out.println("95점 아래 점수 : " + scores.lower(95));
System.out.println("95점 위에 점수 : " + scores.higher(95));
System.out.println("95점 이거나 바로 아래 점수" + scores.floor(95));
System.out.println("85점 이거나 바로 아래 점수" + scores.ceiling(85));
System.out.println("================================");
//내림차순 정렬
NavigableSet<Integer> descScores = scores.descendingSet();
for (Integer score : descScores){
System.out.print(score + " ");
}
System.out.println();
//범위 검색 가능함
NavigableSet<Integer> rangeScores = scores.tailSet(80, true);
for (Integer score : rangeScores){
System.out.print(score + " ");
}
System.out.println();
//구간 검색 가능함
NavigableSet<Integer> subScores = scores.subSet(80, true, 95, false);
for (Integer score : subScores){
System.out.print(score + " ");
}
System.out.println();
}
}
TreeMap
- 이진 트리를 기반으로 한 Map 컬렌션.
- 키와 값이 저장된 엔트리 저장.
- 부모 키 값과 비교해서 낮은 것은 왼쪽, 높은 것은 오른쪽 자식 노드에 Entry 객체를 저장.
package tree.treeMap;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapEx {
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<>();
// 엔트리 저장
treeMap.put("권땡땡",90);
treeMap.put("서땡떙",80);
treeMap.put("김땡땡",95);
treeMap.put("고땡땡",70);
treeMap.put("이땡땡",83);
treeMap.put("이땡떙",93);
//정렬된 엔트리 하나씩 가져오기
Set<Entry<String, Integer>> entrySet = treeMap.entrySet();
for (Entry<String, Integer> student : entrySet){
System.out.println(student.getKey() + "---" + student.getValue());
}
//특정 키 검색하여 값 가져오기
Entry<String, Integer> entry = null;
entry = treeMap.firstEntry();
System.out.println(entry.getKey() + "---" + entry.getValue());
entry = treeMap.lastEntry();
System.out.println(entry.getKey() + "---" + entry.getValue());
entry = treeMap.lowerEntry("이지은");
System.out.println(entry.getKey() + "---" + entry.getValue());
//내림차순 정렬
NavigableMap<String, Integer> descStudents = treeMap.descendingMap();
Set<Entry<String, Integer>> descScoresSet = descStudents.entrySet();
for (Entry<String, Integer> student : descScoresSet){
System.out.print(student.getKey() + "---" + student.getValue());
}
System.out.println();
//범위 검색 가능함
NavigableMap<String, Integer> subStudent = treeMap.subMap("김", true, "이", false);
for (Entry<String, Integer> subMap : subStudent.entrySet()){
System.out.print(subMap.getKey() + "---" + subMap.getValue());
}
System.out.println();
}
}
Comparable과 Comparator
- TreeSet에 저장되는 객체와 TreeMap에 저장되는 키 객체를 정렬.
- Comparable 인터페이스에는 compareTo() 메서드가 정의. 사용자 정의 클래스에서 이 메서드를 재정의해서 비교 결과를 정수값으로 리턴.
- 비교 기능이 없는 Comparable 비구현 객체를 저장하려면 비교자 Comparator를 제공.
- 비교자는 compare() 메서드를 재정의해서 비교 결과를 정수 값으로 리턴.
https://github.com/bottomsUp-99?tab=repositories
728x90
반응형
'자료구조' 카테고리의 다른 글
스트림(Stream) 요소 처리 (0) | 2024.07.17 |
---|---|
자바 스트림(Stream)이란? (0) | 2024.07.03 |
Comparable VS Comparator 의 이해 (0) | 2024.06.30 |
ConcurrentHashMap VS ConcurrentSkipListMap 이란? (0) | 2024.06.19 |
AuthProvider VS Provider 이란? (0) | 2024.06.19 |