double linked list双向链表

[tags] C++

双向链表的实现(与单向链表相近)

1. 节点结构体
struct DouListNode {
  int elem;
  DouListNode *prev, *next;
  DouListNode(int e = 0, DouListNode *p = 0, DouListNode *n = 0) {
    elem = e;
    prev = p;
    next = n;
  }
};
2. 类声明
class DouList {
  private:
    DouListNode *m_head, *m_tail;
  public:
    DouList();
    DouList(const DouList &src);
    ~DouList();
    void clear();
    bool empty() const;
    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 ostream& operator<<(ostream &out,
           const DouList &list);
    // non-meaning static value
    static int _error_sign;  // for illegal front()/back()
};

(1)构造函数

DouList::DouList() {
  m_head = NULL;
  m_tail = NULL;
}
DouList::DouList(const DouList& src) {
  m_head = NULL; 
  m_tail = NULL;
  *this = src;
}

**注意拷贝构造函数中要写m_head = NULL; m_tail = NULL;
每次定义一个成员函数都要考虑特殊值和边界情况
此处调用了重载运算符=

拷贝构造函数是关键,每次出现内存问题都应当重点检查拷贝构造函数
(2)重载运算符=

void DouList::operator=(const DouList& other) {
  this->clear();  //  先进行清空
  if (other.empty()) return;  //  把不满足的情况先挡在外边,排除掉
  m_head = new DouListNode(other.front());  // 里面的other.front()虽说可以直接用m_head并且也不麻烦,但是这样更加符合代码的可读性,尽量用上类中的成员函数,可以使代码更加的简洁
  DouListNode* p = other.m_head->next;
  DouListNode* q = m_head;
  while (p != NULL) {
    q->next = new DouListNode(p->elem, q, NULL);
    p = p->next;
    q = q->next;
  }
  m_tail = q;
}

(3)清空,析构中直接调用clear()即可

void DouList::clear() {
  if (!empty()) {
    DouListNode* p = m_head;
    while (p != NULL) {
      DouListNode* t = p;
      p = p->next;
      delete t;
    }
  }
  m_head = m_tail = NULL;
}
DouList::~DouList() {
  clear();
}

(4)空链表的判断,当头节点和尾节点为同一节点时为空

bool DouList::empty() const {
  return (m_head == NULL && m_tail == NULL);
}

(5)打印的形式

string DouList::to_str() const {
  string result = "[";
  if (m_head == NULL&&m_tail == NULL) {
    result += "]";
  } else {
    stringstream ss1;
    ss1 << m_head->elem;
    result +=  ss1.str();
    DouListNode* p = m_head->next;
    while(p != NULL) {
      stringstream ss;
      ss << p->elem;
      result += ", " + ss.str();
      p = p->next;
    }
    result += "]";
  }
  return result;
}

(6)获得元素(m_head->elem 和m_tail->elem)

int DouList::front() const {
  if (m_head != NULL) return m_head->elem;
}
int DouList::back() const {
  if (m_tail != NULL) return m_tail->elem;
}

(7)从链表的头插入元素(重要)

void DouList::push_front(const int& e) {
//  首先考虑特殊情况,要养成首先考虑特殊情况的好习惯,或者是写完一个函数后重新考虑是否漏掉了特殊情况,这样就不会出现一大堆的内存问题
  if (m_head == NULL && m_tail == NULL) {
    DouListNode* t = new DouListNode(e);
    m_head = m_tail = t;
    return;
  }
  DouListNode* t = new DouListNode(e, NULL, m_head);
  m_head->prev = t;
  m_head = t;
}

(8)从链表的尾插入元素(重要)

void DouList::push_back(const int& e) {
// 考虑特殊情况,与从头插入相同
  if (m_head == NULL && m_head == NULL) {
    DouListNode* t = new DouListNode(e);
    m_head = m_tail = t;
    return;
  }
  DouListNode* t = new DouListNode(e, m_tail, NULL);
  m_tail->next = t;
  m_tail = t;
}

(9)从头pop(重要)

void DouList::pop_front() {
  if (m_head == NULL && m_tail == NULL) return;
  DouListNode* t = m_head;
  m_head = m_head->next;
  m_head->prev = NULL;
  delete t;
}

(10)从尾pop(重要)

void DouList::pop_back() {
  if (m_head == NULL&&m_tail == NULL) return;
  DouListNode* t = m_tail;
  m_tail = m_tail->prev;
  m_tail->next = NULL;
  delete t;
}

(11)友元函数

std::ostream& operator<<(std::ostream& out, const DouList& list) {
  out << list.to_str();
  return out;
}

记得不能写成:ostream& DouList::operator<<(std::ostream& out, const DouList& list)
会报错:
‘std::ostream& DouList::operator<<(std::ostream&, const DouList&)’ must take exactly one argument
因为友元函数不属于该类

总结

  1. 在写每一个成员函数的时候首先应该想清楚特殊情况和边界情况, 尽量避免出现过多的内存问题
  2. 学会利用已有的成员函数,增加代码的可读性,同时也简化代码
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值