文章目录
StaticLinkList.h
#ifndef STATICLINKLIST_H
#define STATICLINKLIST_H
#include "LinkList.h"
/*
父类有父类的实现版本,子类有子类的实现版本------多态的应用
顺序表有预留空间(但是效率有问题), 单链表没有预留空间(直接在堆空间创建节点), 于是想到两者可结合一下;
最后得到一种叫做 静态单链表的新的线性表数据结构
单链表:
创建很多的节点,归还空间后留下内存碎片,当需要一整块内存的时候,系统将进行碎片整理,然而这需要时间。
其本质: 堆空间是公用的,每个人都可以用,为了解决这个问题,静态单链表就诞生了。
静态单链表(思路):
预留一段内存出来,可以是任意一段合法的内存(不管这段内存的出处是哪里,只要连续就可以了),
插入 --> 数据元素的时候,在这段空间中查看有没有空位置,然后创建Node对象,
删除 --> 的时候,就在这片空间调用析构函数,然后将这片内存空间标记为可用,就可以了;
静态单链表 和 单链表:
除了内存分配不同,其它完全一样,因仅需要改两个函数就行,creat() destroy(Node *pn),
两个函数操作的是单独的一块内存。
*/
namespace DTLib
{
template < typename T, int N >
class StaticLinkList : public LinkList<T>
{
protected:
typedef typename LinkList<T>::Node Node; // typedef 简化一个类型,给一个类型新的名字 Node
// 父类的Node和泛指类型和泛指类型牵扯上了关系,此处不可用,故而需要重新定义
// LinkList<T>::Node 编译器不知道这是类型还是静态成员变量,需要关键字typename出场
//unsigned char m_space[sizeof(typename LinkList<T>::Node) * N]; // 定义这片内存空间
unsigned char m_space[sizeof(Node) * N]; // 定义这片内存空间
int m_used[N]; // 标记数组
// --> 重载 new 操作符
struct SNode : public Node
{
void* operator new(unsigned int size, void* loc) // 要来两个参数,我们的目的是:在指定的内存上调用构造函数
{
(void)size; // C语言中的暴力处理方式
return loc; // 直接返回内存地址(调用构造函数的内存地址)
}
};
SNode* creat()
{
SNode* ret = NULL;
for(int i=0; i<N; i++) // 遍历这片空间,看那些是可用的, 每个单元都看看是否被使用了
{
if(!m_used[i]) // 如果i这个单元没有被使用,就可以分配这个单元了
{
ret = reinterpret_cast<SNode*>(m_space) + i; // 做强制类型转换 和 指针运算 (仅分配内存)
// 仅仅这么写是有问题的,不会调用Node构造函数
// 那么问题来了: 分配好内存之后,我们还要在指定的内存上调用构造函数,如何做?
// --> 重载 new 操作符
/* 分析: 父类中 Node 的定义
struct Node : public Object
{
T value; // 泛指类型的value有可能是个对象,是用户自定义类类型的对象,必然牵扯构造问题
Node* next; // value 构造必然涉及到 Node 构造函数调用
};
*/
ret = new(ret)SNode(); // 在指定的空间中,调用构造函数的代码, () 表示你想在哪一个内存空间上调用构造函数
// 成功解决问题,构造函数也被调用;
m_used[i] = 1; // 标记一下,当前的这片内存单元已经分配出去了
break;
}
}
return ret;
}
void destroy(Node *pn)
{
SNode* space = reinterpret_cast<SNode*>(m_space); // 要做指针运算,所以要做强制类型转换
SNode* pst = dynamic_cast<SNode*>(pn); // 从父类指针转换到子类指针
for(int i=0; i<N; i++) // 查看需要归还的空间是哪一个
{
if(pst == (space + i)) // 当pst 等于(space + i) 的地址时, i 空间需要归还
{
m_used[i] = 0; // 标记当前内存单元可用
pst->~SNode(); // 析构
}
}
}
public:
StaticLinkList()
{
for(int i=0; i<N; i++)
{
m_used[i] = 0;
}
}
int capacity()
{
return N;
}
};
}
#endif // STATICLINKLIST_H
main.cpp
#include <iostream>
#include "LinkList.h"
#include "StaticList.h"
#include "StaticLinkList.h"
using namespace std;
using namespace DTLib;
int main()
{
StaticLinkList<int, 5> list;
for(int i = 0; i < 5; i++)
{
list.insert(0, i);
}
//list.insert(6); // 所定义的空间只能5个int,create() 无法找到可用空间,就爆掉了
// StaticLinkList.h --> create() 返回空指针
// LinkList.h ---> insert() Node 为空,抛出异常
for(list.move(0, 1); !list.end(); list.next())
{
cout << list.current() << endl;
}
try
{
list.insert(1);
}
catch (const Exception& obj)
{
cout << obj.message() << endl;
cout << obj.location() << endl;
}
return 0;
}
简直是神奇 ‘