完成鏈式存儲結構線性表的實現
- 類模板,經過頭節點訪問後繼節點
- 定義內部節點類型 Node,用於描述數據域和指針域
- 實現線性表的關鍵操做(增,刪,查,等)
template <typename T> class LinkList : public List<T> { public: LinkList(); // ... protected: struct Node : public Object { T value; Node *next; }; Node m_header; int m_length; };
文件:LinkList.hnode
#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; } bool insert(const T &e) override { return insert(m_length, e); } bool insert(int i, const T &e) override { bool ret = ((0 <= i) && (i <= m_length)); if (ret) { Node *node = new Node(); if (node != nullptr) { Node *current = &m_header; for (int p=0; p<i; ++p) { current = current->next; } 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 { bool ret = ((0 <= i) && (i < m_length)); if (ret) { Node *current = &m_header; for (int p=0; p<i; ++p) { current = current->next; } Node *toDel = current->next; current->next = toDel->next; delete toDel; --m_length; } return ret; } bool set(int i, const T &e) override { bool ret = ((0 <= i) && (i < m_length)); if (ret) { Node *current = &m_header; for (int p=0; p<i; ++p) { current = current->next; } current->next->value = e; } return ret; } T get(int i) const { 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 { bool ret = ((0 <= i) && (i < m_length)); if (ret) { Node *current = &m_header; for (int p=0; p<i; ++p) { current = current->next; } e = current->next->value; } return ret; } int length() const { return m_length; } void clear() { while (m_header.next) { Node *toDel = m_header.next; m_header.next = toDel->next; delete toDel; --m_length; } } ~LinkList() { clear(); } protected: struct Node : public Object { T value; Node *next; }; mutable Node m_header; int m_length; }; } #endif // LINKLIST_H
文件:main.cppios
#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); list.set(0, i*i); } for (int i=0; i<list.length(); ++i) { cout << list.get(i) << endl; } cout << "------------" << endl; list.remove(2); for (int i=0; i<list.length(); ++i) { cout << list.get(i) << endl; } cout << "------------" << endl; list.clear(); for (int i=0; i<list.length(); ++i) { cout << list.get(i) << endl; } cout << "main end" << endl; return 0; }
輸出:編程
main begin 16 9 4 1 0 ------------ 16 9 1 0 ------------ main end
問題
頭節點是否存在隱患?
實現代碼是否須要優化?ide
insert, remove, get, set 等操做都設計元素定位
Node *current = &m_header; for (int p=0; p<i; ++p) { current = current->next; }
==>函數
Node *position(int i);
struct Node : public Object { T value; Node *next; };
==>佈局
class Test { public: Test() { throw 0; } };
會發生什麼呢?測試
int main() { cout << "main begin" << endl; LinkList<Test> list; cout << "main end" << endl; }
輸出:優化
main begin terminate called after throwing an instance of 'int'
使用者的疑問:
儘管 Test 類對象會拋出異常,但是我沒有定義 Test 對象,只是定義了 LinkList<Test> 對象,爲何會有異常被拋出呢?編碼
代碼分析:
=> LinkList<Test> list;
觸發成員對象的構造函數調用;
=> Node m_header;
觸發成員對象的構造函數被調用;
=> Test
(泛指類型) 構造函數被調用,異常拋出。spa
解決方案:
避免在構造頭節點 m_header 時對泛型對象 T 的構造,而又保證內存佈局與Node類對象相同。
==》
頭節點類型重定義。
struct Node : public Object { T value; Node *next; }; mutable struct : public Object { char reserved[sizeof (T)]; // 僅佔位用 Node *next; }m_header;
文件: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; } bool insert(const T &e) override { return insert(m_length, e); } bool insert(int i, const T &e) override { 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 { 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 { bool ret = ((0 <= i) && (i < m_length)); if (ret) { position(i)->next->value = e; } return ret; } T get(int i) const { 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 { bool ret = ((0 <= i) && (i < m_length)); if (ret) { e = position(i)->next->value; } return ret; } int length() const { return m_length; } void clear() { while (m_header.next) { Node *toDel = m_header.next; m_header.next = toDel->next; delete toDel; --m_length; } } ~LinkList() { 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; Node *position(int i) const { Node *ret = reinterpret_cast<Node*>(&m_header); for (int p=0; p<i; ++p) { ret = ret->next; } return ret; } }; } #endif // LINKLIST_H
文件:main.cpp
#include <iostream> #include "LinkList.h" using namespace std; using namespace DTLib; class Test { public: Test() { throw 0; } }; int main() { cout << "main begin" << endl; LinkList<Test> list; cout << "main end" << endl; return 0; }
輸出:
main begin main end
- 經過類模板實現鏈表,包含頭節點成員和長度成員
- 定義節點類型,並經過堆中的節點對象構造鏈式存儲
- 爲了不構造錯誤的隱患,頭節點類型須要重定義
- 代碼優化是編碼完成後必不可少的環節
提示:只要代碼發生改動,就須要從新測試
以上內容整理於狄泰軟件學院系列課程,請你們保護原創!