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

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

你可能感兴趣的:(CPP学习,数据结构)