双向链表(c++实现)
2018-02-02 18:14
155 查看
单向链表的缺点:逆序访问单向链表中的数据元素,效率低下。
若从头节点开始依次访问单向链表的元素,可使用m_current游标,但是逆序访问,只能通过下面代码实现访问:
这种方式,遍历操作的时间复杂度是插入操作的平方,要做代码优化,那就和单向链表的正序访问一样,逆序访问就需要一个可以逆序移动的迭代器,即构成一个双向链表:在单向链表的每一个节点增加一个指针域,用于指向当前节点的前节点的位置。
在软件设计上,因为双向链表的节点类型已经和单向链表不同,所以双向链表不能继承自单向链表,只可以继承自抽象类List。(List原型见单向链表(c++实现) )
编译运行:
若从头节点开始依次访问单向链表的元素,可使用m_current游标,但是逆序访问,只能通过下面代码实现访问:
int main(void) { LinkList<int> ll; for (int i = 0; i < 6; ++i) //O(n) { ll.insert(0, i); } for (int i = ll.length() - 1; i >= 0; --i) //O(n^2) { cout << ll.get(i) << nedl; } return 0; }
这种方式,遍历操作的时间复杂度是插入操作的平方,要做代码优化,那就和单向链表的正序访问一样,逆序访问就需要一个可以逆序移动的迭代器,即构成一个双向链表:在单向链表的每一个节点增加一个指针域,用于指向当前节点的前节点的位置。
在软件设计上,因为双向链表的节点类型已经和单向链表不同,所以双向链表不能继承自单向链表,只可以继承自抽象类List。(List原型见单向链表(c++实现) )
#ifndef __DUALLINKLIST_H__ #define __DUALLINKLIST_H__ #include "LinkList.h" #include <stdexcept> template<typename T> class DualLinkList : public List<T> { protected: struct Node_t //节点的类型 { T value; Node_t *next; Node_t *pre; }; mutable struct { //头节点变量,内存布局和Node_t一致 char reserved[sizeof(T)]; Node_t *next; Node_t *pre; }m 4000 _header; int m_length; int m_step; //next()或pre()每次移动的步长 Node_t* m_current; //游标,方便遍历 Node_t* _position(int i) const //定位目标位置 { Node_t *ret = reinterpret_cast<Node_t*>(&m_header); for (int p = 0; p < i; ++p) { ret = ret->next; } return ret; } //动态分配节点,定义为虚函数,方便派生类继承自本类时修改分配方式,如静态分配内存实现内存池 virtual Node_t* CreateNode() { return new Node_t(); } virtual void DestroyNode(Node_t *p) { delete p; } public: DualLinkList() { m_header.next = NULL; m_header.pre = NULL; m_length = 0; m_step = 1; m_current = NULL; } bool insert(int i, const T& e) { bool ret = ((i >= 0) && (i <= m_length)); if (ret) { Node_t *node = CreateNode(); if (node) { //确定目标地址 Node_t* current = _position(i); Node_t* next = current->next; node->value = e; node->next = next; current->next = node; //插入的位置不是首节点 if (current != reinterpret_cast<Node_t*>(&m_header)) node->pre = current; else node->pre = NULL; //插入的位置不是末节点 if (next != NULL) next->pre = node; ++m_length; } } else { throw(std::out_of_range("LinkList::insert(): i of randge")); } return ret; } bool insert(const T& e) { return insert(m_length, e); } bool remove(int i) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { //确定目标位置 Node_t* current = _position(i); Node_t* toDel = current->next; Node_t* next = toDel->next; //若删除的位置正是游标m_current所指向,需要将m_current移动到有效位置 if (m_current == toDel) { m_current = next; } current->next = next; if (next != NULL) //删除的不是末节点 { next->pre = toDel->pre; } --m_length; DestroyNode(toDel); } return ret; } bool set(int i, const T& e) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { _position(i)->next->value = e; } return ret; } bool get(int i, T& e) const { bool ret = ((0 <= i) && (i < m_length)); if (ret) { e = _position(i)->next->value; } return ret; } //这是LinkList<T>没有的函数,定义为虚函数方便派生类基层发生多态 virtual T get(int i) const { T ret; if (i, ret) return ret; else throw(std::out_of_range("LinkList::insert(): i of randge")); } int find(const T& e) const { int ret = -1; int i = 0; Node_t* node = m_header.next; while (node) { if (node->value == e) { ret = i; break; } else { node = node->next; ++i; } } return ret; } int length() const { return m_length; } void clear() { while (m_length > 0) remove(0); } virtual bool move(int i, int step = 1) //设置游标的位置 { bool ret = ((0 <= i) && (i < m_length) && (step > 0)); if (ret) { m_current = _position(i)->next; m_step = step; } return ret; } virtual bool end() { return m_current == NULL; } virtual T current() { if (!end()) { return m_current->value; } else { throw(std::runtime_error("DualLinkList is NULL...")); } } //移动游标至下一个步长的位置 virtual bool next() { int i = 0; while ((i < m_step) && !end()) { m_current = m_current->next; ++i; } return (i == m_step); } //移动游标至上一个步长的位置 virtual bool pre() { int i = 0; while ((i < m_step) && !end()) { m_current = m_current->pre; ++i; } return (i == m_step); } ~DualLinkList() { clear(); } }; #endif /* __DUALLINKLIST_H__ */ //main.cpp int main(void) { DualLinkList<int> dl; //插入数据 for (int i = 0; i < 6; ++i) { dl.insert(0, i + 2); dl.insert(0, 16); } //顺序打印数据 for (dl.move(0); !dl.end(); dl.next()) { cout << dl.current() << " "; } cout << endl; //删除目标数据 dl.move(dl.length() - 1); while (!dl.end()) { if (dl.current() == 16) { dl.remove(dl.find(dl.current())); } else dl.pre(); } //顺序打印数据 for (dl.move(0); !dl.end(); dl.next()) { cout << dl.current() << " "; } cout << endl; //逆序打印数据 for (dl.move(dl.length() - 1); !dl.end(); dl.pre()) { cout << dl.current() << " "; } cout << endl; getchar(); return 0; }
编译运行:
相关文章推荐
- 双向链表的c++实现
- c++用双向链表实现模板栈
- 双向链表基础操作C++实现
- C++实现双向链表(含头结点)
- 双向链表(c++实现)
- c++顺序表与双向链表实现
- 双向链表的c++实现
- 双向链表(c++实现)
- 双向链表基础操作C++实现
- 双向链表(C++实现)
- 深入解析C++的循环链表与双向链表设计的API实现
- 双向链表的c++实现
- C++双向链表实现
- 双向链表基础操作C++实现
- 用C++实现双向链表代码
- 双向链表的c++实现
- c++中的双向链表写法,主要实现(增删查改,链表逆置,构造函数,运算符重载,等)
- 一个简单的双向链表(C++实现)
- 双向链表基础操作C++实现
- c++中的双向链表写法,主要实现(增删查改,链表逆置,构造函数,运算符重载,等)