問題:如何遍歷單鏈表中的每個元素?
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...設計
- 單鏈表的遍歷須要在線性時間內完成
- 在單鏈表內部定義遊標變量,經過遊標變量提升效率
- 遍歷相關的成員函數是相互依賴,相互配合的關係
- 封裝結點的申請和刪除操做更有利於加強擴展性
以上內容整理於狄泰軟件學院系列課程,請你們保護原創!指針