问题:如何遍历单链表中的每个元素?
LinkList<int> list; for (int i=0; i<5; ++i) { list.insert(0, i); } for (int i=0; i<list.length(); ++i) { cout << list.get(i) << endl; }
遗憾的事实:node
- 不能以线性的时间复杂度完成单链表的遍历
新的需求ios
- 为单链表提供新的方法,在线性时间内完成遍历
- 在单链表的内部定义一个游标(Node *m_current)
- 遍历开始前将游标指向位置为0的数据元素
- 获取游标指向的数据元素
- 经过结点的 next 指针移动游标
提供一组遍历相关的函数,以线性的时间复杂度遍历链表。
函数 | 功能说明 |
move() | 将游标定位到目标位置 |
next() | 移动游标 |
current() | 获取游标所指向的数据元素 |
end() | 游标是否到达尾部(是否为空) |
- bool move(int i, int step = 1);
- bool end();
- T current();
- bool next();
文件:LinkList.h编程
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template <typename T> class LinkList : public List<T> { public: LinkList() { m_header.next = nullptr; m_length = 0; m_step = 1; m_current = nullptr; } bool insert(const T &e) override // O(n) { return insert(m_length, e); } bool insert(int i, const T &e) override // O(n) { bool ret = ((0 <= i) && (i <= m_length)); if (ret) { Node *node = new Node(); if (node != nullptr) { Node *current = position(i); node->value = e; node->next = current->next; current->next = node; ++m_length; } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element ..."); } } return ret; } bool remove(int i) override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { Node *current = position(i); Node *toDel = current->next; current->next = toDel->next; delete toDel; --m_length; } return ret; } bool set(int i, const T &e) override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { position(i)->next->value = e; } return ret; } T get(int i) const // O(n) { T ret; if (!get(i, ret)) { THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ..."); } return ret; } bool get(int i, T &e) const override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { e = position(i)->next->value; } return ret; } int find(const T &e) override // O(n) { int ret = -1; int i = 0; Node *node = m_header.next; while (node) { if (node->value == e) { ret = i; break; } else { node = node->next; ++i; } } return ret; } int length() const // O(1) { return m_length; } void clear() // O(n) { while (m_header.next) { Node *toDel = m_header.next; m_header.next = toDel->next; delete toDel; --m_length; } } bool move(int i, int step = 1) // O(n) { bool ret = ((0 <= i) && (i < m_length) && (step > 0)); if (ret) { m_current = position(i)->next; m_step = step; } return ret; } bool end() // O(1) { return (m_current == nullptr); } T current() // O(1) { if (!end()) { return m_current->value; } else { THROW_EXCEPTION(InvalidOpertionExcetion, " No value at current posotion ..."); } } bool next() // O(n) { int i = 0; while ((i < m_step) && !end()) { m_current = m_current->next; ++i; } return (i == m_step); } ~LinkList() // O(n) { clear(); } protected: struct Node : public Object { T value; Node *next; }; mutable struct : public Object { char reserved[sizeof (T)]; Node *next; }m_header; int m_length; int m_step; Node *m_current; Node *position(int i) const // O(n) { Node *ret = reinterpret_cast<Node*>(&m_header); for (int p=0; p<i; ++p) { ret = ret->next; } return ret; } }; } #endif // LINKLIST_H
文件:main.cppide
#include <iostream> #include "LinkList.h" using namespace std; using namespace DTLib; int main() { cout << "main begin" << endl; LinkList<int> list; for (int i=0; i<5; ++i) { list.insert(0, i); } for (list.move(0); !list.end(); list.next()) { cout << list.current() << endl; } cout << "main end" << endl; return 0; }
输出:函数
main begin 4 3 2 1 0 main end
virtual Node *create() { return new Node(); } virtual void destory(Node *pn) { delete pn; }
LinkList.hspa
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template <typename T> class LinkList : public List<T> { public: LinkList() { m_header.next = nullptr; m_length = 0; m_step = 0; m_current = nullptr; } bool insert(const T &e) override // O(n) { return insert(m_length, e); } bool insert(int i, const T &e) override // O(n) { bool ret = ((0 <= i) && (i <= m_length)); if (ret) { Node *node = create(); if (node != nullptr) { Node *current = position(i); node->value = e; node->next = current->next; current->next = node; ++m_length; } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element ..."); } } return ret; } bool remove(int i) override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { Node *current = position(i); Node *toDel = current->next; current->next = toDel->next; destroy(toDel); --m_length; } return ret; } bool set(int i, const T &e) override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { position(i)->next->value = e; } return ret; } T get(int i) const // O(n) { T ret; if (!get(i, ret)) { THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ..."); } return ret; } bool get(int i, T &e) const override // O(n) { bool ret = ((0 <= i) && (i < m_length)); if (ret) { e = position(i)->next->value; } return ret; } int find(const T &e) override // O(n) { int ret = -1; int i = 0; Node *node = m_header.next; while (node) { if (node->value == e) { ret = i; break; } else { node = node->next; ++i; } } return ret; } int length() const // O(1) { return m_length; } void clear() // O(n) { while (m_header.next) { Node *toDel = m_header.next; m_header.next = toDel->next; destroy(toDel); --m_length; } } bool move(int i, int step = 1) // O(n) { bool ret = ((0 <= i) && (i < m_length) && (step > 0)); if (ret) { m_current = position(i)->next; m_step = step; } return ret; } bool end() // O(1) { return (m_current == nullptr); } T current() // O(1) { if (!end()) { return m_current->value; } else { THROW_EXCEPTION(InvalidOpertionExcetion, " No value at current posotion ..."); } } bool next() // O(n) { int i = 0; while ((i < m_step) && !end()) { m_current = m_current->next; ++i; } return (i == m_step); } ~LinkList() // O(n) { clear(); } protected: struct Node : public Object { T value; Node *next; }; mutable struct : public Object { char reserved[sizeof (T)]; Node *next; }m_header; int m_length; int m_step; Node *m_current; Node *position(int i) const // O(n) { Node *ret = reinterpret_cast<Node*>(&m_header); for (int p=0; p<i; ++p) { ret = ret->next; } return ret; } virtual Node *create() { return new Node(); } virtual void destroy(Node *pn) { delete pn; } }; } #endif // LINKLIST_H
问题:封装 create 和 destroy 函数的意义是什么?
To be continued...设计
- 单链表的遍历须要在线性时间内完成
- 在单链表内部定义游标变量,经过游标变量提升效率
- 遍历相关的成员函数是相互依赖,相互配合的关系
- 封装结点的申请和删除操做更有利于加强扩展性
以上内容整理于狄泰软件学院系列课程,请你们保护原创!指针