一个简单的双向链表的例子

来源:互联网 发布:高考必知文学常识 编辑:程序博客网 时间:2024/06/09 20:02

题目描述:
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 <iostream>#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 <string>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,所以在这里报错。

0 0
原创粉丝点击