题目描述:
Implement the class with given header.
As you guess, DouList means 逗list, very funny.
to_str() function means displaying the list with std::string, formating like [1, 2, 3, 4] , [2] or [] (empty list)(notice white-space)
operator<< means output the string from ‘to_str()’
struct DouListNode is the node of DouList.
if you have any doubt in function of the member methods, take a look at STL.
中文描述概要:
0 大概是让你实现一个双头列表。
1 如果对成员函数的作用有疑问,参照STL的常规含义。
2 to_str()就是把list输出成标准字符串的形式。operator<<则打印to_str()得到的字符串。
测试文件:
//created by my TA
#include
#include "DouList.h"
using namespace std;
DouList list1, list2;
void display() {
cout << list1.empty() << ':' << list1 << endl;
cout << list2.empty() << ':' << list2.to_str() << endl;
}
int main() {
display();
list1.push_front(894);
list2.push_back(2136);
cout << list1.front() << ',' << list1.back() << endl;
cout << list2.front() << ',' << list2.back() << endl;
display();
list1.push_back(214);
list2.push_front(931);
cout << list1.front() << ',' << list1.back() << endl;
cout << list2.front() << ',' << list2.back() << endl;
display();
for (int i = 0; i < 10; ++i) {
int t;
cin >> t;
list1.push_back(t);
list2.push_front(t);
}
display();
for (int i = 0; i < 5; ++i) {
list1.pop_front();
list2.pop_back();
}
display();
DouList list3(list1);
list1 = list2;
cout << list1 << endl;
cout << list3 << endl;
return 0;
}
解决代码:
头文件:
#ifndef SSCPP2014_DOULIST_A_H
#define SSCPP2014_DOULIST_A_H
#include
struct DouListNode {
int elem;
DouListNode *prev, *next;
DouListNode(int e = 0, DouListNode *p = 0, DouListNode *n = 0) {
elem = e;
prev = p;
next = n;
}
};
class DouList {
private:
DouListNode *m_head, *m_tail;
public:
DouList();
DouList(const DouList &src);
~DouList();
void clear();
bool empty() const;
std::string to_str() const;
int front() const;
int back() const;
void push_front(const int &e);
void push_back(const int &e);
void pop_front();
void pop_back();
void operator=(const DouList &other);
friend std::ostream& operator<<(std::ostream &out,
const DouList &list);
// non-meaning static value
static int _error_sign; // for illegal front()/back()
};
#endif
具体实现的cpp文件:
#include "DouList.h"
#include "sstream"
using namespace std;
DouList::DouList() {m_head = NULL, m_tail = NULL;}
DouList::DouList(const DouList &src) {
m_head = m_tail = NULL;
*this = src;}
DouList::~DouList() {clear();}
void DouList::operator=(const DouList &other) {
clear();
if (other.m_head != NULL) {
DouListNode *current = new DouListNode(other.m_head->elem), *prev;
DouListNode *temp = other.m_head;
m_head = current;
while (temp->next != NULL) {
temp = temp->next;
prev = current;
current = new DouListNode(temp->elem);
current->prev = prev;
prev->next = current;
}
m_tail = current;
}
}
void DouList::clear() {
if (m_head != NULL) {
DouListNode* p = m_head, *temp;
while (p != NULL) {
temp = p;
p = p->next;
delete temp;
}
m_head = m_tail = NULL;
}
}
bool DouList::empty() const {return (m_head == NULL) ? true : false;}
string DouList::to_str() const {
string str, temp;
stringstream ss;
str += "[";
DouListNode* t = m_head;
if (t == NULL) {
str += "]";
return str;
}
while (t->next != NULL) {
ss << t->elem;
ss >> temp;
str += temp + ", ";
temp = "", ss.clear();
t = t->next;
}
ss << t->elem;
ss >> temp;
str += temp + "]";
return str;
}
int DouList::front() const {if (m_head != NULL) return m_head->elem;}
int DouList::back() const {if (m_tail != NULL) return m_tail->elem;}
void DouList::push_front(const int &e) {
if (m_head == NULL) {
m_head = new DouListNode(e);
m_tail = m_head;
return;
}
DouListNode *temp = new DouListNode(e);
temp->next = m_head;
m_head->prev = temp;
m_head = temp;
}
void DouList::push_back(const int &e) {
if (m_tail == NULL) {
m_tail = new DouListNode(e);
m_head = m_tail;
return;
}
DouListNode *temp = new DouListNode(e);
temp->prev = m_tail;
m_tail->next = temp;
m_tail = temp;
}
void DouList::pop_front() {
if (m_head == NULL) return;
DouListNode *temp = m_head;
m_head = m_head->next;
if (m_head == NULL) {
m_tail = NULL;
delete temp;
return;
}
m_head->prev = NULL;
delete temp;
}
void DouList::pop_back() {
if (m_tail == NULL) return;
DouListNode *temp = m_tail;
m_tail = m_tail->prev;
if (m_tail == NULL) {
m_head = NULL;
delete temp;
return;
}
m_tail->next = NULL;
delete temp;
}
std::ostream& operator<<(std::ostream &out, const DouList &list) {
out << list.to_str();
return out;
}
下面是写这道题的过程中的一些记录,包括遇到的错误、心得体会、积累的经验等。
一直出现memory limit error的错误,用GDB检查它一直报clear()函数出现错误,可是实际上这个函数并没有问题,说明一定是其他原因导致了这个函数出现了错误,然后系统到这里才检测到。
经过查找,这次的原因,一个是在某些地方忘了把head和tail赋值为NULL,改完之后发现还是memory limit error,说明还有其他错误。最后发现是拷贝函数那里,
DouList::DouList(const DouList &src) {*this = src;}
这个函数,忘了考虑如果src的head是NULL的话,我的重载 “=”是不会把this的head和tail给初始化为NULL的。
由此得到两个教训:
1、永远都要记得初始化成员变量,不管你是否需要用到。
2、一个函数直接调用另一个函数的时候要考虑到,这两个是否完全
等价,即是不是增加一些其他的条件。
比如这里的DouList::DouList(const DouList &src) {*this = src;}
“+”没有考虑到src的head是NULL,所以正确的应该是:
DouList::DouList(const DouList &src) {
m_head = m_tail = NULL;
*this = src;
}//先初始化成员变量,谨慎一点。
至于一直MLE为什么GDB 报的是clear这个函数的问题:
void DouList::clear() {
if (m_head != NULL) {
DouListNode* p = m_head, *temp;
while (p != NULL) {
temp = p;
p = p->next;
delete temp;
}
m_head = m_tail = NULL;
}
}
这个函数中p = p->next;这一行的错误,发现原因之后很好解释:
如果main函数调用了DouList(const DouList &src)
函数,
如DouList list3(list1);
而list1又刚好是NULL,那就会出现head和tail没初始化的情况,自然很大程度上也不可能随机到NULL,所以clear的时候,因为p != NULL,所以继续进行下去,发现p = p->next,p根本没有next,所以在这里报错。