分爲兩部分。一種是鏈表關係是爲了知曉數據間關聯,與正常鏈表一樣的。另一種是爲了知曉下一個可用位置的鏈表。
第一種是原創見http://blog.csdn.net/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;
}