无法打印出预期的结果,Travasa函数中的错误?

时间:2019-07-12 18:22:52

标签: c++ templates stack queue

我必须实现2个模板类:队列和堆栈 在堆栈类中,我必须实现函数Travasa(),该函数应该从当前堆栈中获取元素并将其排队到队列中; 我必须从输入文件中读取一系列操作并获取输出文件

文件输入为:

bool 10 e:0 p:0 p:1 travasa p:1 e:1 pop e:1出队e:0

字符10 e:g p:k e:j e:h travasa p:f p:o e:n pop p:e

char 10 p:c travasa p:n出队travasa p:p e:o出队e:p travasa

int 10 e:7 p:88 p:42 pop pop e:82 e:12 p:54 e:49 travasa

输出应为:

1 0 1 1 0

g j h k n

o p p

7 82 12 49 54

但我的输出是:

0 1 0

g j h n

p

7 82 12 49

#include <iostream>
#include <fstream>

using namespace std;

ifstream infile("input.txt");
ofstream outfile("output.txt");

template<typename T> class Queue
{
private:
    T * values;
    int dim;
    int Top;
public:
    Queue(int L):dim(L){
        values=new T[L];
        dim=L;
        Top=-1;
    };

    ~Queue(){
        delete values;
    }

    void Enqueue(T value);
    void Dequeue();
    void Print();
};
template <typename T> void Queue<T>:: Enqueue(T value){
    if(Top<dim){
    Top++;
    values[Top]=value;
    }
    else cerr<< "Queue is Full!"<< endl;
}


template <typename T> void Queue<T>:: Dequeue(){
    if(Top>=0)
    Top--;
    else cerr<< "Queue already empty"<< endl;
}

template <typename T> void Queue<T>:: Print(){
    for(int i=0; i<=Top; i++) outfile<< values[i]<< " ";
}

template <typename T> class Stack
{
private:
    T * values;
    int dim;
    int top;
public:
    Stack(int L): dim(L){
        values=new T [L];
        top=L;
    } ;
    ~Stack(){
        delete values;
    };


    void Push(T value);
    void Pop();
    void Print();
    void Travasa(Queue <T> A);
};

template <typename T> void Stack<T>:: Push(T value){
    top--;
    if(top>=0)
    values[top]=value;
    else cerr<< "Stack is Full!"<< endl;
}

template <typename T> void Stack<T>:: Pop(){
    if(top<dim)
    top++;
    else cerr<< "Stack is already empty"<< endl;
}

template <typename T> void Stack<T>:: Print(){
    for(int i=top; i<dim; i++) outfile<< values[i]<< " ";
}

template <typename T> void Stack<T>::Travasa(Queue <T> A){
   for(int i=top; i<dim; i++) {
       A.Enqueue(values[i]);
       Pop();
    }

}


