10-1. 순회

shin·2024년 11월 24일

순회1 - 직접 구현하는 Iterable, Iterator


  • 자료 구조에서 순회는 자료 구조에 들어있는 데이터를 차례대로 접근해서 처리하는 것

  • 다양한 자료 구조가 있고, 각각의 자료 구조마다 데이터를 접근하는 방법이 모두 다름

    • 예를 들어서 배열 리스트는 indexsize까지 차례로 증가하면서 순회해야 하고, 연결 리스트는 node.next를 사용해서 node의 끝이 null일 때까지 순회해야 함
    • 이렇듯 각 자료 구조의 순회 방법이 서로 다름
  • 배열 리스트, 연결 리스트, 해시 셋, 연결 해시 셋, 트리 셋 등등 다양한 자료 구조가 있음

    • 각각의 자료 구조마다 순회하는 방법이 서로 다르기 때문에, 각 자료 구조의 순회 방법을 배워야 함
    • 그리고 순회 방법을 배우려면 자료 구조의 내부 구조도 알아야 함
  • 하지만 자료 구조를 사용하는 개발자 입장에서 보면 단순히 자료 구조에 들어있는 모든 데이터에 순서대로 접근해서 출력하거나 계산하고 싶을 뿐

    • 자료 구조의 구현과 관계 없이 모든 자료 구조를 동일한 방법으로 순회할 수 있는 일관성 있는 방법이 있다면, 자료 구조를 사용하는 개발자 입장에서 매우 편리할 것임
  • 자바는 이런 문제를 해결하기 위해 IterableIterator 인터페이스를 제공함

Iterable, Iterator

Iterable 인터페이스의 주요 메서드

public interface Iterable<T> {
 	Iterator<T> iterator();
}
  • 단순히 Iterator 반복자를 반환

Iterator 인터페이스의 주요 메서드

public interface Iterator<E> {
 	boolean hasNext();
 	E next();
}
  • hastNext() : 다음 요소가 있는지 확인하고, 다음 요소가 없으면 false를 반환

  • next() : 다음 요소를 반환하고, 내부에 있는 위치를 다음으로 이동함

  • 자료 구조에 들어있는 데이터를 처음부터 끝까지 순회하는 방법은 단순함

    • 자료 구조에 다음 요소가 있는지 물어보고 있으면 다음 요소를 꺼내는 과정을 반복하면 됨
    • 만약에 다음 요소가 없다면 종료하면 됨
    • 이렇게 하면 자료 구조에 있는 모든 데이터를 순회할 수 있음

Iterator 구현체

package collection.iterable;
 
import java.util.Iterator;
 
public class MyArrayIterator implements Iterator<Integer> {

 	private int currentIndex = -1;
 	private int[] targetArr;
    
 	public MyArrayIterator(int[] targetArr) {
 		this.targetArr = targetArr;
    }
    
    @Override
 	public boolean hasNext() {
 		return currentIndex < targetArr.length - 1;
    }
    
    @Override
 	public Integer next() {
 		return targetArr[++currentIndex];
    }
    
}
  • 생성자를 통해 반복자가 사용할 배열을 참조함
    • 여기서 참조한 배열을 순회할 것임
  • currentIndex : 현재 인덱스, next()를 호출할 때마다 하나씩 증가함
  • haseNext() : 다음 항목이 있는지 검사함
    • 배열의 끝에 다다르면 순회가 끝났으므로 false를 반환함
    • 참고로 인덱스의 길이는 0부터 시작하므로 배열의 길이에 1을 빼야 마지막 인덱스가 나옴
  • next() : 다음 항목을 반환
    • currenctIndex()를 하나 증가하고 항목을 반환
    • 인덱스는 0부터 시작하기 때문에 currentIndex는 처음에는 -1을 가짐
    • 이렇게 하면 다음 항목을 조회했을 때 0이 됨
    • 따라서 처음 next()를 호출하면 0번 인덱스를 가리킴

순회 대상 자료구조 구현

  • Iterator는 단독으로 사용할 수 없음
  • Iterator를 통해 순회의 대상이 되는 자료구조를 만들어야 함
package collection.iterable;
 
import java.util.Iterator;

public class MyArray implements Iterable<Integer> {
  	
    private int[] numbers;
    
    public MyArray(int[] numbers) {
        this.numbers = numbers;
    }
    
    @Override
    public Iterator<Integer> iterator() {
        return new MyArrayIterator(numbers);
    }
    
}
  • 배열을 가지는 매우 단순한 자료 구조
  • Iterable 인터페이스를 구현
    • 이 인터페이스는 이 자료구조에 사용할 반복자를 반환하면 됨
    • 앞서 만든 반복자인 MyArrayIterable를 반환함
    • 이때 MyArrayIterator는 생성자를 통해 MyArray의 내부 배열인 numbers를 참조함

package collection.iterable;
 
import java.util.Iterator;
 
public class MyArrayMain {
    
    public static void main(String[] args) {
        
        MyArray myArray = new MyArray(new int[]{1, 2, 3, 4});
        
        Iterator<Integer> iterator = myArray.iterator();
        
        System.out.println("iterator 사용");
        
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            System.out.println("value = " + value);
        }
        
    }
    
}

실행 결과

iterator 사용
value = 1
value = 2
value = 3
value = 4

  • MyArrayIterator 인터페이스를 구현함
    • 따라서 MyArray는 반복할 수 있다는 의미가 됨
  • Iterator 인터페이스를 구현하면 iterator() 메서드를 구현해야 함
    • 이 메서드는 Iterator 인터페이스를 구현한 반복자를 반환함
    • 여기서는 MyArrayIterator를 생성해서 반환함

  • MyArrayIterator의 인스턴스를 생성할 때 순회할 대상을 지정해야 함
    • 여기서는 MyArray의 배열을 지정함
  • MyArrayIterator 인스턴스는 내부에서 MyArray의 배열을 참조함
  • 이제 MyArrayIterator를 통해 MyArray가 가진 내부 데이터를 순회할 수 있음


강의 출처 : 김영한의 실전 자바 - 중급 2편

profile
Backend development

0개의 댓글