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


157

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

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

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

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

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

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


1
더 많은 내장 메소드를 제공하거나,보다 "일관되고 일관성있는"메소드를 제공하는데,이를 활용하면 작성해야하는 코드의 양이 줄어 듭니다.

답변:


190

우선, 상속 측면에서 더 합리적입니다. 내 견해로는 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에도 설명되어 있습니다 .

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


10
ArrayDeque의 javadoc는 "이 클래스는 스택으로 사용될 때 Stack보다 빠르며, 대기열로 사용될 때 LinkedList보다 빠를 것"이라고 말합니다. .. 이것을 스택 또는 대기열로 사용할지 어떻게 지정합니까?
Geek

23
@ eek : 당신은하지 않습니다. 요점은 큐잉 동작을 원한다면을 사용할 LinkedList 있지만 ArrayDequeue종종 더 빠를 것입니다. 스택 동작을 원한다면 사용할 Stack있지만 ArrayDeque더 빠를 것입니다.
존 스키트

7
그래도 추상화 측면에서 덜 합리적이지 않습니까? Stackrep 노출 문제가 있기 때문에 솔루션이 추상화 측면에서 실제로 우수 하지는 않지만 스택 데이터 구조를 원한다면 푸시, 팝 및 엿보기와 같은 메소드를 호출 할 수 있기를 원합니다. 스택의 다른 쪽 끝으로 수행하십시오.
PeteyPabPro

4
@ JonSkeet도 Stack의 반복자가 잘못되었습니다. 왜냐하면 위에서 아래로가 아니라 아래에서 위로 반복하기 때문입니다. stackoverflow.com/questions/16992758/…
Pavel

1
@ PeteyPabPro : 당신이 맞아요. Dequeue를 스택으로 사용하면 상속되지 않은 Stack의 Vector 메서드로 비 LIFO를 계속 사용할 수 있습니다. 문제와 (캡슐화) 솔루션에 대한 설명은 여기에서 찾을 수 있습니다 : baddotrobot.com/blog/2013/01/10/stack-vs-deque
RICS에게

4

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

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

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

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

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

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


2

스택을 통한 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]

2

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

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

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

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


-1

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


grep "이것과 별개"
Pacerier

-1

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


grep "이것과 별개"
Pacerier

-6

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


1
질문의 마지막 단락을 참조하십시오. javadoc은 Deques를 사용해야한다고 말하고 이유를 알고 싶습니까?
Geek

2
양단 큐 바람직하다 때문에 당신이 할 수없는 중간에 액세스 요소. 더블 엔드이므로 FIFO의 FILO가 될 수 있습니다.
Thufir

그들이 말하고자하는 것은 클래스가 명시 적 메소드로 스택 작업을 지원한다는 것입니다. 설명서 및 방법을 참조하십시오. 스택 구현을 명시 적으로 지원합니다.
Abhishek Nandgaonkar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.