开头先介绍下背景,本人是做游戏服务器端开发的,最近项目不紧,所以一直计划着完善自己的一套底层代码库,包括容器,内存池,智能指针,网络,数据库等等。并在此基础上完成一个C/S的服务器设计。
顺便提一句,后续的这些代码,在可能的情况下,基本上都是采取空间换时间的思路,比如很多地方会在设计的时候多记录几个指针,达到更快的获取而不用搜索的目的。
今天是第一篇,最基础的单链表,实现的其实是队列的功能。
这里就没有实现单链表的中途插入和删除操作了,因为单链表的中途删除,需要遍历,效率不是很高,因此就不提供了,下篇的双链表中再实现这两个功能。
PS:
2013.6.5修改了容器的实现:继承了后面提到的TContainer,实现相关接口。
上代码:
#ifndef _TLinkList_h_
#define _TLinkList_h_
#include <windows.h>
#include "TContainer.h"
template <class T>
class TLinkList;
//单向链表结点
template <class T>
struct TLinker
{
TLinker<T> *m_pNext;//下一个结点
T m_Value; //值域
};
//单向链表
//该类自己不申请TLinker,只是负责管理外部申请的TLinker结点
//将其链表化,提供接入、删除功能
template <class T>
class TLinkList : public TContainer<T>
{
public:
TLinkList();
~TLinkList();
//将pLinker加入到链表尾
//成功返回true
//参数不合法返回false
bool PushTail(TLinker<T> *pLinker);
//从链表头拿一个pLinker出来,从链表中断开pLinker
//成功返回pLinker
//链表本身没有结点了返回NULL
TLinker<T> *PopHead();
// 初始化\清空链表
void Init(ContainerFlag dwLock = enum_EnableLock);
//获取链表头对象
//若m_pHead为空则返回空
T *GetHead();
//获取链表中curr的下一个对象
//若curr为空则返回空
//若curr没有下一个对象则返回空
T *GetNext(T *curr);
//获取链表中curr对应的结点对象
//若curr为空则返回空
void *GetNode(T *curr);
private:
TLinker<T> *m_pHead;//头指针
TLinker<T> *m_pTail;//尾指针
};
#include "TLinkList.hpp"
#endif
说明:
1、此处TLinker结构里面没有做成T *m_Value,而是让数据直接包含在结点中(数据就是指针的另算),一个是可以省四字节的指针空间;二主要是为了方便,当在逻辑当中知道某个对象的物理地址的时候,可以直接根据该对象的地址(T的地址)计算出结点的地址(TLinker的地址),这样提供给逻辑的指针,可以直接是T的地址,而不需要暴露整个TLinker结构给上层逻辑。比如上层逻辑有一个Obj a,但是不知道a对应的链表结点,当需要在TLinkList<Obj> listA上操作a对象的时候,就得遍历链表,逐个判断找出a对应的TLinker,再操作。但是现在不需要遍历了,写一个宏,可以计算出TLinker了,
#define MemOffset(ClassName, MemberName) \
((DWORD)(&(((ClassName *)0)->MemberName)))
#define ContainerOf(MemberAddr , ClassName , MemberName) \
((ClassName *)((DWORD)(MemberAddr) - MemOffset(ClassName , MemberName)))
那么结点的地址就是:TLinker<Obj> *pLinker = ContainerOf(&a, TLinker<Obj>, m_Value);
2、PushTail的参数的安全性,此处只检查了pLinker是否为空,没有对pLinker的从属做检查,也就是没有判断pLinker是否已经在这个链表上了,这是使用时需要注意的,必须明确PushTail传递的结点,不是之前应经被Push但是没有Pop出来的结点。在下篇的双向链表中,双向链表的结点的设计会加上结点从属链表对象的字段。
最后贴下实现TLinkList.hpp
#ifndef _TLinkList_hpp_
#define _TLinkList_hpp_
template <class T>
TLinkList<T>::TLinkList()
{
Init();
}
template <class T>
TLinkList<T>::~TLinkList()
{
Init();
}
template <class T>
void TLinkList<T>::Init(ContainerFlag dwLock)
{
m_pHead = NULL;
m_pTail = NULL;
m_dwLen = 0;
m_dwLock = dwLock;
}
template <class T>
TLinker<T> *TLinkList<T>::PopHead()
{
TLinker<T> *pLinker = NULL;
//此处需要在下面if的外面加锁
//因为m_pHead在多线程环境下可能会变
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
if (NULL != m_pHead)
{
pLinker = m_pHead;
ResetNext(&(pLinker->m_Value));
m_pHead = m_pHead->m_pNext;
pLinker->m_pNext = NULL;
if (m_pTail == pLinker)
{
m_pTail = NULL;
}
m_dwLen--;
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pLinker;
}
template <class T>
bool TLinkList<T>::PushTail(TLinker<T> *pLinker)
{
bool bRes = false;
if (NULL != pLinker)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
pLinker->m_pNext = NULL;
if (NULL != m_pTail)
{
m_pTail->m_pNext = pLinker;
}
m_pTail = pLinker;
if (NULL == m_pHead)
{
m_pHead = pLinker;
}
m_dwLen++;
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
bRes = true;
}
return bRes;
}
template <class T>
T *TLinkList<T>::GetHead()
{
T *pRes = NULL;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
if (NULL != m_pHead)
{
pRes = &(m_pHead->m_Value);
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pRes;
}
template <class T>
T *TLinkList<T>::GetNext(T *curr)
{
T *pRes = NULL;
if (NULL != curr)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TLinker<T> *pCurrLinker = (TLinker<T> *)GetNode(curr);
if (NULL != pCurrLinker->m_pNext)
{
pRes = &(pCurrLinker->m_pNext->m_Value);
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
return pRes;
}
template <class T>
void *TLinkList<T>::GetNode(T *curr)
{
TLinker<T> *pRes = NULL;
if (NULL != curr)
{
pRes = ContainerOf(curr, TLinker<T>, m_Value);
}
return pRes;
}
#endif