【问题标题】:Truncating A Java Stack截断 Java 堆栈
【发布时间】:2015-06-07 20:27:36
【问题描述】:

我在 Java 中定义了一个 Stack<String>,用于在工作流中导航。

我想做的是确保堆栈中的所有值都是唯一的:当发生到“先前”状态的转换时,我想在堆栈中第一次出现前一个状态之后从堆栈中删除所有内容.

有没有简单的方法可以做到这一点?

编辑:要求提供更多信息。以下是堆栈内容的示例:

[state2, state3, state2, state1, startState]

我需要能够接受一个字符串,检查堆栈并查看它是否多次出现,然后弹出元素直到该字符串的“最底部”出现。 “截断”可能是对我想要做的事情的错误描述......“弹出直到我达到任意索引”可能更接近我的需要。

【问题讨论】:

  • 弹出直到到达之前的状态?似乎没有那么“难”;虽然“第一次出现”可以使用澄清 - 例如最接近堆栈的顶部或底部?
  • 堆栈中存在重复字符串的可能性很小。如果我从堆栈中弹出,我需要弹出直到第一次出现该字符串。如果我使用列表,我会获取索引并创建一个 subList,但没有 subStack 这样的东西。
  • 您能否进一步澄清这意味着什么?当前的描述意味着像流行音乐将删除头部以及除了头部下方的值 1 之外的所有其他内容?
  • @Jason,Stack 实现了 List(在许多其他接口中)。所以你仍然可以得到一个子列表。

标签: java


【解决方案1】:

这是一个使用 Deque 而不是 Stack 的 truncate 方法的示例。

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;

public class ExampleDeque 
{

  public static void main(String[] args)    
  {
    Deque<String> deque = new ArrayDeque<String>();
    deque.offer("startState");
    deque.offer("state1");
    deque.offer("state2");
    deque.offer("state3");
    deque.offer("state2");

    System.out.println("Before");
    print(deque);
    deque = truncate(deque, "state2");
    System.out.println("After");
    print(deque);
  }

  static Deque<String> truncate (Deque<String> deque, String value)
  {
    if(!deque.contains(value)) return deque;

    String[] array = deque.toArray(new String[deque.size()]);
    for(int i = 0; i < array.length;  i++)
    {
      if(array[i] == value)
      {
        String[] truncated = Arrays.copyOfRange(array, 0, i + 1);
        Collection<String> collection = Arrays.asList(truncated);   
        return new ArrayDeque<>(collection);
      }
    }
    return null;
  }

  static void print(Deque<String> deque)
  {
    for(String s : deque)
      System.out.println(s);
    System.out.println();
  }
}

【讨论】:

    【解决方案2】:

    如果您创建自己的容器(基本上是一个集合即堆栈),它会简化您的整体代码吗?类似的东西(不是完整的实现):

    public class StackSet<T> {
        private final Set<T> set;
        private final Deque<T> queue;
    
        public StackSet(){
            set = new HashSet<>();
            queue = new ArrayDeque<>();
        }
    
        public void push(T value){
            if(set.add(value)){
                queue.push(value);
            }
        }
    
        public T pop(){
            return queue.pop();
        }
    }
    

    这应该保证没有重复。

    【讨论】:

      【解决方案3】:

      Stack 实现List(在各种其他接口中)。为最后一个元素获取ListIterator,并将其向后移动,直到找到新状态的出现,计算沿途有多少元素,然后弹出那么多元素。 (如果您没有找到新状态,那么您当然不会弹出任何内容,而是将新状态推送到堆栈中。

      这可能不是特别有效,但肯定会奏效。如果您还希望它高效,您可能需要使用另一种数据结构(代替堆栈或与堆栈一样)。一种可能性是使用Map(除了堆栈)来跟踪堆栈上的哪些状态以及它们发生的索引,或者至少使用Set 来跟踪哪些状态处于打开状态堆栈(然后您可以弹出状态,直到找到您要查找的状态)。您将维护堆栈和地图或并行设置。

      或者如果你是认真的:

      “pop until I hit an random index”可能更接近我的需要。

      ...那么肯定就足够了:

      int numberToPop = stack.size() - arbitraryIndex - 1;
      while (numberToPop-- > 0) {
          stack.pop();
      }
      

      【讨论】:

        【解决方案4】:

        考虑使用双端队列。下面的链接解释了为什么要在堆栈上使用它。

        Why should I use Deque over Stack?

        【讨论】:

          猜你喜欢
          • 2012-01-29
          • 2015-11-14
          • 2010-12-15
          • 1970-01-01
          • 2015-11-16
          • 2011-03-16
          • 1970-01-01
          • 2019-11-07
          • 1970-01-01
          相关资源
          最近更新 更多