我必须实现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;
}
}
}
答案 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
是调用方参数的默认副本。A
和调用方变量)都具有指向 same 数据的动态指针。当其中一个释放后,另一个将悬空指针留下,进一步的解除引用会导致未定义的行为。以适应特定问题。 Travesa
应该以{{1}}作为参考。显然正在修改它。后来。我们可以支持两个类模板A
和Queue
,以确保它们不再允许这种错误。
首先是成员函数:
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