这两天看到一种静态链表的实现,刚好可以拿来做资源池的实现,记下供参考。
先说静态链表,这最开始为了给Pascal等没有指针的语言来实现链表的一种方式,为了模拟链表指针指向下一个节点的方式,静态聊表使用数组下标来表示下一个元素的位置。
就算是在有指针的语言中,使用静态链表也有它的优势:初始化后相对顺序存储结构插入删除元素不需要移动元素,相对指针实现的链表不需要动态分配和删除元素内存,正好适用于固定大小的资源分配池的实现。
思路
如下初始化一个数组作为静态链表,每个元素初始指向第后一个元素,初始size=0,头结点head指向第1个节点,下一个可分配节点也指向第1个节点。
接下来,如下连续分配4个节点,则size=4,head按照头插入生成链,因此head指向第4个节点,分配的节点依次指向之前分配的节点,next指向第5个节点。
接下来,如下先后删除第4和第1个分配的节点,则size=2,此时head指向第3个元素,next下一个可分配的则是最后删除的第1个节点。可以看到,其实相当于有两条链存在这个数组中,已分配的head链和待分配的next链互补,申请元素时将next链元素给head链,删除元素时head链将元素还给next链。这样的方式非常适合做资源池的实现。
。
具体实现
抽象元素类型T和初始大小nInitSize,以一个数组作为静态表分配,模板类声明如下
template <class T, uint32_t nInitSize>
class StaticLinkList
{
private:
...
typedef struct
{
T data;
uint32_t next;
}ElemType;
ElemType m_dataArr[nInitSize];
uint32_t m_nIndexHead;
uint32_t m_nIndexNext;
uint32_t m_nCurSize;
...
初始化大小,head和next链
template <class T, uint32_t nInitSize>
void StaticLinkList<T, nInitSize>::Clear()
{
memset(&this->m_dataArr, 0, sizeof(m_dataArr));
for (int i = 0; i < nInitSize - 1; i++)
{
m_dataArr[i].next = i + 1;
}
m_nIndexHead = m_nIndexNext = m_nCurSize = 0;
}
封装静态链表元素分配和释放,其实就是从next链删除和增加
template <class T, uint32_t nInitSize>
uint32_t StaticLinkList<T, nInitSize>::Malloc_SL()
{
uint32_t i = m_nIndexNext;
m_nIndexNext = m_dataArr[i].next;
return i;
}
template <class T, uint32_t nInitSize>
void StaticLinkList<T, nInitSize>::Free_SL(const int32_t nIndex)
{
m_dataArr[nIndex].next = m_nIndexNext;
m_nIndexNext = nIndex;
}
获取资源实现如下,只需要从next获取一个资源,添加到head链即可
template <class T, uint32_t nInitSize>
T* StaticLinkList<T, nInitSize>::Get()
{
if (m_nCurSize >= nInitSize)
{
return NULL;
}
uint32_t nNewIndex = Malloc_SL();
if (m_nCurSize != 0)
{
m_dataArr[nNewIndex].next = m_nIndexHead;
}
m_nIndexHead = nNewIndex;
m_nCurSize += 1;
return &m_dataArr[nNewIndex].data;
}
释放资源,只需要找到对应的元素,从head链删除,还给next链即可,这里还可以做下优化,每个分配的元素自己保存父节点,这样就可以直接找到自己的下标,快速删除
template <class T, uint32_t nInitSize>
bool StaticLinkList<T, nInitSize>::Delete(T *pdata)
{
if (m_nCurSize<=0 || !pdata)
{
return false;
}
uint32_t nIndexFind = 0;
if (&m_dataArr[m_nIndexHead].data == pdata)
{
nIndexFind = m_nIndexHead;
m_nIndexHead = m_dataArr[m_nIndexHead].next;
}
else
{
bool bFind = false;
uint32_t np = m_nIndexHead;
for (uint32_t i=0; i < m_nCurSize - 1; i++)
{
if (&m_dataArr[m_dataArr[np].next].data == pdata)
{
bFind = true;
break;
}
np = m_dataArr[np].next;
}
if (!bFind)
{
return false;
}
nIndexFind = m_dataArr[np].next;
m_dataArr[np].next = m_dataArr[nIndexFind].next;
}
Free_SL(nIndexFind);
m_nCurSize -= 1;
return true;
}
如下分配一个简单的资源池,添加删除后再添加
StaticLinkList<int, 10> l;
int *p0= l.Get();
int *p1 = l.Get();
int *p2 = l.Get();
int *p3 = l.Get();
*p0 = 10;
*p1 = 11;
*p2 = 12;
*p3 = 13;
cout << "Init data:" << endl;
l.Dump([](const uint32_t n, const int *a) {
cout << n << "->" << *a << endl;
});
l.Delete(p3);
l.Delete(p0);
cout << endl << "Delete data:" << endl;
l.Dump([](const uint32_t n, const int *a) {
cout << n << "->" << *a << endl;
});
*l.Get() = 15;
*l.Get() = 19;
*l.Get() = 21;
cout << endl << "After data:" << endl;
l.Dump([](const uint32_t n, const int *a) {
cout << n << "->" << *a << endl;
});
运行结果为
Init data:
Head Index:3 Next Index:4 Cur Size:4
3->13
2->12
1->11
0->10
Delete data:
Head Index:2 Next Index:0 Cur Size:2
2->12
1->11
After data:
Head Index:4 Next Index:5 Cur Size:5
4->21
3->19
0->15
2->12
1->11
演示代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219