Могу ли я реализовать переходы состояний для DFA на Java с помощью java.util.Set

Я использую DFA как можно ближе к формальному определению в качестве учебного упражнения (и материалов для блогов).

Я планировал использовать java.util.Set, где набор участвует в определении.

Определение включает в себя набор кортежей для определения переходов между законными состояниями: (состояние, символ) -> nextState.

У меня есть класс Transition с состоянием членов, символом и nextState. Я реализовал equals () и hashCode (), чтобы указать, что два перехода равны, если они совпадают по состоянию и символу. Затем у меня есть java.util.Set экземпляров Transition.

В моем алгоритме обработки у меня есть текущее состояние, когда я читаю следующий символ. Я ожидал создания объекта Transition, используя эти два, чтобы вытащить соответствующий переход из набора, который затем сообщит мне следующее состояние, и я могу выполнить итерацию.

Но - я не вижу способа извлечь член java.util.Set для дальнейшего использования. Я могу удалить (Объект o), но это просто возвращает логическое значение.

Что я делаю неправильно?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
0
5 634
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Set, вероятно, не то, что вы хотите использовать для этого. Я бы рекомендовал использовать List <Transition> или, возможно, Map <State, List <Transition >>. Я не уверен, что было бы лучше, не создавая его и не делая некоторых тестов.

Дело не в производительности или чем-то еще, это просто простая для понимания реализация. Мне нравится мысль Map - в определении написано, что есть функция перехода, а не набор функций перехода - так что, думаю, это было бы в духе ...

brabster 15.01.2009 01:11

Я думаю, что Map <<Transition>, State>, где состояние - это следующее состояние, на самом деле - позвольте мне попробовать.

brabster 15.01.2009 01:13

Переход / Состояние также будет хорошим выбором для записей на карте. знак равно

Matthew Brubaker 15.01.2009 01:19

Похоже, ваше переопределение equals () и hashCode () сомнительно, потому что исходный переход совпадает с переходом в наборе в соответствии с equals (), и все же эти два не взаимозаменяемы (иначе вы просто использовали бы новый переход вместо оригинала.)

Вероятно, вам понадобится класс, представляющий собой просто комбинацию состояния и символа без других атрибутов, и использовать его в качестве ключа на карте. В качестве альтернативы вы можете использовать Map<State, Map<Symbol, State>>

Я согласен с Мэтью Брубейкером в том, что Set, вероятно, не то, что вам нужно. Вместо этого вы можете попробовать enums; см. Глоссарий Java для примера.

Разве вы не можете этого добиться, не имея некоторого внешнего набора состояний или даже объектов Transistion? Если класс State определен как:

public class State
{
    private Map<Symbol, State> transitions = new HashMap<Symbol, State>();

    public State() { /* populate transitions somehow */ }

    public State nextState(Symbol symbol) { return transitions.get(symbol); }
}

Затем, если у вас есть ссылка на начальное состояние, вы можете просто перейти из состояния в состояние следующим образом:

State initial = getInitialStateSomehow();
State second = initial.nextState(SYMBOL_1);
State third = initial.nextState(SYMBOL_2);  // etc...

Да, я немного не понимаю, зачем вообще нужна коллекция.

Для простого конечного автомата вы можете просто использовать статические целые числа и оператор case, чтобы сделать конечный автомат следующим образом:

int STATE1 = 1; 
int STATE2 = 2;
int STATE3 = 3;
int STATE4 = 4;

int currentstate = STATE1 ;
int input = nextInput();


while(currentstate != STATE4 ){
   switch(input){
      case STATE1: 
          if (input == 'a') currentstate = STATE2; 
          break;
      case STATE2: 
          if (input == 'b') currentstate = STATE3;
          else currentstate = STATE1;
          break;
      case STATE3: 
          if (input == 'c')  currentstate = STATE4;
          else currentstate = STATE1;
      }
 }

Это базовый конечный автомат, который будет искать любую строку, содержащую «abc». Вы можете легко расширить это тоже, ищите ab * c или что угодно.

Так что, если вам нужен динамический конечный автомат, созданный во время выполнения? Что ж, я тоже это сделал. Это не так уж сложно. Я создал класс состояний со списком переходов. Каждый переход имеет указатель на следующее состояние и критерии для ссылки.

Так, например, STATE1 будет иметь переход с критерием «a» и указатель на некоторый объект, представляющий STATE2. Код будет проверять критерии (это может быть объект, который принимает int в качестве параметра и возвращает true или false, если он совпадает), и если критерии совпадают, он переместит указатель состояния в состояние, на которое также указывает переход.

Код может выглядеть примерно так: ths

public void move(int input){
   for(transition t : currentState.transitions){
      if (t.getCriteria().matches(input)){
         currentState = t.getNextState();
         break;
      }
   }
}

Вы думаете о детерминированном конечном автомате! OP, вероятно, означал недетерминированный конечный автомат, где использование наборов для текущих состояний и принятых состояний имеет гораздо больший смысл.

Konrad Rudolph 15.01.2009 01:34

Он конкретно сказал «DFA», а не «NFA». Хотя было бы больше смысла, если бы он говорил о NFA.

Chad Okere 15.01.2009 04:12

Если вы просто хотите реализовать механизм сопоставления с шаблоном, шаблон State Design Pattern может быть ненужным, поскольку шаблон вряд ли изменится. Как указал Чад, использование switch для кодирования функции перехода в таких случаях полностью приемлемо.

Вот пример недетерминированного автомата сопоставления с образцом, который использует наборы:

public boolean validate() {
    Set<Integer> currentStates = new HashSet<Integer>();
    final Set<Integer> acceptingStates = new HashSet<Integer>();

    currentStates.add(0); // Initial state.
    acceptingStates.add(1);
    acceptingStates.add(3);
    acceptingStates.add(6);

    for (int i = 0; i < getInput().length(); i++) {
        char c = getInput().charAt(i);
        Set<Integer> newStates = new HashSet<Integer>();

        for (int state : currentStates) {
            switch (state) {
                case 0:
                    if (c == 'a')
                        newStates.add(1);
                    break;
                case 1:
                    if (c == 'b') {
                        newStates.add(2);
                        newStates.add(4);
                    }
                    break;
                case 2:
                    if (c == 'b')
                        newStates.add(3);
                    break;
                case 3:
                    if (c == 'b')
                        newStates.add(2);
                    break;
                case 4:
                    if (c == 'b')
                        newStates.add(5);
                    break;
                case 5:
                    if (c == 'b')
                        newStates.add(6);
                    break;
                case 6:
                    if (c == 'b')
                        newStates.add(4);
                    break;
            }
        }

        if (newStates.size() == 0)
            return false;
        currentStates = newStates;

        System.out.printf("Character read: %c\n", c);
        System.out.printf("Current states: ");
        printStates(currentStates);
    }

    for (int state : acceptingStates)
        if (currentStates.contains(state))
            return true;
    return false;
}

Этот автомат распознает входные слова обычного языка, описанные шаблоном "a(bb*|bbb*) ", то есть" а ", за которым следует либо кратное двум, либо кратное трем многим буквам" b ".

Другие вопросы по теме