📜  摩尔机在 C++ 中的实现

📅  最后修改于: 2021-09-28 10:12:36             🧑  作者: Mango

摩尔机:摩尔机基本上是一个 DFA,其输出与每个状态相关联。这些机器可用于多种任务,例如计算给定字符串特定子字符串的出现次数、查找二进制数的 2 的补码等。

摩尔机的工作原理:

  • 它有一个与每个状态相关联的输出。
  • 在接受输入时,它进入下一个状态。
  • 在到达下一个状态时,它会打印下一个状态的输出。
  • 这一直持续到输入结束。

摩尔机的一些应用

应用一:
给定一个由ab组成的字符串S以及一个子字符串“abb” ,任务是使用摩尔机计算给定字符串S 中给定子字符串str的出现次数。

例子:

方法:
这个问题所需的摩尔机由下式给出:

机器的转换表如下:

要实现这一点,请创建一个将输入映射到其下一个状态的结构:

struct item
{
     int value;
     State* next;
};

然后,将此结构作为数据成员在我们的类 State 中。该类具有三个数据成员:

  • Input_1:这是上面定义的 item 类型的变量。它将第一种类型的输入‘a’映射到它的下一个状态。
  • Input_2:这也是一个 item 类型的变量。它将第二种类型的输入‘b’映射到它的下一个状态。
  • m_out:这是与摩尔机的每个状态相关联的输出。

类的每个对象都表现为一个状态。它接受输入并进入适当的下一个状态。要进入下一个状态,可以使用对象指针。每个对象还有一个与之关联的输入。

以下成员函数将用于处理此数据:

  • Initialize():这用输入和相应的下一个状态初始化类对象(状态)。
  • Transition():作为机器的转换表。它从输入字符串获取一个字符并将其传递到当前状态,然后在产生输出后进入适当的下一个状态。
  • 横动():此函数采用由字符的输入字符串和字符并将其传递到所述转换函数和返回输出字符串。
  • mooreOut():此函数定义所需的状态(对象)并将它们初始化为所需的值。然后将输入字符串传递给遍历函数并接收输出字符串。
  • countStr():该函数计算输出字符串中 1 的出现次数并返回它。

下一步是在将字符串输入传递给机器的同时存储机器的当前状态。这可以通过使用静态对象指针作为数据成员:

下面是上述方法的实现:

C++14
// C++ program for the above approach
 
#include 
using namespace std;
 
// Define a class named State
class State {
private:
    // Item
    struct item {
        char value;
        State* next;
    };
 
    // Three states
    item Input1;
    item Input2;
    char m_out;
 
public:
    // Constructor
    State()
        : Input1{ ' ', nullptr },
          Input2{ ' ', nullptr },
          m_out{ ' ' }
    {
    }
 
    // Member functions
    static State* m_ptr;
    void Initialize(item input1,
                    item input2,
                    char out);
    static char Transition(char x);
    static string Traverse(string& str,
                           int n);
};
 
// Global object pointer points to
// current state
State* State::m_ptr{ nullptr };
 
// Function that initializes the states
// with appropriate values
void State::Initialize(item input1,
                       item input2,
                       char out)
{
    Input1 = input1;
    Input2 = input2;
    m_out = out;
}
 
// Transition function that takes each
// character of string
char State::Transition(char x)
{
    char ch{};
 
    // Prints the output
    if ((*m_ptr).Input1.value == x) {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input1.next;
    }
    else {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input2.next;
    }
 
    // Return ch
    return ch;
}
 
// Takes the whole string and pass
// it through machine
string State::Traverse(string& str,
                       int n)
{
    string str1{};
 
    // Add all the transition state to
    // the string str1
    for (int i = 0; i < n; i++)
        str1 += Transition(str[i]);
 
    // Append output
    str1 += (*m_ptr).m_out;
    cout << (*m_ptr).m_out << endl;
 
    // Return str1
    return str1;
}
 
// Function that create states and
// produce output
string mooreOut(string str, int n)
{
    State q1, q2, q3, q4;
 
    // Initializing the states
    q1.Initialize({ 'a', &q2 },
                  { 'b', &q1 }, '0');
    q2.Initialize({ 'a', &q2 },
                  { 'b', &q3 }, '0');
    q3.Initialize({ 'a', &q2 },
                  { 'b', &q4 }, '0');
    q4.Initialize({ 'a', &q2 },
                  { 'b', &q1 }, '1');
    State::m_ptr = &q1;
 
    // Traverse the string str1
    string str1{ State::Traverse(str, n) };
    return str1;
}
 
// Function that counts the occurrences
// of 1 in the output string
int countStr(string& str, int n)
{
    int count{};
 
    // Count the 1s in str
    for (int i = 0; i < n; i++) {
        if (str[i] == '1')
            count++;
    }
 
    // Return count
    return count;
}
 
// Driver Code
int main()
{
 
    // Given string
    string str{ "babbabbabbb" };
 
    int n{ static_cast(str.length()) };
 
    // Function Call
    string str1{ mooreOut(str, n) };
    int n1{ static_cast(str.length()) };
 
    // Print the count of substring
    cout << "abb occurs " << countStr(str1, n1)
         << " times\n";
    return 0;
}


C++
// C++ program for the above approach
 
#include 
using namespace std;
 
// Define a class named State
class State {
private:
    struct item {
        char value;
        State* next;
    };
    item Input1;
    item Input2;
    char m_out;
 
public:
    // Constructors
    State()
        : Input1{ ' ', nullptr },
          Input2{ ' ', nullptr },
          m_out{ ' ' }
    {
    }
    static State* m_ptr;
 
    // Member Functions
    void Initialize(item input1,
                    item input2,
                    char out);
    static char Transition(char x);
    static string Traverse(string& str,
                           int n);
};
 
// Global object pointer points to
// current state
State* State::m_ptr{ nullptr };
 
// Function that initializes the states
// with appropriate values
void State::Initialize(item input1,
                       item input2,
                       char out)
{
    Input1 = input1;
    Input2 = input2;
    m_out = out;
}
 
// Transition function takes each
// character of string
char State::Transition(char x)
{
    char ch{};
 
    // Prints the output
    if ((*m_ptr).Input1.value == x) {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input1.next;
    }
    else {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input2.next;
    }
 
    // Return ch
    return ch;
}
 
// Takes the whole string and passes
// through machine
string State::Traverse(string& str, int n)
{
    string str1{};
 
    // Add all the transition state to
    // the string str1
    for (int i = n - 1; i >= 0; i--) {
        str1 += Transition(str[i]);
    }
 
    // To read the characters from end
    // therefore we need to reverse
    reverse(str1.begin(), str1.end());
 
    return str1;
}
 
// Function to create states and
// produce output
string mooreOut(string str, int n)
{
    State q1, q2, q3;
 
    // Initializing the states
    q1.Initialize({ '0', &q1 },
                  { '1', &q2 }, '0');
    q2.Initialize({ '0', &q2 },
                  { '1', &q3 }, '1');
    q3.Initialize({ '0', &q2 },
                  { '1', &q3 }, '0');
    State::m_ptr = &q1;
    return State::Traverse(str, n);
}
 
// Driver Code
int main()
{
    // Given string
    string str{ "111010000" };
    int n{ static_cast(str.length()) };
 
    // Function Call
    string str1{ mooreOut(str, n) };
 
    // Print the output
    cout << "2's complement: " << str1;
    return 0;
}


输出:
000010010010
abb occurs 3 times

时间复杂度: O(N)
辅助空间: O(N)
应用二:
给定一个二进制字符串str ,任务是找到给定字符串str的 2s 补码。

方法:这个想法是从最右边的位开始并将其传递到给出输出的机器中。像这样从右到左传递整个字符串。可以观察到以下观察结果:
例如:给定的字符串是“111010000”。现在,2s 补码由(str) + 1 的 1s 补码给出。因此,

