问题描述
所以我正在使用迭代器遍历堆栈和队列列表,我需要修改它们。我尝试取消引用迭代器,然后使用 pop 和 push 但对象没有改变。
我认为问题在于函数 Push 和 Pop(不是堆栈和队列的成员函数),但我可能是错的。实际的程序接收一个带有命令的文件,但我修改了它,以便它接收单行命令。
这是代码的可重现版本:
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;
#include <list>
template <class T>
class SimpleList
{
struct Node
{
T data;
Node* next;
Node(T datI,Node* nextI)
{
data = datI;
next = nextI;
}
};
public:
Node* start;
int size;
Node* end;
std::string name;
SimpleList(std::string title)
{
name = title;
size = 0;
}
void addFront(T element)
{
Node *temp = new Node(element,start);
if (size == 0) {end = temp;}
if (size == 1) {(*start).next = end;}
if (size > 1) {(*temp).next = start;}
start = temp;
size ++;
}
void addEnd(T element)
{
Node *temp = new Node(element,NULL);
if (size == 0) {start = temp;}
end = temp;
if(size > 0) {(*end).next = temp;}
size ++;
}
T* remove()
{
if (size == 0) {return 0;}
T *temp = &((*start).data);
start = (*start).next;
size --;
if (size == 1) {start = end;}
return temp;
}
virtual void push(T element) {}
virtual T pop() { return *(remove()); }
};
template <class T>
class Stack :public SimpleList<T>
{
public:
Stack(std::string title): SimpleList<T>(title) {}
void push(T element){SimpleList<T>::addFront(element);}
};
template <class T>
class Queue :public SimpleList<T>
{
public:
Queue(std::string title): SimpleList<T>(title) {}
void push(T element){SimpleList<T>::addEnd(element);}
};
std::list<SimpleList<std::string> > liI;
std::list<SimpleList<std::string> > liD;
std::list<SimpleList<std::string> > liS;
bool IsIn(std::string title,std::list<SimpleList<std::string> > li)
{
std::list<SimpleList<std::string> >::iterator it;
for (it = li.begin(); it != li.end(); ++it)
{
std::string temp = it -> name;
if(temp == title){return true;}
}
return false;
}
std::string Pop(std::vector<std::string> para,std::list<SimpleList<std::string> > *li)
{
if(!IsIn(para[1],*li)) { return "\nERROR: This name does not exist!\n";}
std::list<SimpleList<std::string> >::iterator it;
for (it = (*li).begin(); it != (*li).end(); ++it)
{
if(it -> name == para[1])
{
return "\nValue popped: " + (*it).pop() + "\n";
}
}
return "";
}
std::string Push(std::vector<std::string> para,*li)) { return "\nERROR: This name does not exist!\n";}
std::list<SimpleList<std::string> >::iterator it;
for (it = (*li).begin(); it != (*li).end(); ++it)
{
if(it -> name == para[1])
{
(*it).push(para[2]);
return "\n";
}
}
return "";
}
std::string Create(std::vector<std::string> para,std::list<SimpleList<std::string> > *li)
{
if(IsIn(para[1],*li)) { return "\nERROR: This name already exists!\n";}
if (para[2] == "stack")
{
Stack<std::string> temp = Stack<std::string>(para[1]);
(*li).push_back(temp);
}
else
{
Queue<std::string> temp = Queue<std::string>(para[1]);
(*li).push_back(temp);
}
return "\n";
}
std::string Processing(std::vector<std::string> para)
{
std::string message;
if (para[0] == "create")
{
if (para[1][0] == 'i') {message = Create(para,&liI);}
if (para[1][0] == 's') {message = Create(para,&liS);}
else {message = Create(para,&liD);}
}
if (para[0] == "push")
{
if (para[1][0] == 'i') {message = Push(para,&liI);}
if (para[1][0] == 's') {message = Push(para,&liS);}
else {message = Push(para,&liD);}
}
if (para[0] == "pop")
{
if (para[1][0] == 'i') {message = Pop(para,&liI);}
if (para[1][0] == 's') {message = Pop(para,&liS);}
else {message = Pop(para,&liD);}
}
return message;
}
int main()
{
std::vector<std::string> vec;
vec.push_back("create");
vec.push_back("i1");
vec.push_back("queue");
std::cout << Processing(vec);
vec.clear();
vec.push_back("push");
vec.push_back("i1");
vec.push_back("500");
std::cout << Processing(vec);
vec.clear();
vec.push_back("pop");
vec.push_back("i1");
std::cout << Processing(vec);
return 0;
}
解决方法
为了让程序更好地运行,我做了我认为最少的更改。一般来说,这只不过是应用您现在应该已经学会的最佳实践。您的 add*()
函数中有几个地方正在执行一些无意义的操作。
链接列表极大地从绘图中受益。画出算法的步骤,然后编码。如果它不起作用,您可以通过一系列图片轻松找到您的代码分歧点。
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// using namespace std; // CHANGED: Bad practice
#include <list>
template <class T> // CHANGED: Removed blank line
class SimpleList {
struct Node {
T data = T(); // CHANGED: added default member initialization
Node* next = nullptr;
// Node(T datI,Node* nextI) // CHANGED: Unncecessary; hinders
// { // aggregate initialization
// data = datI;
// next = nextI;
// }
};
// Not changing for now,but traditionally linked lists have a head and tail
Node* start = nullptr; // CHANGED: Added default member initialization
int size = 0;
Node* end = nullptr;
std::string name;
public: // CHANGED: Made list data private
SimpleList(std::string title)
: name(title) {} // CHANGED: use ctor
// initialization sections
std::string get_name() const { return name; } // Added getter for name
void addFront(T element) {
// NOTE: Use nullptr in C++,not NULL
Node* temp = new Node{element}; // CHANGED: Used aggregate initialization
if (size == 0) end = temp;
// if (size == 1) start->next = end; // CHANGED: Makes no sense
if (size > 1) temp->next = start; // CHANGED: Arrow notation
start = temp;
size++;
}
void addEnd(T element) {
// Similar changeas as above
Node* temp = new Node{element};
if (size == 0) start = temp;
end = temp;
if (size > 0) end->next = temp;
size++;
}
// Function broken as delivered; remove WHAT?
// CHANGED: Reading the body implies that the function is poorly named,so
// changed the name
T pop_front() {
if (size == 0) return nullptr; // CHANGED: Fixed return type
T temp = start->data; // CHANGED: Copy data held in start
Node* tmpNode = start; // CHANGED: Need to track original start
start = start->next;
delete tmpNode; // CHANGED: Actually get rid of node
size--; // CHANGED: Remove space
// if (size == 1) start = end; // CHANGED: Makes no sense
// NOTE: pop functions should only delete,not provide the data
// You provide the data,and never delete
return temp;
}
// virtual void push(T element) {} // ???
// virtual T pop() { return *(remove()); } // ???
};
template <class T> // CHANGED: Removed blank line
class Stack : public SimpleList<T> {
public:
Stack(std::string title) : SimpleList<T>(title) {}
void push(T element) { SimpleList<T>::addFront(element); }
};
template <class T> // CHANGED: Removed blank line
class Queue : public SimpleList<T> {
public:
Queue(std::string title) : SimpleList<T>(title) {}
void push(T element) { SimpleList<T>::addEnd(element); }
};
// CHANGED: Moving randomly placed globals into main()
// std::list<SimpleList<std::string> > liI;
// std::list<SimpleList<std::string> > liD;
// std::list<SimpleList<std::string> > liS;
bool IsIn(std::string title,std::list<SimpleList<std::string>> li) {
// CHANGED: Moved declartion into for loop with auto
// std::list<SimpleList<std::string> >::iterator it;
for (auto it = li.begin(); it != li.end(); ++it) {
std::string temp = it->get_name(); // CHANGED: removed spacing around arrow
if (temp == title) return true;
}
return false;
}
// CHANGED: Changed parameter from pointer to list to reference to list
std::string Pop(std::vector<std::string> para,std::list<SimpleList<std::string>>& li) {
if (!IsIn(para[1],li)) {
return "\nERROR: This name does not exist!\n";
}
// std::list<SimpleList<std::string> >::iterator it;
for (auto it = (li).begin(); it != (li).end(); ++it) {
if (it->get_name() == para[1]) {
// CHANGED: Cleaned up and fixed return statement
return "\nValue popped: " + it->pop_front() + "\n";
}
}
return "";
}
// CHANGED: Changed parameter from pointer to list to reference to list
std::string Push(std::vector<std::string> para,li)) {
return "\nERROR: This name does not exist!\n";
}
std::list<SimpleList<std::string>>::iterator it;
for (it = (li).begin(); it != (li).end(); ++it) {
if (it->get_name() == para[1]) {
it->addEnd(para[2]); // Changed to correct call
return "\n";
}
}
return "";
}
// CHANGED: Change parameter from pointer to list to reference to list
std::string Create(std::vector<std::string> para,std::list<SimpleList<std::string>>& li) {
if (IsIn(para[1],li)) {
return "\nERROR: This name already exists!\n";
}
if (para[2] == "stack") {
Stack<std::string> temp = Stack<std::string>(para[1]);
(li).push_back(temp);
} else {
Queue<std::string> temp = Queue<std::string>(para[1]);
(li).push_back(temp);
}
return "\n";
}
// CHANGED: In attempting to make minimal changes,this is going into main()
// as a lambda
// std::string Processing(std::vector<std::string> para)
// {
// std::string message;
// if (para[0] == "create")
// {
// if (para[1][0] == 'i') {message = Create(para,liI);}
// if (para[1][0] == 's') {message = Create(para,liS);}
// else {message = Create(para,liD);}
// }
// if (para[0] == "push")
// {
// if (para[1][0] == 'i') {message = Push(para,liI);}
// if (para[1][0] == 's') {message = Push(para,liS);}
// else {message = Push(para,liD);}
// }
// if (para[0] == "pop")
// {
// if (para[1][0] == 'i') {message = Pop(para,liI);}
// if (para[1][0] == 's') {message = Poppara,liS);}
// else {message = Pop(para,liD);}
// }
// return message;
// }
int main() {
std::list<SimpleList<std::string>> liI;
std::list<SimpleList<std::string>> liD;
std::list<SimpleList<std::string>> liS;
auto Processing = [&liI,&liD,&liS](std::vector<std::string> para) {
std::string message;
if (para[0] == "create") {
if (para[1][0] == 'i') {
message = Create(para,liI);
}
if (para[1][0] == 's') {
message = Create(para,liS);
} else {
message = Create(para,liD);
}
}
if (para[0] == "push") {
if (para[1][0] == 'i') {
message = Push(para,liI);
}
if (para[1][0] == 's') {
message = Push(para,liS);
} else {
message = Push(para,liD);
}
}
if (para[0] == "pop") {
if (para[1][0] == 'i') {
message = Pop(para,liI);
}
if (para[1][0] == 's') {
message = Pop(para,liS);
} else {
message = Pop(para,liD);
}
}
return message;
};
std::vector<std::string> vec;
vec.push_back("create");
vec.push_back("i1");
vec.push_back("queue");
std::cout << Processing(vec);
vec.clear();
vec.push_back("push");
vec.push_back("i1");
vec.push_back("500");
std::cout << Processing(vec);
vec.clear();
vec.push_back("pop");
vec.push_back("i1");
std::cout << Processing(vec);
return 0;
}
注意:我没有进行广泛的测试,但我不需要做任何测试就可以说它不是一个好地方。您缺少析构函数和其他 5 规则函数,这意味着您将制作浅拷贝并泄漏内存。值得称赞的是,您编写了一个类,而没有编写 C 风格的链表。
我也通过clang-format运行代码,因为样式不一致。虽然这可能会使您的代码按原样工作,但我会注意到缺乏整体设计。您对 Stack
和 Queue
使用继承,这毫无意义。我可以用链表、向量、静态数组等来实现堆栈。要说 Stack
是 底层数据结构是......嗯。通过使用继承,您还可以为您的 Stack
和 Queue
提供您的链表的所有公共功能,而它们不应该拥有这些功能。例如,您的 Stack
可以添加到前面和后面。
更好的是,使用组合。在您的 Stack
中私下持有一个链表。现在,您的 Stack
用户现在可以正确地限制为只能使用 Stack
功能,而不是拥有对链表公共功能的完全访问权限。