Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

게으른 리스트 정리(이장안) #195

Open
lja3723 opened this issue Aug 28, 2024 · 0 comments
Open

게으른 리스트 정리(이장안) #195

lja3723 opened this issue Aug 28, 2024 · 0 comments

Comments

@lja3723
Copy link
Collaborator

lja3723 commented Aug 28, 2024

문제가 무엇인가?

게으른 리스트에 대한 개념을 다시 정리하였습니다.

왜 이런 문제를 선정하였는가?

이번 챕터 중 게으른 리스트에 대한 설명이 잘 이해가 가지 않아서, 게으른 리스트가 무엇이고 어떻게 사용하며, 어떤 효과가 있는지 다시 복습하고자 하였습니다.

자신이 생각한 답변은 무엇인가?

프로그래밍에서 게으른 계산 (Lazy Evaluation) 이란, 값이 실제로 필요할 때까지 계산을 미루는 기법을 의미합니다. 이는 자바 8의 스트림 API에서 널리 사용되며, 스트림은 데이터를 필요로 할 때만 계산이 이루어지기 때문에 효율적인 메모리 사용과 성능 향상을 도모할 수 있습니다. 이런 게으른 계산의 개념은 스트림 뿐만 아니라, 게으른 리스트 (Lazy List) 와 같은 자료구조에서도 사용됩니다.

게으른 리스트의 정의 및 동작

게으른 리스트는 리스트의 각 요소를 미리 계산하지 않고, 필요할 때마다 계산하는 리스트입니다. Supplier<T> 인터페이스를 활용하여 구현됩니다.

책에서 언급되었던 LazyList<T> 리스트의 첫 번째 요소(head)나머지 리스트(tail) 를 관리합니다. 하지만 tail은 즉시 계산되지 않고, Supplier<MyList<T>> 로 래핑되어 필요할 때만 계산됩니다.

LazyList는 게으른 특성을 가지기 때문에, 리스트의 나머지 부분을 사용할 때만 계산이 이루어집니다. 즉, 모든 리스트가 한꺼번에 메모리에 로드되지 않으며, 필요한 부분만 점진적으로 생성됩니다.

class LazyList<T> implements MyList<T> {
    
    // 리스트의 첫 번째 요소를 저장
    final T head;
    
    // 리스트의 나머지 부분을 필요할 때만 계산하기 위해 Supplier로 래핑
    final Supplier<MyList<T>> tail;

    // 생성자: LazyList를 초기화할 때 head는 즉시 저장되지만, tail은 Supplier로 래핑
    public LazyList(T head, Supplier<MyList<T>> tail) {
        this.head = head;
        this.tail = tail;
    }

    // 리스트의 첫 번째 요소를 반환
    public T head() {
        return head;
    }

    // Supplier를 통해 리스트의 나머지 부분을 반환
    // 이 부분이 LazyList의 핵심으로, tail() 메서드가 호출될 때까지
    // 실제로 리스트의 나머지 부분은 계산되지 않음
    public MyList<T> tail() {
        return tail.get(); // tail의 실제 값을 얻기 위해 Supplier의 get() 메서드를 호출
    }

    // isEmpty() 메서드는 이 리스트가 비어있는지 여부를 반환
    // LazyList는 요소가 항상 하나 이상 존재하기 때문에 false를 반환
    public boolean isEmpty() {
        return false;
    }
}

게으른 리스트 사용 예시

// 이 메서드는 주어진 정수 n부터 시작하는 무한한 LazyList<Integer>를 생성
public static LazyList<Integer> from(int n) {
    // 새로운 LazyList를 생성
    // head는 n이며, tail은 n + 1부터 시작하는 새로운 LazyList가 됨
    return new LazyList<>(n, () -> from(n + 1)); 
    // tail 부분이 Supplier로 래핑되어 있기 때문에, 실제로 필요한 경우에만 계산됨
    // 즉, from(n + 1)은 tail()이 호출될 때까지 실행되지 않음
}

이 메서드는 자연수 리스트를 생성하는 예시로, n에서 시작하여 그 다음 숫자(n+1)를 가지는 리스트를 생성합니다. LazyList의 tail 부분은 Supplier<MyList<T>>로 감싸져 있어, tail에 접근할 때만 from(n + 1)이 호출됩니다.

만약 이 리스트가 게으르지 않았다면, 모든 가능한 숫자들이 미리 계산되고 메모리에 저장되었을 것입니다. 이로 인해 메모리 소모가 매우 커지고 프로그램이 종료되지 않았을 것입니다. 그러나 게으른 리스트는 실제로 필요할 때만 다음 숫자를 계산하므로, 무한한 리스트를 다룰 수 있게 해줍니다.

결론

자바 스트림과 마찬가지로, 게으른 리스트를 사용하면 불필요한 계산을 피해 메모리 사용량을 줄이고, 무한한 데이터 시퀀스와 같은 무거운 연산을 처리할 수 있게 해줍니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant