分为两部分。一种是链表关系是为了知晓数据间关联,与正常链表一样的。另一种是为了知晓下一个可用位置的链表。
第一种是原创见http://blog.youkuaiyun.com/pcliuguangtao/article/details/6316743
第二种原创见loki库,稍微作相应的改变。
第一种:
- /*基于结构体数组的链表实现*/
- /* made by winlin 2011.4.11
- *initialize( )初始化存储池
- *insertNode( )插入一个节点
- *deleteNode( )删除一个节点
- *display_member( )显示存储池里面的数据
- *display_info( )显示存储池当前的信息
- *isempty( )存储池是否已满
- */
- #include <iostream>
- #include <cstdlib>
- typedef int elementType;
- const int NULL_VALUE=-1; //不存在的位置
- //节点声明
- typedef struct node
- {
- elementType data; //存放节点的数据
- int next; //存放下一个节点在存储池数组中的序号
- }Node;
- //存储池
- const int NUMNODES=2048;
- Node nodeList[NUMNODES];
- int freelist; //其值为空闲节点链的在存储池中的起始位置
- int first; //其值为第一个节点在存储池中的位置
- int emptyNodes;
- void initialize( )
- {
- int i;
- for( i=0;i<NUMNODES;++i )
- {
- nodeList[ i ].next=i+1;
- }
- nodeList[ NUMNODES-1 ].next=NULL_VALUE;
- freelist=0;
- first=NULL_VALUE;
- emptyNodes=NUMNODES;
- }
- bool isempty( )
- {
- if( emptyNodes==NUMNODES )
- return 1;
- return 0;
- }
- int insertNode(const elementType& nodedata)
- {
- int temp;
- if( emptyNodes<=0 )
- {
- std::cout<<"the NodeList has full/n";
- exit( -1 );
- }
- temp=freelist;
- freelist=nodeList[ freelist ].next; //从空闲链表中剔除开始的那个节点
- if( first==NULL_VALUE )
- {
- first=temp;
- nodeList[ temp].data=nodedata;
- nodeList[ temp].next=NULL_VALUE;
- }
- else
- {
- nodeList[ temp ].data=nodedata;
- nodeList[ temp ].next=first;
- first=temp;
- }
- --emptyNodes;
- return temp;
- }
- void deleteNode(const elementType& nodedata )
- {
- if( first==NULL_VALUE )
- {
- std::cout<<"the NodeList is empty/n";
- exit( -1 );
- }
- int temp_cur=first;
- int temp_pre=first;
- while( temp_cur !=NULL_VALUE)
- {
- if( nodeList[ first ].data==nodedata ) //第一个就是要删除的节点
- {
- int i=first;
- first=nodeList[ i ].next; //处理已使用链
- //处理未使用链
- nodeList[i].next=freelist;
- freelist=i;
- }
- else if( nodeList[ temp_cur].data==nodedata )
- {
- nodeList[temp_pre].next=nodeList[ temp_cur ].next; //处理已使用的链表
- //处理未使用的链表
- nodeList[ temp_cur ].next=freelist;
- freelist=temp_cur;
- }
- temp_pre=temp_cur;
- temp_cur=nodeList[ temp_cur].next;
- }
- ++emptyNodes;
- }
- void display_member( )
- {
- if( emptyNodes==NUMNODES )
- {
- std::cout<<"the NodeList is empty/n";
- exit( -1 );
- }
- int temp=first;
- while(temp!=NULL_VALUE)
- {
- std::cout<<nodeList[ temp ].data<<" ";
- temp=nodeList[ temp ].next;
- }
- std::cout<<"/n";
- }
- void display_info( )
- {
- std::cout<<"NodeList的总容量为:"<<NUMNODES<<"/nNodeList已经使用:"
- <<NUMNODES-emptyNodes<<"/n剩余可用量为:"<<emptyNodes<<"/n";
- }
- int main( )
- {
- initialize( );
- insertNode( 12 );
- insertNode( 13 );
- insertNode( 14 );
- insertNode( 15 );
- insertNode( 16 );
- display_member( );
- display_info( );
- deleteNode(16);
- deleteNode( 12 );
- deleteNode( 13 );
- display_member( );
- display_info( );
- return 0;
- }
第二种
第二种不是知道链表中首个存储节点的位置,如果需要遍历,则特别不方便。
class Chunk
{
public:
bool Init( ::std::size_t blockSize, unsigned char blocks );
void * Allocate( ::std::size_t blockSize );
void Deallocate( void * p, ::std::size_t blockSize );
void Reset( ::std::size_t blockSize, unsigned char blocks );
void Release();
bool IsCorrupt( unsigned char numBlocks, ::std::size_t blockSize,
bool checkIndexes ) const;
bool IsBlockAvailable( void * p, unsigned char numBlocks,
::std::size_t blockSize ) const;
inline bool HasBlock( void * p, ::std::size_t chunkLength ) const
{
unsigned char * pc = static_cast< unsigned char * >( p );
return ( pData_ <= pc ) && ( pc < pData_ + chunkLength );
}
inline bool HasAvailable( unsigned char numBlocks ) const
{ return ( blocksAvailable_ == numBlocks ); }
inline bool IsFilled( void ) const
{ return ( 0 == blocksAvailable_ ); }
/// Pointer to array of allocated blocks.
unsigned char * pData_;
/// Index of first empty block.
unsigned char firstAvailableBlock_;
/// Count of empty blocks.
unsigned char blocksAvailable_;
};
bool Chunk::Init( ::std::size_t blockSize, unsigned char blocks )
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
const ::std::size_t allocSize = blockSize * blocks;
assert( allocSize / blockSize == blocks);
#ifdef USE_NEW_TO_ALLOCATE
// If this new operator fails, it will throw, and the exception will get
// caught one layer up.
pData_ = static_cast< unsigned char * >( ::operator new ( allocSize ) );
#else
// malloc can't throw, so its only way to indicate an error is to return
// a nullptr pointer, so we have to check for that.
pData_ = static_cast< unsigned char * >( ::std::malloc( allocSize ) );
if ( nullptr == pData_ )
return false;
#endif
Reset( blockSize, blocks );
return true;
}
void Chunk::Reset(::std::size_t blockSize, unsigned char blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
assert((blockSize * blocks) / blockSize == blocks);
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
for ( unsigned char * p = pData_; i != blocks; p += blockSize )
{
*p = ++i;
}
}
void Chunk::Release()
{
assert( nullptr != pData_ );
#ifdef USE_NEW_TO_ALLOCATE
::operator delete ( pData_ );
#else
::std::free( static_cast< void * >( pData_ ) );
#endif
}
void* Chunk::Allocate(::std::size_t blockSize)
{
if ( IsFilled() )
return nullptr;
assert((firstAvailableBlock_ * blockSize) / blockSize ==
firstAvailableBlock_);
unsigned char * pResult = pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
// Chunk::Deallocate ----------------------------------------------------------
void Chunk::Deallocate(void* p, ::std::size_t blockSize)
{
assert(p >= pData_);
unsigned char* toRelease = static_cast<unsigned char*>(p);
// Alignment check
assert((toRelease - pData_) % blockSize == 0);
unsigned char index = static_cast< unsigned char >(
( toRelease - pData_ ) / blockSize);
#if defined(DEBUG) || defined(_DEBUG)
// Check if block was already deleted. Attempting to delete the same
// block more than once causes Chunk's linked-list of stealth indexes to
// become corrupt. And causes count of blocksAvailable_ to be wrong.
if ( 0 < blocksAvailable_ )
assert( firstAvailableBlock_ != index );
#endif
*toRelease = firstAvailableBlock_;
firstAvailableBlock_ = index;
// Truncation check
assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
++blocksAvailable_;
}
// Chunk::IsCorrupt -----------------------------------------------------------
bool Chunk::IsCorrupt( unsigned char numBlocks, ::std::size_t blockSize,
bool checkIndexes ) const
{
if ( numBlocks < blocksAvailable_ )
{
// Contents at this Chunk corrupted. This might mean something has
// overwritten memory owned by the Chunks container.
assert( false );
return true;
}
if ( IsFilled() )
// Useless to do further corruption checks if all blocks allocated.
return false;
unsigned char index = firstAvailableBlock_;
if ( numBlocks <= index )
{
// Contents at this Chunk corrupted. This might mean something has
// overwritten memory owned by the Chunks container.
assert( false );
return true;
}
if ( !checkIndexes )
// Caller chose to skip more complex corruption tests.
return false;
/* If the bit at index was set in foundBlocks, then the stealth index was
found on the linked-list.
*/
::std::bitset< UCHAR_MAX > foundBlocks;
unsigned char * nextBlock = nullptr;
for ( unsigned char cc = 0; ; )
{
nextBlock = pData_ + ( index * blockSize );
foundBlocks.set( index, true );
++cc;
if ( cc >= blocksAvailable_ )
// Successfully counted off number of nodes in linked-list.
break;
index = *nextBlock;
if ( numBlocks <= index )
{
assert( false );
return true;
}
if ( foundBlocks.test( index ) )
{
assert( false );
return true;
}
}
if ( foundBlocks.count() != blocksAvailable_ )
{
assert( false );
return true;
}
return false;
}
// Chunk::IsBlockAvailable ----------------------------------------------------
bool Chunk::IsBlockAvailable( void * p, unsigned char numBlocks,
::std::size_t blockSize ) const
{
(void) numBlocks;
if ( IsFilled() )
return false;
unsigned char * place = static_cast< unsigned char * >( p );
// Alignment check
assert( ( place - pData_ ) % blockSize == 0 );
unsigned char blockIndex = static_cast< unsigned char >(
( place - pData_ ) / blockSize );
unsigned char index = firstAvailableBlock_;
assert( numBlocks > index );
if ( index == blockIndex )
return true;
/* If the bit at index was set in foundBlocks, then the stealth index was
found on the linked-list.
*/
::std::bitset< UCHAR_MAX > foundBlocks;
unsigned char * nextBlock = nullptr;
for ( unsigned char cc = 0; ; )
{
nextBlock = pData_ + ( index * blockSize );
foundBlocks.set( index, true );
++cc;
if ( cc >= blocksAvailable_ )
// Successfully counted off number of nodes in linked-list.
break;
index = *nextBlock;
if ( index == blockIndex )
return true;
assert( numBlocks > index );
assert( !foundBlocks.test( index ) );
}
return false;
}