[자바] java 자료구조
20210321
01. 여러가지 자료구조에 대해 알아봅시다.
자료구조란 무엇인가? (Data Structure)
프로그램에서 사용할 많은 데이타를 메모리 상에서 관리하는 여러 구현방법들
효율적인 자료구조가 성능 좋은 알고리즘의 기반이 됨
자료의 효율적인 관리는 프로그램의 수행속도와 밀접한 관련이 있음
여러 자료 구조 중에서 구현하려는 프로그램에 맞는 최적의 자료구조를 활용해야 하므로 자료구조에 대한 이해가 중요함
자료구조에는 어떤 것들이 있나?
- 한 줄로 자료를 관리하기 (선형 자료구조)
배열 (Array) : 선형으로 자료를 관리, 정해진 크기의 메모리를 먼저 할당받아 사용하고, 자료의 물리적 위치와 논리적 위치가 같음
연결 리스트 (LinkedList) : 선형으로 자료를 관리, 자료가 추가될 때마다 메모리를 할당 받고, 자료는 링크로 연결됨. 자료의 물리적 위치와 논리적 위치가 다를 수 있음
리스트에 자료 추가하기
리스트에서 자료 삭제하기
스택 (Stack) : 가장 나중에 입력 된 자료가 가장 먼저 출력되는 자료 구조 (Last In First OUt)
큐 (Queue) : 가장 먼저 입력 된 자료가 가장 먼저 출력되는 자료 구조 (First In First Out)
- 트리 (Tree) : 부모 노드와 자식 노드간의 연결로 이루어진 자료 구조
힙(heap) : Priority queue를 구현 (우선 큐) -> 우선순위 큐는 우선순위가 높은 순으로 꺼내므로 힙을 이용해서 구현한다. (최대힙이 부모노드가 자식노드보다 항상 크기떄문 반대인 최소힙으로도 가능.)
Max heap : 부모 노드는 자식 노드보다 항상 크거나 같은 값을 갖는 경우
Min heap : 부모 노드는 자식 노드보다 항상 작거나 같은 값을 갖는 경우
heap정렬에 활용 할 수 있음
이진 트리 (binary tree) : 부모노드에 자식노드가 두 개 이하인 트리
이진 검색 트리 (binary search tree)
자료(key)의 중복을 허용하지 않음
왼쪽 자식 노드는 부모 노드보다 작은 값, 오른쪽 자식 노드는 부모 노드보다 큰 값을 가짐
자료를 검색에 걸리는 시간이 평균 log(n) 임
inorder traversal 탐색을 하게 되면 자료가 정렬되어 출력됨
예) [23, 10, 28, 15, 7, 22, 56] 순으로 자료를 넣을때 BST
나중에 tresset이나 treemap 할떄 compaable인터페이스 구현해서 비교하게끔 구현할 거.
jdk 클래스 : TreeSet, TreeMap (Tree로 시작되는 클래스는 정렬을 지원 함)
- 그래프 (Graph) : 정점과 간선들의 유한 집합 G = (V,E)
-> 네비게이션, 구글맵 이런게 다 그래프에 기반해서 구현.
정점(vertex) : 여러 특성을 가지는 객체, 노드(node)
간선(edge) : 이 객체들을 연결 관계를 나타냄. 링크(link)
간선은 방향성이 있는 경우와 없는 경우가 있음(노드와 노드 연결하는걸 edge나 link라고 한다.)
그래프를 구현하는 방법 : 인접 행렬(adjacency matrix), 인접 리스트(adjacency list)
그래프를 탐색하는 방법 : BFS(bread first search), DFS(depth first search)
그래프의 예)
해싱 (Hashing) : 자료를 검색하기 위한 자료 구조
검색을 위한 자료 구조
키(key)에 대한 자료를 검색하기 위한 사전(dictionary) 개념의 자료 구조
key는 유일하고 이에 대한 value를 쌍으로 저장
index = h(key) : 해시 함수가 key에 대한 인덱스를 반환해줌 해당 인덱스 위치에 자료를 저장하거나 검색하게 됨
해시 함수에 의해 인덱스 연산이 산술적으로 가능 O(1)
저장되는 메모리 구조를 해시테이블이라 함
jdk 클래스 : HashMap, Properties
키는 중복 되지 않음. 나머지를 구하는게 해시함수(123%100해서 23번쨰 자리에 저장) 해시테이블
체이닝
해시는 키에대한 밸류가 있다.
키는 유해서 키는 중복될 수 없다. 키만 알면 밸류를 꺼낼 수 없다. 해시는 들어가는 순서와 상관이 없다. 배열과 비슷하게 생겨서 많이 오해. 해시펑션에 의해 정해져서 순서랑은 무관하다.
02. 배열(Array) 구현하기
Array의 특징
동일한 데이터 타입을 순서에 따라 관리하는 자료 구조
정해진 크기가 있음
요소의 추가와 제거시 다른 요소들의 이동이 필요함
배열의 i 번째 요소를 찾는 인덱스 연산이 빠름
jdk 클래스 : ArrayList, Vector
Array 구현하기
MyArray.java
public class MyArray {
int[] intArr; //int array
int count; //개수
public int ARRAY_SIZE;
public static final int ERROR_NUM = -999999999;
public MyArray()
{
count = 0;
ARRAY_SIZE = 10;
intArr = new int[ARRAY_SIZE];
}
public MyArray(int size)
{
count = 0;
ARRAY_SIZE = size;
intArr = new int[size];
}
public void addElement(int num)
{
if(count >= ARRAY_SIZE){
System.out.println("not enough memory");
return;
}
intArr[count++] = num;
}
public void insertElement(int position, int num)
{
int i;
if(count >= ARRAY_SIZE){ //꽉 찬 경우
System.out.println("not enough memory");
return;
}
if(position < 0 || position > count ){ //index error
System.out.println("insert Error");
return;
}
for( i = count-1; i >= position ; i--){
intArr[i+1] = intArr[i]; // 하나씩 이동
}
intArr[position] = num;
count++;
}
public int removeElement(int position)
{
int ret = ERROR_NUM;
if( isEmpty() ){
System.out.println("There is no element");
return ret;
}
if(position < 0 || position >= count ){ //index error
System.out.println("remove Error");
return ret;
}
ret = intArr[position];
for(int i = position; i<count -1; i++ )
{
intArr[i] = intArr[i+1];
}
count--;
return ret;
}
public int getSize()
{
return count;
}
public boolean isEmpty()
{
if(count == 0){
return true;
}
else return false;
}
public int getElement(int position)
{
if(position < 0 || position > count-1){
System.out.println("검색 위치 오류. 현재 리스트의 개수는 " + count +"개 입니다.");
return ERROR_NUM;
}
return intArr[position];
}
public void printAll()
{
if(count == 0){
System.out.println("출력할 내용이 없습니다.");
return;
}
for(int i=0; i<count; i++){
System.out.println(intArr[i]);
}
}
public void removeAll()
{
for(int i=0; i<count; i++){
intArr[i] = 0;
}
count = 0;
}
}
MyArrayTest.java
public class MyArrayTest {
public static void main(String[] args) {
MyArray array = new MyArray();
array.addElement(10);
array.addElement(20);
array.addElement(30);
array.insertElement(1, 50);
array.printAll();
System.out.println("===============");
array.removeElement(1);
array.printAll();
System.out.println("===============");
array.addElement(70);
array.printAll();
System.out.println("===============");
array.removeElement(1);
array.printAll();
System.out.println("===============");
System.out.println(array.getElement(2));
}
}
MyObjectArray.java
public class MyObjectArray {
private int cout;
private Object[] array;
public int ARRAY_SIZE;
public MyObjectArray()
{
ARRAY_SIZE = 10;
array = new Object[ARRAY_SIZE];
}
public MyObjectArray(int size)
{
ARRAY_SIZE = size;
array = new Object[ARRAY_SIZE];
}
}
02. 연결 리스트 (LinkedList) 구현하기
LinkedList 특징
동일한 데이터 타입을 순서에 따라 관리하는 자료 구조
자료를 저장하는 노드에는 자료와 다음 요소를 가리키는 링크(포인터)가 있음
자료가 추가 될때 노드 만큼의 메모리를 할당 받고 이전 노드의 링크로 연결함 (정해진 크기가 없음)
연결 리스트의 i 번째 요소를 찾는게 걸리는 시간은 요소의 개수에 비례 : O(n)
jdk 클래스 : LinkedList
LinkedList 구현하기
MyListNode.java
public class MyListNode {
private String data; // 자료
public MyListNode next; // 다음 노드를 가리키는 링크
public MyListNode(){
data = null;
next = null;
}
public MyListNode(String data){
this.data = data;
this.next = null;
}
public MyListNode(String data, MyListNode link){
this.data = data;
this.next = link;
}
public String getData(){
return data;
}
}
MyLinkedList.java
public class MyLinkedList {
private MyListNode head;
int count;
public MyLinkedList()
{
head = null;
count = 0;
}
public MyListNode addElement( String data )
{
MyListNode newNode;
if(head == null){ //맨 처음일때
newNode = new MyListNode(data);
head = newNode;
}
else{
newNode = new MyListNode(data);
MyListNode temp = head;
while(temp.next != null) //맨 뒤로 가서
temp = temp.next;
temp.next = newNode;
}
count++;
return newNode;
}
public MyListNode insertElement(int position, String data )
{
int i;
MyListNode tempNode = head;
MyListNode newNode = new MyListNode(data);
if(position < 0 || position > count ){
System.out.println("추가 할 위치 오류 입니다. 현재 리스트의 개수는 " + count +"개 입니다.");
return null;
}
if(position == 0){ //맨 앞으로 들어가는 경우
newNode.next = head;
head = newNode;
}
else{
MyListNode preNode = null;
for(i=0; i<position; i++){
preNode = tempNode;
tempNode = tempNode.next;
}
newNode.next = preNode.next;
preNode.next = newNode;
}
count++;
return newNode;
}
public MyListNode removeElement(int position)
{
int i;
MyListNode tempNode = head;
if(position >= count ){
System.out.println("삭제 할 위치 오류입니다. 현재 리스트의 개수는 " + count +"개 입니다.");
return null;
}
if(position == 0){ //맨 앞을 삭제하는
head = tempNode.next;
}
else{
MyListNode preNode = null;
for(i=0; i<position; i++){
preNode = tempNode;
tempNode = tempNode.next;
}
preNode.next = tempNode.next;
}
count--;
System.out.println(position + "번째 항목 삭제되었습니다.");
return tempNode;
}
public String getElement(int position)
{
int i;
MyListNode tempNode = head;
if(position >= count ){
System.out.println("검색 위치 오류 입니다. 현재 리스트의 개수는 " + count +"개 입니다.");
return new String("error");
}
if(position == 0){ //맨 인 경우
return head.getData();
}
for(i=0; i<position; i++){
tempNode = tempNode.next;
}
return tempNode.getData();
}
public MyListNode getNode(int position)
{
int i;
MyListNode tempNode = head;
if(position >= count ){
System.out.println("검색 위치 오류 입니다. 현재 리스트의 개수는 " + count +"개 입니다.");
return null;
}
if(position == 0){ //맨 인 경우
return head;
}
for(i=0; i<position; i++){
tempNode = tempNode.next;
}
return tempNode;
}
public void removeAll()
{
head = null;
count = 0;
}
public int getSize()
{
return count;
}
public void printAll()
{
if(count == 0){
System.out.println("출력할 내용이 없습니다.");
return;
}
MyListNode temp = head;
while(temp != null){
System.out.print(temp.getData());
temp = temp.next;
if(temp!=null){
System.out.print("->");
}
}
System.out.println("");
}
public boolean isEmpty()
{
if(head == null) return true;
else return false;
}
}
MyLinkedListTest.java
public class MyLinkedListTest {
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
list.addElement("A");
list.addElement("B");
list.addElement("C");
list.printAll();
list.insertElement(3, "D");
list.printAll();
list.removeElement(0);
list.printAll();
list.removeElement(1);
list.printAll();
list.insertElement(0, "A-1");
list.printAll();
System.out.println(list.getSize());
list.removeElement(0);
list.printAll();
System.out.println(list.getSize());
list.removeAll();
list.printAll();
list.addElement("A");
list.printAll();
System.out.println(list.getElement(0));
list.removeElement(0);
}
}
03. 스택(Stack) 구현하기
Stack의 특징
맨 마지막 위치(top)에서만 자료를 추가,삭제, 꺼내올 수 있음 ( 중간의 자료를 꺼낼 수 없음)
Last In First Out ( 후입선출 ) 구조
택배 상자가 쌓여있는 모양
가장 최근의 자료를 찾아오거나 게임에서 히스토리를 유지하고 이를 무를때 사용할 수 있음
함수의 메모리는 호출 순서에 따른 stack 구조
jdk 클래스 : Stack
배열을 활용하여 Stack 구현하기
MyArrayStack.java
import array.MyArray;
public class MyArrayStack {
int top;
MyArray arrayStack;
public MyArrayStack()
{
top = 0;
arrayStack = new MyArray();
}
public MyArrayStack(int size)
{
arrayStack = new MyArray(size);
}
public void push(int data)
{
if(isFull()){
System.out.println("stack is full");
return;
}
arrayStack.addElement(data);
top++;
}
public int pop()
{
if (top == 0){
System.out.println("stack is empty");
return MyArray.ERROR_NUM;
}
return arrayStack.removeElement(--top);
}
public int peek()
{
if (top == 0){
System.out.println("stack is empty");
return MyArray.ERROR_NUM;
}
return arrayStack.getElement(top-1);
}
public int getSize()
{
return top;
}
public boolean isFull()
{
if(top == arrayStack.ARRAY_SIZE){
return true;
}
else return false;
}
public boolean isEmpty()
{
if (top == 0){
return true;
}
else return false;
}
public void printAll()
{
arrayStack.printAll();
}
}
MyArrayStackTest.java
public class MyArrayStackTest {
public static void main(String[] args) {
MyArrayStack stack = new MyArrayStack(3);
stack.push(10);
stack.push(20);
stack.push(30);
stack.push(40);
stack.printAll();
System.out.println("top element is " + stack.pop());
stack.printAll();
System.out.println("stack size is " + stack.getSize());
}
}
04. 큐(Queue) 구현하기
Queue의 특징
맨 앞(front) 에서 자료를 꺼내거나 삭제하고, 맨 뒤(rear)에서 자료를 추가 함
Fist In First Out (선입선출) 구조
일상 생활에서 일렬로 줄 서 있는 모양
순차적으로 입력된 자료를 순서대로 처리하는데 많이 사용 되는 자료구조
콜센터에 들어온 문의 전화, 메세지 큐 등에 활용됨
jdk 클래스 : ArrayList
연결 리스트를 활용하여 Queue 구헌하기
MyListQueue.java
import linkedlist.MyListNode;
import linkedlist.MyLinkedList;
interface IQueue{
public void enQueue(String data);
public String deQueue();
public void printAll();
}
public class MyListQueue extends MyLinkedList implements IQueue{
MyListNode front;
MyListNode rear;
public MyListQueue()
{
front = null;
rear = null;
}
public void enQueue(String data)
{
MyListNode newNode;
if(isEmpty()) //처음 항목
{
newNode = addElement(data);
front = newNode;
rear = newNode;
}
else
{
newNode = addElement(data);
rear = newNode;
}
System.out.println(newNode.getData() + " added");
}
public String deQueue()
{
if(isEmpty()){
System.out.println("Queue is Empty");
return null;
}
String data = front.getData();
front = front.next;
if( front == null ){ // 마지막 항목
rear = null;
}
return data;
}
public void printAll()
{
if(isEmpty()){
System.out.println("Queue is Empty");
return;
}
MyListNode temp = front;
while(temp!= null){
System.out.print(temp.getData() + ",");
temp = temp.next;
}
System.out.println();
}
}
MyListQueueTest.java
public class MyListQueueTest {
public static void main(String[] args) {
MyListQueue listQueue = new MyListQueue();
listQueue.enQueue("A");
listQueue.enQueue("B");
listQueue.enQueue("C");
listQueue.enQueue("D");
listQueue.enQueue("E");
System.out.println(listQueue.deQueue());
listQueue.printAll();
}
}
06. 무엇이든 담을 수 있는 제네릭(Generic) 프로그래밍
제네릭 자료형 정의
- 클래스에서 사용하는 변수의 자료형이 여러개 일수 있고, 그 기능(메서드)은 동일한 경우 클래스의 자료형을 특정하지 않고
추후 해당 클래스를 사용할 때 지정 할 수 있도록 선언
실제 사용되는 자료형의 변환은 컴파일러에 의해 검증되므로 안정적인 프로그래밍 방식
컬렉션 프레임워크에서 많이 사용되고 있음
제네릭 타입을 사용하지 않는 경우의 예
재료가 Powder인 경우
public class ThreeDPrinter1{
private Powder material;
public void setMaterial(Powder material) {
this.material = material;
}
public Powder getMaterial() {
return material;
}
}
재료가 Plastic인 경우
public class ThreeDPrinter2{
private Plastic material;
public void setMaterial(Plastic material) {
this.material = material;
}
public Plastic getMaterial() {
return material;
}
}
- 여러 타입을 대체하기 위해 Object를 사용할 수 있음
public class ThreeDPrinter{ private Object material; public void setMaterial(Object material) { this.material = material; } public Object getMaterial() { return material; } }
- Object를 사용하는 경우는 형 변환을 하여야 함 ``` ThreeDPrinter printer = new ThreeDPrinter();
Powder powder = new Powder(); printer.setMaterial(powder);
Powder p = (Powder)printer.getMaterial();
- 제네릭 클래스 정의
GenericPrinter.java
public class GenericPrinter
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
public String toString(){
return material.toString();
} } ``` - 자료형 매개변수 T(type parameter) : 이 클래스를 사용하는 시점에 실제 사용할 자료형을 지정, static 변수는 사용할 수 없음
GenericPrinter
: 제네릭 자료형 E : element, K: key, V : value 등 여러 알파벳을 의미에 따라 사용 가능
제네릭 클래스 사용하기
Powder.java
public class Powder {
public String toString() {
return "재료는 Powder 입니다";
}
}
Plastic.java
public class Plastic {
public String toString() {
return "재료는 Plastic 입니다";
}
}
GenericPrinter.java
public class GenericPrinter<T> {
private T material; //T 자료형으로 선언한 변수
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() { //T 자료형을 반환하는 제네릭 메서드
return material;
}
public String toString(){
return material.toString();
}
}
GenericPrinterTest.java
public class GeneriPrinterTest {
public static void main(String[] args) {
GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();
powderPrinter.setMaterial(new Powder());
System.out.println(powderPrinter);
GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<Plastic>();
plasticPrinter.setMaterial(new Plastic());
System.out.println(plasticPrinter);
}
}
다이아몬드 연산자 <>
-
에서 <>를 다이아몬드 연산자라 함 ArrayList
list = new ArrayList<>(); //다이아몬든 연산자 내부에서 자료형은 생략가능 함 제네릭에서 자료형 추론(자바 10부터)
ArrayList
list = new ArrayList () => var list = new ArrayList ();
07. 사용하기
상위 클래스의 필요성
T 자료형의 범위를 제한 할 수 있음
상위 클래스에서 선언하거나 정의하는 메서드를 활용할 수 있음
상속을 받지 않는 경우 T는 Object로 변환되어 Object 클래스가 기본으로 제공하는 메서드만 사용가능
T extends 를 사용한 프로그래밍
GenericPrinter
에 material 변수의 자료형을 상속받아 구현 T에 무작위 클래스가 들어갈 수 없게 Material 클래스를 상속받은 클래스로 한정
Material.java
public abstract class Material {
public abstract void doPrinting();
}
Powder.java
public class Powder extends Material{
public void doPrinting() {
System.out.println("Powder 재료로 출력합니다");
}
public String toString() {
return "재료는 Powder 입니다";
}
}
Plastic.java
public class Plastic extends Material{
public void doPrinting() {
System.out.println("Plastic 재료로 출력합니다");
}
public String toString() {
return "재료는 Plastic 입니다";
}
}
GenericPrinter.java
public class GenericPrinter<T extends Material> {
private T material;
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
public String toString(){
return material.toString();
}
public void printing() {
material.doPrinting();
}
}
GenericPrinterTest.java
public class GenericPrinterTest {
public static void main(String[] args) {
GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();
powderPrinter.setMaterial(new Powder());
Powder powder = powderPrinter.getMaterial(); // 형변환 하지 않음
System.out.println(powderPrinter);
GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<Plastic>();
plasticPrinter.setMaterial(new Plastic());
Plastic plastic = plasticPrinter.getMaterial(); // 형변환 하지 않음
System.out.println(plasticPrinter);
/* GenericPrinter powderPrinter2 = new GenericPrinter();
powderPrinter2.setMaterial(new Powder());
Powder powder = (Powder)powderPrinter.getMaterial();
System.out.println(powderPrinter);
*/
//GenericPrinter<Water> printer = new GenericPrinter<Water>();
}
}
08. 제네릭 메서드 활용하기
제네릭 메서드란?
자료형 매개변수를 메서드의 매개변수나 반환 값으로 가지는 메서드는
자료형 매개 변수가 하나 이상인 경우도 있음
제네릭 클래스가 아니어도 내부에 제네릭 메서드는 구현하여 사용 할 수 있음
public <자료형 매개="" 변수=""> 반환형 메서드 이름(자료형 매개변수.....) { }자료형>
제네릭 메서드의 활용 예
두 점(top, bottom)을 기준으로 사각형을 만들 때 사각형의 너비를 구하는 메서드를 만들어 보자
두 점은 정수인 경우도 있고, 실수인 경우도 있으므로 제네릭 타입을 사용하여 구현한다.
Point.java
public class Point<T, V> {
T x;
V y;
Point(T x, V y){
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public V getY() {
return y;
}
}
GenericMethod.java
public class GenericMethod {
public static <T, V> double makeRectangle(Point<T, V> p1, Point<T, V> p2) {
double left = ((Number)p1.getX()).doubleValue();
double right =((Number)p2.getX()).doubleValue();
double top = ((Number)p1.getY()).doubleValue();
double bottom = ((Number)p2.getY()).doubleValue();
double width = right - left;
double height = bottom - top;
return width * height;
}
public static void main(String[] args) {
Point<Integer, Double> p1 = new Point<Integer, Double>(0, 0.0);
Point<Integer, Double> p2 = new Point<>(10, 10.0);
double rect = GenericMethod.<Integer, Double>makeRectangle(p1, p2);
System.out.println("두 점으로 만들어진 사각형의 넓이는 " + rect + "입니다.");
}
}
09. 자바에서 제공되는 자료구조 구현 클래스들 - 컬레션 프레임워크
컬렉션 프레임워크
프로그램 구현에 필요한 자료구조(Data Structure)를 구현해 놓은 JDK 라이브러리
java.util 패키지에 구현되어 있음
개발에 소요되는 시간을 절약하면서 최적화 된 알고리즘을 사용할 수 있음
여러 구현 클래스와 인터페이스의 활용에 대한 이해가 필요함
Collection 인터페이스
하나의 객체를 관리하기 위한 메서드가 선언된 인터페이스의
하위에 List와 Set 인터페이스가 있음
List 인터페이스
객체를 순서에 따라 저장하고 관리하는데 필요한 메서드가 선언된 인터페이스
자료구조 리스트 (배열, 연결리스트)의 구현을 위한 인터페이스
중복을 허용함
ArrayList, Vector, LinkedList, Stack, Queue 등…
Set 인터페이스
순서와 관계없이 중복을 허용하지 않고 유일한 값을 관리하는데 필요한 메서드가 선언됨
아이디, 주민번호, 사번등을 관리하는데 유용
저장된 순서와 출력되는 순서는 다를 수 있음
HashSet, TreeSet등…
Map 인터페이스
쌍(pair)로 이루어진 객체를 관리하는데 사용하는 메서드들이 선언된 인터페이스
객체는 key-value의 쌍으로 이루어짐
key는 중복을 허용하지 않음
HashTable, HashMap, Properties, TreeMap 등이 Map 인터페이스를 구현 함
10. 순차적으로 자료를 관리하는 List 인터페이스를 구현한 클래스와 그 활용
멤버십 관리하기
Member 클래스를 만들고, 아이디와 이름을 멤버 변수로 선언
Member 클래스로 생성된 인스턴스들을 관리하는 클래스를 컬렉션 프레임워크 클래스들을 활용하여 구현한다.
ArrayList 활용하기
- 멤버를 순차적으로 관리함
Member.java
public class Member {
private int memberId; //회원 아이디
private String memberName; //회원 이름
public Member(int memberId, String memberName){ //생성자
this.memberId = memberId;
this.memberName = memberName;
}
public int getMemberId() { //
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
@Override
public String toString(){ //toString 메소드 오버로딩
return memberName + " 회원님의 아이디는 " + memberId + "입니다";
}
}
MemberArrayList.java
public class MemberArrayList {
private ArrayList<Member> arrayList; // ArrayList 선언
public MemberArrayList(){
arrayList = new ArrayList<Member>(); //멤버로 선언한 ArrayList 생성
}
public void addMember(Member member){ //ArrayList 에 멤버 추가
arrayList.add(member);
}
public boolean removeMember(int memberId){ // 멤버 아이디를 매개변수로, 삭제 여부를 반환
for(int i =0; i<arrayList.size(); i++){ // 해당 아이디를 가진 멤버를 ArrayList에서 찾음
Member member = arrayList.get(i);
int tempId = member.getMemberId();
if(tempId == memberId){ // 멤버아이디가 매개변수와 일치하면
arrayList.remove(i); // 해당 멤버를 삭제
return true; // true 반환
}
}
System.out.println(memberId + "가 존재하지 않습니다"); //for 가 끝날때 까지 return 이 안된경우
return false;
}
public void showAllMember(){
for(Member member : arrayList){
System.out.println(member);
}
System.out.println();
}
}
MemberArrayListTest.java
public class MemberArrayListTest {
public static void main(String[] args) {
MemberArrayList memberArrayList = new MemberArrayList();
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
Member memberHong = new Member(1004, "홍길동");
memberArrayList.addMember(memberLee);
memberArrayList.addMember(memberKim);
memberArrayList.addMember(memberKang);
memberArrayList.addMember(memberHong);
memberArrayList.showAllMember();
memberArrayList.removeMember(memberHong.getMemberId());
memberArrayList.showAllMember();
}
}
11. Collection 요소를 순회하는 Iterator
요소의 순회란?
컬렉션 프레임워크에 저장된 요소들을 하나씩 차례로 참조하는것
순서가 있는 List인터페이스의 경우는 Iterator를 사용 하지 않고 get(i) 메서드를 활용할 수 있음
Set 인터페이스의 경우 get(i) 메서드가 제공되지 않으므로 Iterator를 활용하여 객체를 순회함
Iterator 사용하기
boolean hasNext() : 이후에 요소가 더 있는지를 체크하는 메서드, 요소가 있다면 true를 반환
E next() : 다음에 있는 요소를 반환
MemberArrayList.java 의 removeMember() 메서드를 Iterator를 활용하여 구현
public boolean removeMember(int memberId){ // 멤버 아이디를 매개변수로, 삭제 여부를 반환
Iterator<Member> ir = arrayList.iterator();
while(ir.hasNext()) {
Member member = ir.next();
int tempId = member.getMemberId();
if(tempId == memberId){ // 멤버아이디가 매개변수와 일치하면
arrayList.remove(member); // 해당 멤버를 삭제
return true; // true 반환
}
}
System.out.println(memberId + "가 존재하지 않습니다"); //for 가 끝날때 까지 return 이 안된경우
return false;
}
12. 중복되지 않게 자료를 관리하는 Set 인터페이스를 구현한 클래스와 그 활용
HashSet 클래스
Set 인터페이스를 구현한 클래스와
멤버의 중복 여부를 체크하기 위해 인스턴스의 동일성을 확인해야 함
동일성 구현을 위해 필요에 따라 equals()와 hashCode()메서드를 재정의함
HashSetTest.java
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add(new String("김유신"));
hashSet.add(new String("이순신"));
hashSet.add(new String("홍연의"));
hashSet.add(new String("강감찬"));
hashSet.add(new String("강감찬"));
System.out.println(hashSet);
}
}
MemberHashSet.java
public class MemberHashSet {
private HashSet<Member> hashSet;
public MemberHashSet(){
hashSet = new HashSet<Member>();
}
public void addMember(Member member){
hashSet.add(member);
}
public boolean removeMember(int memberId){
Iterator<Member> ir = hashSet.iterator();
while( ir.hasNext()){
Member member = ir.next();
int tempId = member.getMemberId();
if( tempId == memberId){
hashSet.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다");
return false;
}
public void showAllMember(){
for(Member member : hashSet){
System.out.println(member);
}
System.out.println();
}
}
MemberHashSetTest.java
public class MemberHashSetTest {
public static void main(String[] args) {
MemberHashSet memberHashSet = new MemberHashSet();
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
memberHashSet.addMember(memberLee);
memberHashSet.addMember(memberKim);
memberHashSet.addMember(memberKang);
memberHashSet.showAllMember();
Member memberHong = new Member(1003, "홍길동"); //1003 아이디 중복
memberHashSet.addMember(memberHong);
memberHashSet.showAllMember();
}
}
- 아이디가 동일한 경우 같은 멤버이므로 중복되지 않도록 Member 클래스의 equals()와 hashCode()메서드를 재정의함
Member.java
...
@Override
public int hashCode() {
return memberId;
}
@Override
public boolean equals(Object obj) {
if( obj instanceof Member){
Member member = (Member)obj;
if( this.memberId == member.memberId )
return true;
else
return false;
}
return false;
}
...
13. 정렬을 위해 Comparable과 Comparator 인터페이스 구현하기
TreeSet 클래스 활용하기
객체의 정렬에 사용하는 클래스
Set 인터페이스를 구현하여 중복을 허용하지 않고, 오름차순이나 내림차순으로 객체를 정렬할 수 있음
내부적으로 이진검색트리(binary search tree)로 구현됨
이진검색트리에 저장하기 위해 각 객체를 비교해야 함
비교 대상이 되는 객체에 Comparable이나 Comparator 인터페이스를 구현 해야 TreeSet에 추가 될 수 있음
String, Integer등 JDK의 많은 클래스들이 이미 Comparable을 구현했음
TreeSetTest.java
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<String>();
treeSet.add("홍길동");
treeSet.add("강감찬");
treeSet.add("이순신");
for(String str : treeSet) {
System.out.println(str);
}
}
}
String 클래스는 이미 Comprable 인터페이스가 구현되어 있으므로 오름차순으로 정렬되어 출력됨
MemberTreeSet.java
public class MemberTreeSet {
private TreeSet<Member> treeSet;
public MemberTreeSet(){
treeSet = new TreeSet<Member>();
}
public void addMember(Member member){
treeSet.add(member);
}
public boolean removeMember(int memberId){
Iterator<Member> ir = treeSet.iterator();
while( ir.hasNext()){
Member member = ir.next();
int tempId = member.getMemberId();
if( tempId == memberId){
treeSet.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다");
return false;
}
public void showAllMember(){
for(Member member : treeSet){
System.out.println(member);
}
System.out.println();
}
}
MemberTreeSetTest.java
public class MemberTreeSetTest {
public static void main(String[] args) {
MemberTreeSet memberTreeSet = new MemberTreeSet();
Member memberKim = new Member(1003, "김유신");
Member memberLee = new Member(1001, "이순신");
Member memberKang = new Member(1002, "강감찬");
memberTreeSet.addMember(memberKim);
memberTreeSet.addMember(memberLee);
memberTreeSet.addMember(memberKang);
memberTreeSet.showAllMember();
}
}
- Member클래스가 아이디 오름차순으로 정렬되게 하기 위해 Comparable 인터페이스를 구현
Member.java
public class Member implements Comparable<Member>{
......
@Override
public int compareTo(Member member) {
//return (this.memberId - member.memberId); //오름차순
return (this.memberId - member.memberId) * (-1); //내림 차순
}
}
- Comparator의 활용 : 이미 Comparable이 구현된 경우 Comparator로 비교하는 방식을 다시 구현할 수 있음
class MyCompare implements Comparator<String>{
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2)) *-1 ;
}
}
public class ComparatorTest {
public static void main(String[] args) {
Set<String> set = new TreeSet<String>(new MyCompare());
set.add("aaa");
set.add("ccc");
set.add("bbb");
System.out.println(set);
}
}
14. 쌍(pair)으로 자료를 관리하는 Map 인터페이스를 구현한 클래스와 그 활용
HashMap 클래스 활용하기
Map 인터페이스를 구현한 클래스와
가장 많이 사용되는 Map 인터페이스 기반 클래스
key - value를 쌍으로 관리하는 메서드를 구현함
검색을 위한 자료구조
key를 이용하여 값을 저정하고 key를 이용하여 값을 꺼내오는 방식 - hash 알고리즘으로 구현 됨
key가 되는 객체는 중복될 수 없고 객체의 유일성을 비교를 위한 equals()와 hashCode() 메서드를 구현해야 함
// Member.java 는 기존과 동일
MemberHashMap.java
public class MemberHashMap {
private HashMap<Integer, Member> hashMap;
public MemberHashMap()
{
hashMap = new HashMap<Integer, Member>();
}
public void addMember(Member member){
hashMap.put(member.getMemberId(), member);
}
public boolean removeMember(int memberId){
if(hashMap.containsKey(memberId)){
hashMap.remove(memberId);
return true;
}
System.out.println(memberId + "가 존재하지 않습니다");
return false;
}
public void showAllMember(){
Iterator<Integer> ir = hashMap.keySet().iterator();
while (ir.hasNext()){
int key = ir.next();
Member member = hashMap.get(key);
System.out.println(member);
}
System.out.println();
}
}
MemberHashMapTest.java
public class MemberHashMapTest {
public static void main(String[] args) {
MemberHashMap memberHashMap = new MemberHashMap();
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
Member memberHong = new Member(1004, "홍길동");
memberHashMap.addMember(memberLee);
memberHashMap.addMember(memberKim);
memberHashMap.addMember(memberKang);
memberHashMap.addMember(memberHong);
memberHashMap.showAllMember();
memberHashMap.removeMember(1004);
memberHashMap.showAllMember();
}
}
TreeMap 클래스
Map 인터페이스를 구현한 클래스이고 key에 대한 정렬을 구현할 수 있음
key가 되는 클래스에 Comparable이나 Comparator인터페이스를 구현함으로써 key-value 쌍의 자료를 key값 기준으로 정렬하여 관리 할 수 있음