1、课程目标
— 完成链式存储结构线性表的实现
LinkList 设计要点 — 类模板,通过头结点访问后继节点 — 定义内部结点类型 Node,用于描述数据域和指针域 — 实现线性表的关键操作(增,删,查,等)LinkList 的定义LinkList 的实现:
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template <typename T> class LinkList : public List<T> { protected: struct Node : public Object { T value; Node* next; }; mutable Node m_header; int m_length; public: LinkList() { m_header.next = nullptr; m_length = 0; } bool insert(const T& e) { return insert(m_length, e); } bool insert(int i, const T& e) { bool ret = (i >= 0 && 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 the Linklist"); } } return ret; } bool remove(int i) { bool ret = (i >= 0 && 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) { bool ret = (i >= 0 && 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)) { return ret; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is Invalid"); } } bool get(int i, T& e)const { bool ret = (i >= 0 && i < m_length); //这个函数是一个const成员函数,const成员函数内部的成员变量是只读的,所以我们不能直接赋值,解决方法是用mutable修饰成员变量m_header,使它可以被访问。 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 != nullptr) { Node* toDel = m_header.next; m_header.next = toDel->next; delete toDel; } m_length = 0; } ~LinkList() { clear(); } }; } #endif // LINKLIST_Hmain.cpp
#include <iostream> #include "LinkList.h" using namespace std; using namespace DTLib; int main() { LinkList<int> sl; for(int i = 0; i < 5; i++) { sl.insert(0, i); sl.set(0, i*i); } for(int i = 0; i < sl.length(); i++) { int e = 0; if(sl.get(i, e)) { cout << e << endl; } } cout << endl; sl.clear(); for(int i = 0; i < sl.length(); i++) { cout << sl.get(i) << endl; } return 0; }2、单链表的具体实现
问题 头结点是否存在隐患?实现代码是否需要优化?
头结点的隐患
代码优化
LinkList 的实现:
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template <typename T> class LinkList : public List<T> { 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; } public: LinkList() { m_header.next = nullptr; m_length = 0; } bool insert(const T& e) { return insert(m_length, e); } bool insert(int i, const T& e) { bool ret = (i >= 0 && 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 the Linklist"); } } return ret; } bool remove(int i) { bool ret = (i >= 0 && 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) { bool ret = (i >= 0 && i < m_length); if(ret) { position(i)->next->value = e; } return ret; } T get(int i)const { T ret; if(get(i, ret)) { return ret; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is Invalid"); } } bool get(int i, T& e)const { bool ret = (i >= 0 && i < m_length); if(ret) { //这个函数是一个const成员函数,const成员函数内部的成员变量是只读的,所以我们不能直接赋值,解决方法是用mutable修饰成员变量m_header,使它可以被访问。 e = position(i)->next->value; } return ret; } int length()const { return m_length; } void clear() { while(m_header.next != nullptr) { Node* toDel = m_header.next; m_header.next = toDel->next; delete toDel; } m_length = 0; } ~LinkList() { clear(); } }; } #endif // LINKLIST_Hmain.cpp
#include <iostream> #include "LinkList.h" using namespace std; using namespace DTLib; class Test { public: Test() { throw(0); } }; int main() { LinkList<Test>a; cout << "xiebs" << endl; 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; } return 0; } 小结 — 通过类模板实现链表,包含 头结点成员 和 长度成员 — 定义结点类型,并通过堆中的节点对象构成链式存储 — 为了避免构成错误的隐患,头结点类型需要重新定义 — 代码优化是编码完成后必不可少的环节position(0) 指向头结点,position(1) 指向首结点,position(1).value 是第0个结点的value值,position(1).next 指向第一个结点。以此类推。
position(i) ,对应于指针指向 i 前面那个结点。
所以指针指向尾结点就是 position(m_length - 1).next