2013-06-07 2 views
27

Сегодня я пытался нажать java.util.Stack класс, а затем использовать Iterator для итерации (без использования pop) через предметы. Я ожидал собственности LIFO, но удивился.Есть ли ошибка в java.util.Stack's Iterator?

Вот код, который я пытался.

import java.util.*; 
import java.util.Stack; 

public class Main { 
    public static void main(String[] args) { 
     RobStack<Integer> rstack = new RobStack<Integer>(); // Correct Implementation 
     Stack<Integer> jstack = new Stack<Integer>(); // Default Java Implementation 
     rstack.push(0); jstack.push(0); 
     rstack.push(1); jstack.push(1); 
     rstack.push(2); jstack.push(2); 
     rstack.push(3); jstack.push(3); 

     System.out.print("Algo Stack: "); 
     for (int i : rstack) 
      System.out.print(i + " "); 
     System.out.print("\nJava Stack: "); 
     for (int i : jstack) 
      System.out.print(i + " "); 
    } 

} 

Выход выше программы приведен ниже:

Algo Stack: 3 2 1 0 
Java Stack: 0 1 2 3 

В приведенном выше коде jstack использует реализацию Java по умолчанию и rstack использует implementation provided by Robert Sedgewick для своего класса алгоритма. Я обнаружил, что реализация профессора Роберта работает нормально, но реализация java.util.Stack не выполняется.

Это ошибка или это дизайн?

+7

Примечание: 'Stack' является устаревшим, вы должны использовать' Deque' вместо (например, символом 'ArrayDeque' – fge

+0

А что, если вы используете поп() операцию – jtomaszk

+2

В поддержку комментариев FGE, в самом док? класса [Stack] (http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html): 'Более полный и согласованный набор операций стека LIFO обеспечивается интерфейсом Deque и его реализации, которые следует использовать в предпочтении этому классу. ' – nhahtdh

ответ

25

См. Bug ID 4475301 : RFE: java.util.Stack.iterator() iterates the wrong way. Это поведение (плохой) дизайн. Встроенные в Java методы Stack итератора наследуются от других классов, поэтому они не ведут себя так, как вы ожидали.

+0

Почему они исправляют ошибку, когда это можно сделать, просто переопределив метод Итератора? –

+0

@ vincentmathew Да, они могли бы переопределить метод 'iterator()' точно так же, как в коде профессора Sedgewick, с которым вы связались, чтобы сделать его итерацией в порядке LIFO (при условии того же внутреннего представления). –

+0

@BilltheLiazard Возможно, они не могли. «Было неправильным проектным решением о том, что Stack extend Vector (« is-a », а не« has-a »). Мы сочувствуем подателю, но не можем исправить это, потому что совместимости». –

2

Ну, в принципе, вы не должны перебирать Stack, а только нажимать сверху или поп сверху. Что касается фактической реализации, большинство языков, включая Java, используют другой collection type для реализации Stack. С точки зрения строгих требований, это должно позволить постоянное время работы push, top and pop.

Любые дополнительные функции (или ошибка в этом случае) следует просто игнорировать и не использовать для кодирования.

1

Eclipse Collections содержит mutable stack implementation, где итератор возвращает значения сверху вниз. Этот код печатает 3, 2, затем 1.

MutableStack<Integer> stack = ArrayStack.newStack(); 
stack.push(1); 
stack.push(2); 
stack.push(3); 
for (Iterator<Integer> iterator = stack.iterator(); iterator.hasNext();) 
{ 
    Integer each = iterator.next(); 
    System.out.println(each); 
} 

MutableStack не распространяется MutableCollection или Collection, так что вы не можете удалить из середины стопки, например. Методы, которые реализуют внутренние итерационные шаблоны, такие как forEach(), select(), collect(), anySatisfy(), allSatisfy() и т. Д. Также обрабатывают элементы сверху донизу. Этот код печатает то же самое.

stack.forEach(Procedures.println(System.out)); 

Примечание: Я коммиттер для коллекций Eclipse.

0

Стек наследует .listIterator() от AbstractList который позволяет итерации обратного порядка.

Stack<Integer> stack = new Stack<Integer>(); 
stack.push(1); 
stack.push(2); 
stack.push(3); 
for (ListIterator<Integer> iterator = stack.listIterator(stack.size()); iterator.hasPrevious();) { 
    Integer integer = iterator.previous(); 
    System.out.println(integer); 
} 
// Output: 3 2 1 
9

Вы должны использовать Deque вместо Stack.

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

See Oracle Doc

2

Может быть, вы можете использовать .get() для печати элементов в стеке сверху вниз.

Stack<Integer> stack = new Stack<Integer>(); 
stack.push(3); 
stack.push(2); 
stack.push(1); 
// print from top to bottom 
for(int i = stack.size() - 1; i >= 0; i--){ 
    System.out.println(stack.get(i)); 
} 
/* 
output 
1 
2 
3 
*/