str =           "111010000"
1s compliment = "000101111"
                +        1
---------------------------
2s compleemnt =  000110000

在这里我们可以观察到,从最右边的位开始,这些位以相同的方式复制,直到出现 1。之后,所有位都被反转。
因此,我们的想法是定义一个摩尔机来从最右边开始接受输入。只要该位为0,它就会给出相同的输出(0) 。当遇到1,那么它给1为。在此之后,对于作为输入的任何位,其逆作为输出给出。

这个问题的摩尔机如下:

要首先实现这一点,请映射此机器的转换表。需要三个状态,即开头定义的 State 类的三个对象:

  • State1 => Initialize( {‘0’, &State1}, {‘1’, &State2}, ‘0’)
  • State2 => Initialize( {‘0’, &State2}, {‘1’, &State3}, ‘1’)
  • State3 => Initialize( {‘0’, &State2}, {‘1’, &State3}, ‘0’)

初始化后,需要一个 Transition函数,就像上面定义的那样。它接受一个输入并为此打印当前状态的输出,并通过使用上面定义的转换表将输入映射到下一个状态来进入下一个状态。然后遍历字符串,转换从最右边的位开始,一直到最左边的位。

下面是上述方法的实现:

C++

// C++ program for the above approach
 
#include 
using namespace std;
 
// Define a class named State
class State {
private:
    struct item {
        char value;
        State* next;
    };
    item Input1;
    item Input2;
    char m_out;
 
public:
    // Constructors
    State()
        : Input1{ ' ', nullptr },
          Input2{ ' ', nullptr },
          m_out{ ' ' }
    {
    }
    static State* m_ptr;
 
    // Member Functions
    void Initialize(item input1,
                    item input2,
                    char out);
    static char Transition(char x);
    static string Traverse(string& str,
                           int n);
};
 
// Global object pointer points to
// current state
State* State::m_ptr{ nullptr };
 
// Function that initializes the states
// with appropriate values
void State::Initialize(item input1,
                       item input2,
                       char out)
{
    Input1 = input1;
    Input2 = input2;
    m_out = out;
}
 
// Transition function takes each
// character of string
char State::Transition(char x)
{
    char ch{};
 
    // Prints the output
    if ((*m_ptr).Input1.value == x) {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input1.next;
    }
    else {
 
        // Output the current state
        cout << (*m_ptr).m_out;
        ch = (*m_ptr).m_out;
 
        // Next input state
        m_ptr = (*m_ptr).Input2.next;
    }
 
    // Return ch
    return ch;
}
 
// Takes the whole string and passes
// through machine
string State::Traverse(string& str, int n)
{
    string str1{};
 
    // Add all the transition state to
    // the string str1
    for (int i = n - 1; i >= 0; i--) {
        str1 += Transition(str[i]);
    }
 
    // To read the characters from end
    // therefore we need to reverse
    reverse(str1.begin(), str1.end());
 
    return str1;
}
 
// Function to create states and
// produce output
string mooreOut(string str, int n)
{
    State q1, q2, q3;
 
    // Initializing the states
    q1.Initialize({ '0', &q1 },
                  { '1', &q2 }, '0');
    q2.Initialize({ '0', &q2 },
                  { '1', &q3 }, '1');
    q3.Initialize({ '0', &q2 },
                  { '1', &q3 }, '0');
    State::m_ptr = &q1;
    return State::Traverse(str, n);
}
 
// Driver Code
int main()
{
    // Given string
    string str{ "111010000" };
    int n{ static_cast(str.length()) };
 
    // Function Call
    string str1{ mooreOut(str, n) };
 
    // Print the output
    cout << "2's complement: " << str1;
    return 0;
}
输出:
2's complement: 000110000

时间复杂度: O(N),其中 N 是给定二进制字符串的长度。
辅助空间: O(N)