13. 静态单链表的实现

1. 单链表的一个缺陷

触发条件:长时间使用单链表对象频繁增加和删除数据元素
可能的结果:堆空间产生大量的内存碎片,导致系统运行缓慢

2. 新的线性表

2.1 设计思路

在“单链表”的内部增加一片预留的空间,所有的Node对象都在这篇空间中动态创建和动态销毁。
在这里插入图片描述

2.2实现思路

  1. 通过模板定义静态单链表类(StaticLinkList)
  2. 在类中定义固定大小的空间(unsigned char [ ])
  3. 重写create 和 destroy函数,改变内存的分配和归还方式
  4. 在Node类中重载operator new ,用于在指定内存上创建对象

2.3代码

#ifndef STATICLINKLIST_H
#define STATICLINKLIST_H
#include "linklist.h"
namespace DragonLib
{

template<typename T,int N>
class StaticLinkList : public LinkList<T>
{
protected:
    typedef typename LinkList<T>::Node Node;
    struct SNode : public Node
    {
        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;
                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);
        for(int i=0;i<N;i++)
        {
            if(pn == (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
//main.cpp
#include <iostream>
#include "StaticLinkList.h"

using namespace std;
using namespace DragonLib;


int main()
{
    StaticLinkList<int,5> list;
    for(int i=0;i<5;i++)
    {
        list.insert(0,i);
    }
    try
    {
        list.insert(6);
    }
    catch(const Exception& e)
    {
        cout<< e.message()<<endl;
    }
    for(list.move(0);!list.end();list.next())
    {
        cout << list.current() << endl;
    }
    return 0;
}

插入五个数据元素之后,再次插入会抛异常:
在这里插入图片描述
我们来看看insert()函数:

bool insert(int i,const T& e)
    {
        bool ret = ((0<=i) && (i<=m_length));
        if(ret)
        {
            Node* node = create();
            if(node != NULL)
            {
                Node* current = position(i);//O(n)
                node->value = e;
                node->next = current->next;
                current->next = node;
                m_length++;
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException,"No memory to insert new element!");
            }
        }
        return ret;
    }

我们可以发现里面有个create()函数,我们再来深入看看:

//LinkList.h
virtual Node* create()
{
    return new Node();
}

我们发现它是一个虚函数,我们在LinkList的子类中对他进行实现,这是面向对象里多态的典型应用!

Node* create()
    {
        SNode* ret = NULL;
        for(int i=0;i<N;i++)
        {
            if(!m_used[i])
            {
                ret = reinterpret_cast<SNode*>(m_space) + i;
                ret = new(ret)SNode();
                m_used[i] = 1;
                break;
            }
        }
        return ret;
    }

此时N是5,我们要在第六个位置插数据,当然不行!所以抛异常

3. Q&A

LinkList中封装create和destroy函数的意义?
为静态链表StaticLinkList的实现做准备。StaticLinkList与LinkList的不同仅在于链表结点内存分配上的不同;因此,将仅有的不同封装于父类和子类的虚函数中。

4. 小结

  1. 顺序表与单链表相结合后衍生出静态单链表
  2. 静态单链表是LinkList的子类,拥有单链表的所有操作
  3. 静态单链表在预留的空间中创建结点对象
  4. 静态单链表适合于频繁增删数据元素的场合(最大元素个数固定)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值