数组链表

/*

数组:在删除的时候需要移动数组元素开销大
链表:无法使用预先分配固定内存,并且无法使用索引方式在O(1)复杂度下删除
数组链表优点:
1.在插入O(1),删除的复杂度都是O(N),带索引删除复杂度为O(1)
2.并且可以预先把需要的内存分配好
*/

class CAList
{
public:
    CAList(unsigned int Count,unsigned int ElementSize);
    ~CAList(void);
    
    //获得一个空闲节点的存储地址 
    //nIndex为返回的节点索引
    char* GetFreeNode(int& nIndex);
    
    //回收一个节点 nIndex为索引
    bool FreeNode(int nIndex);

    //最大节点个数
    unsigned int GetMaxCount() { return m_MaxCount;}
    //已使用节点个数
    unsigned int GetAllocCount() { return m_AllocCount;}
    //剩余节点个数
    unsigned int GetFreeCount() { return m_MaxCount - m_AllocCount; }
private:
    //最大元素个数
    unsigned int m_MaxCount;
    //每个元素字节大小
    unsigned int m_ElementSize;
    //指针数组
    int *pFreeIndex;
    //数据存储区域
    char* pDate;
   // char (*pDate)[] 
    //已经使用的个数
    unsigned int m_AllocCount;
    //当前分配的索引,只递增不减
    unsigned int m_AllocCurrentIdx;
    //空闲索引头,每次分配取这个节点的value值,该值为一个空闲节点的下标
    unsigned int m_FreeHead;
    //空闲索引尾部,每次回收节点使用
    unsigned int m_FreeTail;
    
};
 
//实现cpp

#include "StdAfx.h"
#include "AList.h"

CAList::CAList(unsigned int Count,unsigned int ElementSize)
{
    m_MaxCount = Count;
    m_ElementSize = ElementSize;
    pFreeIndex = new int[Count];
    pDate = new char[Count*ElementSize]; //存储区域可从外部分配 pDate = GetBlock(Count,ElementSize);
    
    m_AllocCount = 0;
    m_AllocCurrentIdx = 0;
    m_FreeHead = 0;
    m_FreeTail = 0;

}

CAList::~CAList(void)
{
    if (0 != pFreeIndex)
    {
        delete [] pFreeIndex;
    }

    if (0 != pDate)
    {
         delete [] pDate;
    }
}


char* CAList::GetFreeNode(int& nIndex)
{
    char* p = 0;
    nIndex = 0;
    //
    if (m_AllocCurrentIdx > m_AllocCount)
    {
        while(m_FreeHead != m_FreeTail)
        {
            int FrIndex = pFreeIndex[m_FreeHead];
            if (pFreeIndex[FrIndex] & MASK)
            {
                //节点被使用
                m_FreeHead = (m_FreeHead + 1) % m_MaxCount;
                continue;
            }
            nIndex = FrIndex;
            m_FreeHead = (m_FreeHead + 1) % m_MaxCount; 
            p = pDate + (nIndex * m_ElementSize);
            pFreeIndex[nIndex] |= MASK;
            m_AllocCount++;
           return p;
        }
    }
    if (m_AllocCurrentIdx >= m_MaxCount)
    {
        return p;
    }
    nIndex = m_AllocCurrentIdx;
    p = pDate + (nIndex * m_ElementSize);
    pFreeIndex[nIndex] |= MASK;
    m_AllocCurrentIdx++;
    m_AllocCount++;
    return p;
}

bool CAList::FreeNode(int nIndex)
{   
   if (nIndex < 0 || nIndex > m_MaxCount)
   {
       return false; 
   }

   if ((pFreeIndex[nIndex] & MASK) == 0)
   {
        return false;
   }

   pFreeIndex[m_FreeTail] &= MASK;
   pFreeIndex[m_FreeTail] |= nIndex; //nIndex总是整数,所以|操作不会影响最高位(符号位)

   m_FreeTail = (m_FreeTail + 1) % m_MaxCount;
   m_AllocCount--;
   pFreeIndex[nIndex] &= (~MASK);

   return true;
}

 

/*

假设game的后台地图管理,先回把地图分区,然后用9宫格管理地图上的对象,每个区域都会有一个类似链表的对象来管理本地区上的对象。

如果使用数组,那么在对象下线或者移动离开本区域就要删除对象,数组的元素删除后可能需要移动,这样对需要高性能的后台程序是不合适的。

那么链表可不吗?虽然链表可以在O(1)复杂度里删除对象,但是不能直接使用索引删除,需要遍历也是很消耗性能的操作。

使用上面的数组链表就可以很好的解决这个问题,让插入和删除复杂度都在O(1)的时间复杂度里。

*/

//需要管理的对象

struct tagEntityInfo
{
    int ObjectID;
    int MapId;
    int Posx;
    int Posy;
    int Index; //在数组链表的索引
};

typedef struct tagEntityInfo EntityInfo;
#define MAX_SAMPLE 10
#define SAMPLE_DATA sizeof(EntityInfo*)

int _tmain(int argc, _TCHAR* argv[])
{
 
     CAList AList(MAX_SAMPLE,sizeof(EntityInfo));
    int FrIndex;
    //请求一个对象空间
    char* pDate = AList.GetFreeNode(FrIndex);
    EntityInfo* pEntity = reinterpret_cast<EntityInfo*>(pDate);
    pEntity->MapId = 1;
    pEntity->ObjectID = 1;
    pEntity->Posx = 100;
    pEntity->Posy = 100;
    pEntity->Index = FrIndex;  //设置在数组里的索引

    pDate = AList.GetFreeNode(FrIndex);
    EntityInfo* pEntity2 = reinterpret_cast<EntityInfo*>(pDate);
    pEntity2->MapId = 1;
    pEntity2->ObjectID = 2;
    pEntity2->Posx = 200;
    pEntity2->Posy = 300;
    pEntity2->Index = FrIndex;

    //删除一个对象	
    AList.FreeNode(pEntity->Index);

    pDate = AList.GetFreeNode(FrIndex);
    EntityInfo* pEntity3 = reinterpret_cast<EntityInfo*>(pDate);
    pEntity3->MapId = 1;
    pEntity3->ObjectID = 1;
    pEntity3->Posx = 500;
    pEntity3->Posy = 500;
    pEntity3->Index = FrIndex;
}


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值