[java] 스택 위에 Deque를 사용해야하는 이유는 무엇입니까?

Stack사용 사례에 대한 데이터 구조 가 필요합니다 . 항목을 데이터 구조로 푸시 할 수 있어야하며 스택에서 마지막 항목 만 검색하려고합니다. 스택의 JavaDoc는 말합니다 :

보다 완벽하고 일관된 LIFO 스택 작업 세트는 Deque 인터페이스 및 해당 구현에 의해 제공되며이 클래스보다 우선적으로 사용해야합니다. 예를 들면 다음과 같습니다.

Deque<Integer> stack = new ArrayDeque<>();

이 데이터 구조를 메소드에 로컬로 사용할 것이므로 여기서 동기화 된 동작을 원하지 않습니다. 이 외에도에서 왜 선호한다 Deque이상 Stack여기에?

추신 : Deque의 javadoc는 말합니다 :

데크는 LIFO (Last-In-First-Out) 스택으로도 사용할 수 있습니다. 이 인터페이스는 레거시 스택 클래스보다 우선적으로 사용해야합니다.



답변

우선, 상속 측면에서 더 합리적입니다. 내 견해로는 Stack확장 되는 사실 Vector이 정말 이상합니다. Java 초기에는 상속이 IMO를 과도하게 사용했습니다.Properties . 또 다른 예입니다.

나에게 인용 한 문서에서 중요한 단어는 일관성이있다 . Deque컬렉션의 시작 또는 끝에서 항목을 가져 오기 / 추가 / 제거하고 반복하는 등의 작업 집합을 노출합니다. 위치에 따라 요소에 액세스하는 방법은 의도적으로 없습니다 . 하위 클래스 이기 때문에Stack 노출 됩니다.Vector

아, 그리고 Stack인터페이스 도 없기 때문에 Stack작업이 필요하다는 것을 알고 있다면 특정 구체적인 클래스에 커밋하는 것이 일반적으로 좋지 않습니다.

또한 같은 코멘트에 지적 StackDeque역 반복 주문이 있습니다

Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(new ArrayList<>(stack)); // prints 1, 2, 3


Deque<Integer> deque = new ArrayDeque<>();
deque.push(1);
deque.push(2);
deque.push(3);
System.out.println(new ArrayList<>(deque)); // prints 3, 2, 1

이는 Deque.iterator () 에 대한 JavaDocs에도 설명되어 있습니다 .

이 큐 내의 요소의 반복자를 적절한 순서로 돌려줍니다. 요소는 첫 번째 (머리)부터 마지막 ​​(꼬리)까지 순서대로 반환됩니다.


답변

다음은 Stack 클래스 설명에 언급 된 불일치에 대한 해석입니다.

여기서 범용 구현을 살펴보면 집합, 맵 및 목록 구현에 일관된 접근 방식이 있음을 알 수 있습니다.

  • 세트와 맵에는 해시 맵과 트리가있는 2 가지 표준 구현이 있습니다. 첫 번째 구조가 가장 많이 사용되고 두 번째 구조는 정렬 된 구조가 필요할 때 사용됩니다 (또한 자체 인터페이스 인 SortedSet 또는 SortedMap을 구현 함).

  • 여기에서Set<String> set = new HashSet<String>(); 이유를 보는 것처럼 선호하는 선언 스타일을 사용할 수 있습니다. .

그러나 스택 클래스 : 1) 자체 인터페이스가 없습니다. 2) 벡터 클래스의 서브 클래스-크기 조정 가능한 배열을 기반으로합니다. 그렇다면 스택의 링크 목록 구현은 어디에 있습니까?

Deque 인터페이스에는 두 가지 구현 (크기 조정 가능한 배열-ArrayDeque; 연결 목록-LinkedList)을 포함하여 이러한 문제가 없습니다.


답변

스택을 통한 Dequeue를 사용하는 또 다른 이유는 Dequeue는 스택이 아닌 LIFO 개념을 적용한 상태에서 스트림을 변환하여 목록으로 변환 할 수 있기 때문입니다.

Stack<Integer> stack = new Stack<>();
Deque<Integer> deque = new ArrayDeque<>();

stack.push(1);//1 is the top
deque.push(1)//1 is the top
stack.push(2);//2 is the top
deque.push(2);//2 is the top

List<Integer> list1 = stack.stream().collect(Collectors.toList());//[1,2]

List<Integer> list2 = deque.stream().collect(Collectors.toList());//[2,1]


답변

다음은 Deque가 Stack보다 나은 몇 가지 이유입니다.

객체 지향 디자인-상속, 추상화, 클래스 및 인터페이스 : 스택은 클래스이고 Deque는 인터페이스입니다. 하나의 클래스 만 확장 할 수있는 반면 Java에서 단일 클래스 (다중 유형의 상속)로 인터페이스를 여러 개 구현할 수 있습니다. Deque 인터페이스를 사용하면 구체적인 Stack 클래스와 그 상위 항목에 대한 종속성이 제거되고 다른 클래스를 확장하거나 다른 Deque 구현 (예 : LinkedList, ArrayDeque)을 교체 할 수있는 자유와 같은 유연성이 향상됩니다.

불일치 : 스택은 인덱스로 요소에 액세스 할 수있는 Vector 클래스를 확장합니다. 이것은 스택이 실제로 해야하는 것과 일치하지 않기 때문에 Deque 인터페이스가 선호되는 이유 (이러한 작업을 허용하지 않음)-허용 된 작업은 FIFO 또는 LIFO 데이터 구조가 허용 해야하는 것과 일치합니다.

성능 : Stack이 확장하는 Vector 클래스는 기본적으로 ArrayList의 “스레드 안전”버전입니다. 동기화로 인해 응용 프로그램에 상당한 성능 저하가 발생할 수 있습니다. 또한 필요하지 않은 기능으로 다른 클래스를 확장하면 (# 2에서 언급 한 바와 같이) 객체가 부풀려 져서 추가 메모리와 성능 오버 헤드가 많이 발생할 수 있습니다.


답변

나 에게이 특정 포인트가 누락되었습니다 : 스택은 벡터에서 파생되므로 스레드 안전하지만 가장 구현이 빠르지 않으므로 단일 스레드에서만 사용하면 더 빠릅니다.


답변

성능이 이유 일 수 있습니다. 내가 사용한 알고리즘은 Stack을 Deque로 교체하여 7.6 분에서 1.5 분으로 줄었습니다.


답변

데크는 머리와 꼬리 모두에서 요소를 검색하려는 상황입니다. 간단한 스택을 원한다면 deque 할 필요가 없습니다.