int main(){

    int c=0, N;
    string tipo,operazione;

    for(c=0; c<4; c++){
        cout<<"prova"<< endl;
        infile>>tipo>> N;
        if(tipo=="int"){
            Queue<int> A(N);
            Stack<int> B(N);
            for(int j=0; j<N;j++){
                infile>> operazione;
                if(operazione== "travasa")
                B.Travasa(A);
                else if(operazione=="pop")
                B.Pop();
                else if(operazione=="dequeue")
                A.Dequeue();
                else if(operazione.substr(0,2)=="e:")
                {
                    int elemento=stoi(operazione.substr(2));
                    A.Enqueue(elemento);    
                }
                else if(operazione.substr(0,2)=="p:")
                {
                    int elemento=stoi(operazione.substr(2));
                    B.Push(elemento);
                }

            }
            A.Print();
            //A.~Queue();
            //B.~Stack();
            outfile<< endl;
        }
        if(tipo=="double"){
            Queue<double> A(N);
            Stack<double> B(N);
            for(int j=0; j<N;j++){
                infile>> operazione;
                if(operazione== "travasa")
                B.Travasa(A);
                else if(operazione=="pop")
                B.Pop();
                else if(operazione=="dequeue")
                A.Dequeue();
                else if(operazione.substr(0,2)=="e:")
                {
                    double elemento=stod(operazione.substr(2));
                    A.Enqueue(elemento);    
                }
                else if(operazione.substr(0,2)=="p:")
                {
                    double elemento=stod(operazione.substr(2));
                    B.Push(elemento);
                }

            }
            A.Print();
            A.~Queue();
            B.~Stack();            
            outfile<< endl;        
        }
        if(tipo=="bool"){
            Queue<int> A(N);
            Stack<int> B(N);
            for(int j=0; j<N;j++){
                infile>> operazione;
                if(operazione== "travasa")
                B.Travasa(A);
                else if(operazione=="pop")
                B.Pop();
                else if(operazione=="dequeue")
                A.Dequeue();
                else if(operazione.substr(0,2)=="e:")
                {
                    bool elemento=stoi(operazione.substr(2));

                    A.Enqueue(elemento);    
                }
                else if(operazione.substr(0,2)=="p:")
                {
                    bool elemento=stoi(operazione.substr(2));
                    B.Push(elemento);
                }

            }
            A.Print();
            A.~Queue();
            B.~Stack();            
            outfile<< endl;    
        }
        if(tipo=="char"){
            Queue<char> A(N);
            Stack<char> B(N);
            for(int j=0; j<N;j++){
                infile>> operazione;
                if(operazione== "travasa")
                B.Travasa(A);
                else if(operazione=="pop")
                B.Pop();
                else if(operazione=="dequeue")
                A.Dequeue();
                else if(operazione.substr(0,2)=="e:")
                {
                    string elemento=operazione.substr(2);
                    A.Enqueue(elemento[0]);    
                }
                else if(operazione.substr(0,2)=="p:")
                {
                    string elemento=operazione.substr(2);
                    B.Push(elemento[0]);
                }

            }
            A.Print();
            A.~Queue();
            B.~Stack();
            outfile<< endl;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

这将涉及..现有代码中存在很多错误。将代码分解为更小,更易于管理的部分,可以更轻松地发现这些问题所在。


出队中断

这是更微妙的问题之一。您对出队的操作完全是错误的。您的队列基于最初为空的序列,并且其“顶部”始终指队列的“后部”(项进入其中)。添加项目时,t Top会增加,新项目会存储在values[Top]中。

但是您在出队操作期间不要坚持这种设计。请记住,队列是一个FIFO(先进先出)。这意味着values开头的项目是需要删除的项目。对于当前的设计(非循环队列),这意味着需要对元素进行一些“向下”移动,但您无需这样做。相反,您的出队看起来像这样:

template <typename T> void Queue<T>:: Dequeue(){
    if(Top>=0)
       Top--;
    else cerr<< "Queue already empty"<< endl;
}

错了。这将您的队列视为 stack 。它应该看起来像这样:

template <typename T> void Queue<T>:: Dequeue(){
{
    if (Top >= 0)
    {
        for (int i=0; i<Top; ++i)
            values[i] = values[i+1];
        --Top;
    }
    else
    {
        std::cerr<< "Queue already empty"<< std::endl;
    }
}

违反三/五/零法规的规定

无论您是否意识到,您的类(尤其是Queue<T>)都在进行不必要的复制。他们没有为此做好准备。这个:

template <typename T> void Stack<T>::Travasa(Queue <T> A){
   for(int i=top; i<dim; i++) {
       A.Enqueue(values[i]);
       Pop();
    }
}

查看A参数。是按价值。这意味着两件事。

  • A是调用方参数的默认副本。
  • 由于不正确的3/5/0规则,现在两个对象(此处的A和调用方变量)都具有指向 same 数据的动态指针。当其中一个释放后,另一个将悬空指针留下,进一步的解除引用会导致未定义的行为

以适应特定问题。 Travesa应该以{{1​​}}作为参考。显然正在修改它。后来。我们可以支持两个类模板AQueue,以确保它们不再允许这种错误。

首先是成员函数:

Stack

(可选)通过使这两个类不可复制来确保不再发生这种情况。很简单首先创建一个简单的基类template <typename T> void Stack<T>::Travasa(Queue <T>& A) { for(int i=top; i<dim; i++) A.Enqueue(values[i]); top = dim; }

NonCopyable

现在,仅从中继承您的两个类模板。例如,class NonCopyable { protected: NonCopyable() {} private: NonCopyable(const NonCopyable&) = delete; NonCopyable& operator =(const NonCopyable&) = delete; }; 的外观如下:

Queue

现在,您尝试在任何地方制作template<typename T> class Queue : public NonCopyable { // ... implementation } 实例化值的副本时,编译器都会抱怨,并且您将看到问题出在哪里。


分而治之

您的Queue中有很多密密的代码试图做很多事情。但是,如果您不需要它怎么办?如果您将每条操作线都当作自己的实体来处理,该怎么办?例如,假设您有一条main()行来处理命令行序列的整数转换。看起来可能像这样:

process_int

此代码中唯一与您的实现不兼容的是最终输出,该输出使用运算符重载(我将在稍后介绍)。但是希望您能看到这有多清洁。显然发生了什么。这是另一个版本,这次是void process_int(int N, std::istream& inp, std::ostream& outp) { Queue<int> A(N); Stack<int> B(N); std::string op; while (N-- && inp >> op) { if(op == "travasa") B.Travasa(A); else if(op=="pop") B.Pop(); else if(op=="dequeue") A.Dequeue(); else if(op.substr(0,2)=="e:") { int elemento=stoi(op.substr(2)); A.Enqueue(elemento); } else if(op.substr(0,2)=="p:") { B.Push(std::stoi(op.substr(2))); } } outp << A << '\n'; }

char

再次,看看了解正在发生的事情要容易得多。


全部组合

所有这些的最终版本如下所示。在众多变化中:

  • 固定出队操作
  • 添加了不可复制的基类,以防止意外复制
  • 添加了按行处理
  • 添加了流媒体打印支持,并且void process_char(int N, std::istream& inp, std::ostream& outp) { Queue<char> A(N); Stack<char> B(N); std::string op; while (N-- && inp >> op) { if(op== "travasa") B.Travasa(A); else if(op=="pop") B.Pop(); else if(op=="dequeue") A.Dequeue(); else if(op.substr(0,2)=="e:") A.Enqueue(op[2]); else if(op.substr(0,2)=="p:") B.Push(op[2]); } outp << A << '\n'; } 超载。
  • 模块化处理每种正在处理的命令行。
  • 将文件移动到它们所属的operator <<

结果如下:

main

输入文件

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

class NonCopyable
{
protected:
    NonCopyable() {}

private:
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator =(const NonCopyable&) = delete;
};


template<typename T>
class Queue : public NonCopyable
{
private:
    T * values;
    int dim;
    int Top;
public:
    Queue(int L)
        : values(new T[L])
        , dim(L)
        , Top(-1)
    {
    };

    virtual ~Queue()
    {
        delete [] values;
    }

    void Enqueue(T value)
    {
        if(Top<dim){
            Top++;
            values[Top]=value;
        }
        else std::cerr<< "Queue is Full!"<< std::endl;
    }

    void Dequeue()
    {
        if (Top >= 0)
        {
            for (int i=0; i<Top; ++i)
                values[i] = values[i+1];
            --Top;
        }
        else
        {
            std::cerr<< "Queue already empty"<< std::endl;
        }
    }

    void Print(std::ostream& outp) const
    {
        for(int i=0; i<=Top; i++)
            outp << values[i] << ' ';
    }

    friend std::ostream& operator <<(std::ostream& os, Queue<T> const& q)
    {
        q.Print(os);
        return os;
    }
};

template <typename T>
class Stack : public NonCopyable
{
private:
    T * values;
    int dim;
    int top;
public:
    Stack(int L)
        : values( new T[L]() )
        , dim( L )
        , top( L )
    {
    }

    virtual ~Stack()
    {
        delete [] values;
    }

    void Push(T value)
    {
        if (top > 0)
        {
            values[--top]=value;
        }
        else
        {
            std::cerr << "Stack is Full!"<< std::endl;
        }
    }

    void Pop()
    {
        if (top < dim)
            ++top;
        else
            std::cerr<< "Stack is already empty"<< std::endl;
    }

    // queues all the items on the stack. resets the stack
    void Travasa(Queue <T>& A)
    {
        for(int i=top; i<dim; i++)
            A.Enqueue(values[i]);
        top = dim;
    }

    void Print(std::ostream& os) const
    {
        for (int i=top; i<dim; ++i)
            os << values[i] << ' ';
    }

    friend std::ostream& operator <<(std::ostream& os, Stack<T> const& st)
    {
        st.Print(os);
        return os;
    }
};


// int commands
void process_int(int N, std::istream& inp, std::ostream& outp)
{
    Queue<int> A(N);
    Stack<int> B(N);
    std::string op;

    while (N-- && inp >> op)
    {
        if(op == "travasa")
            B.Travasa(A);

        else if(op=="pop")
            B.Pop();

        else if(op=="dequeue")
            A.Dequeue();

        else if(op.substr(0,2)=="e:")
        {
            int elemento=stoi(op.substr(2));
            A.Enqueue(elemento);
        }

        else if(op.substr(0,2)=="p:")
        {
            B.Push(std::stoi(op.substr(2)));
        }
    }
    outp << A << '\n';
}

// char sequence
void process_char(int N, std::istream& inp, std::ostream& outp)
{
    Queue<char> A(N);
    Stack<char> B(N);
    std::string op;

    while (N-- && inp >> op)
    {
        if(op== "travasa")
            B.Travasa(A);

        else if(op=="pop")
            B.Pop();

        else if(op=="dequeue")
            A.Dequeue();

        else if(op.substr(0,2)=="e:")
            A.Enqueue(op[2]);

        else if(op.substr(0,2)=="p:")
            B.Push(op[2]);
    }

    outp << A << '\n';
}

// double sequence
void process_double(int N, std::istream& inp, std::ostream& outp)
{
    Queue<double> A(N);
    Stack<double> B(N);
    std::string op;

    while (N-- && inp >> op)
    {
        if(op== "travasa")
            B.Travasa(A);

        else if(op=="pop")
            B.Pop();

        else if(op=="dequeue")
            A.Dequeue();

        else if(op.substr(0,2)=="e:")
            A.Enqueue(std::stod(op.substr(2)));

        else if(op.substr(0,2)=="p:")
            B.Push(stod(op.substr(2)));
    }

    outp << A << '\n';
}

// bool sequence
void process_bool(int N, std::istream& inp, std::ostream& outp)
{
    Queue<int> A(N);
    Stack<int> B(N);
    std::string op;

    while (N-- && inp >> op)
    {
        if(op == "travasa")
            B.Travasa(A);

        else if(op == "pop")
            B.Pop();

        else if(op == "dequeue")
            A.Dequeue();

        else if(op.substr(0,2)=="e:")
            A.Enqueue(std::stoi(op.substr(2)));

        else if(op.substr(0,2)=="p:")
            B.Push(std::stoi(op.substr(2)));
    }

    outp << A << '\n';
}

int main()
{
    std::ifstream infile("input.txt");
    std::ofstream outfile("output.txt");

    // per line processing
    std::string line;
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        std::string type;
        int n;
        if (iss >> type >> n && n > 0)
        {
            if (type == "int")
                process_int(n, iss, outfile);

            else if (type == "char")
                process_char(n, iss, outfile);

            else if (type == "double")
                process_double(n, iss, outfile);

            else if (type == "bool")
                process_bool(n, iss, outfile);
        }
    }
}

输出文件

bool 10 e:0 p:0 p:1 travasa p:1 e:1 pop e:1 dequeue e:0
char 10 e:g p:k e:j e:h travasa p:f p:o e:n pop p:e
char 10 p:c travasa p:n dequeue travasa p:p e:o dequeue e:p travasa
int 10 e:7 p:88 p:42 pop pop e:82 e:12 p:54 e:49 travasa