使用シナリオ:
頻繁欠失データ要素
の固定のデータ要素の最大数
欠陥の単一のリスト
- トリガーが
頻繁に追加、削除データ要素オブジェクト単一のリストの使用を長期
- 起こりそうな結果を
ゆっくり実行するためのシステム原因、メモリの断片化のヒープ領域に大量
説明:
リストに単一のデータ要素を追加すると、彼らは、ビューの手続きの点から、何の問題もなく、そうするヒープ領域にノードジャンクションを作成しますが、長い時間のために作成頻繁にいくつかのシステムでは、ノード削除接合するたびにポイントは、ヒープメモリの断片を大量に製造することが可能です。メモリの断片化と、直接の結果は、システムが遅い実行されていることです。これは、欠陥重リンクリストの実装です。
新しいリニアフォームの
デザインのアイデア:
ノードが動的の動的な作成と破棄に、この空間内のオブジェクトのすべての単一のリスト内に予約スペース高める
ためのフォーム単一のリスト+ =静的単一のリストを
継承階層静的単一のリスト
メモリ、単鎖及びその他の操作のさまざまな方法に、静的な単鎖付加は、実装前に全く同じです。
実施静的単一リンクリスト考え
を通してテンプレートを単一の静的メンバobjectlist(StaticLinkList)を定義し
、クラスに定義された固定サイズの空間(unsigned char型を[])
関数を作成し、破壊書き換え、方法メモリの割り当てと反発変化
ノードクラスに重みをアップロードオペレータは新しい、指定されたメモリ内のオブジェクトを作成します
静的単一リンクリストは、達成するために:
このタイプでのノードLinkList.hがどのように定義されるかを見てください。
構造体ノード:パブリックオブジェクト
{
T value; //既然是泛指类型的value,那么这个value就有可能是一个对象(用户自定义类类型的对象),必然牵涉到构造函数调用的问题了。value构造函数的调用,必然牵涉到Node构造函数的调用了(value是Node的一个成员变量)
Node* next;
};
在StaticLinkList.h中,再看一下create函数的定义,
Node* create()
{
Node* ret = NULL;
for(int i=0; i<N; i++) //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。
{
if(!m_used[i])
{
ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。
m_used[i] = 1;
break;
}
}
return ret;
}
这里面不涉及Node构造函数的定义。仅仅是单纯的分配内存,并没有涉及到构造函数的调用。
分配好内存之后,我们还需要在指定的内存上调用构造函数。此时就需要重载new操作符了。
struct SNode : public Node
{
//loc保存了一个内存地址,该内存地址就是调用构造函数的内存地址
void* operator new(unsigned int size, void* loc)
{
return loc;
}
};
Node* create()
{
SNode* ret = NULL;
for(int i=0; i<N; i++) //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。
{
if(!m_used[i])
{
ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。
ret = new(ret) SNode();
m_used[i] = 1;
break;
}
}
return ret;
}
void destroy(Node* pn)
{
SNode* space = reinterpret_cast<SNode*>(m_space);
SNode* psn = dynamic_cast<SNode*>(pn);//从父类指针,转换为子类指针,直接调用dynameic_cast
for(int i=0; i<N; i++)
{
if(psn == (space + i))
{
m_used[i] = 0;
psn->~SNode();
}
}
}
具体代码如下:
#ifndef STATICLINKLIST_H
#define STATICLINKLIST_H
#include "linklist.h"
namespace DTLib
{
template <typename T,int N> //N用来定义预留大小空间使用的
class StaticLinkList : public LinkList<T>
{
protected:
typedef typename LinkList<T>::Node Node; //为什么需要加上typename,因为LinkList<T>::Node这种写法,根本就无法确定Node是一种类型还是静态成员变量。
struct SNode : public Node
{
//loc保存了一个内存地址,该内存地址就是调用构造函数的内存地址
void* operator new(unsigned int size, void* loc)
{
(void)size;
return loc;
}
};
unsigned char m_space[sizeof(SNode) * N]; //定义预留的空间
int m_used[N]; //标记数组
Node* create()
{
SNode* ret = NULL;
for(int i=0; i<N; i++) //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。
{
if(!m_used[i])
{
ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。
ret = new(ret) SNode();
m_used[i] = 1;
break;
}
}
return ret;
}
void destroy(Node* pn)
{
SNode* space = reinterpret_cast<SNode*>(m_space);
SNode* psn = dynamic_cast<SNode*>(pn);//从父类指针,转换为子类指针,直接调用dynameic_cast
for(int i=0; i<N; i++)
{
if(psn == (space + i))
{
m_used[i] = 0;
psn->~SNode();
}
}
}
public:
StaticLinkList()
{
for(int i=0; i<N; i++)
{
m_used[i] = 0;
}
}
int capacity()
{
return N; //表示静态单链表最多可以容纳多少个数据元素
}
};
}
#endif // STATICLINKLIST_H
LinkList中封装create和destroy函数的意义:
为静态单链表(StackLinkList)的实现做准备。StaticLinkList与LinkList的不同仅在于链表结点内存分配上的不同。因此将仅有的不同封装于父类和子类的虚函数中
小结:
顺序表与单链表相结合后衍生出静态单链表
静态单链表是LinkList的子类,拥有单链表的所有操作
静态单链表在预留的空间中创建结点对象
静态单链表适合于频繁增删数据元素的场合(最大元素个数固定)