數組去實現鏈表

分爲兩部分。一種是鏈表關係是爲了知曉數據間關聯,與正常鏈表一樣的。另一種是爲了知曉下一個可用位置的鏈表。

第一種是原創見http://blog.csdn.net/pcliuguangtao/article/details/6316743

第二種原創見loki庫,稍微作相應的改變。


第一種:

  1. /*基於結構體數組的鏈表實現*/ 
  2. /* made by winlin 2011.4.11
  3. *initialize(  )初始化存儲池 
  4. *insertNode(  )插入一個節點 
  5. *deleteNode(  )刪除一個節點 
  6. *display_member(  )顯示存儲池裏面的數據 
  7. *display_info(  )顯示存儲池當前的信息 
  8. *isempty(  )存儲池是否已滿 
  9.  */ 
  10. #include <iostream> 
  11. #include <cstdlib> 
  12.  
  13. typedef int elementType; 
  14. const int NULL_VALUE=-1;   //不存在的位置 
  15. //節點聲明 
  16. typedef struct node 
  17.     elementType data;   //存放節點的數據 
  18.     int next;                  //存放下一個節點在存儲池數組中的序號 
  19. }Node; 
  20.  
  21. //存儲池 
  22. const int NUMNODES=2048; 
  23. Node  nodeList[NUMNODES]; 
  24. int freelist;       //其值爲空閒節點鏈的在存儲池中的起始位置 
  25. int first;   //其值爲第一個節點在存儲池中的位置 
  26. int emptyNodes; 
  27.  
  28. void initialize( ) 
  29.     { 
  30.         int i; 
  31.         for( i=0;i<NUMNODES;++i ) 
  32.             { 
  33.                 nodeList[ i ].next=i+1; 
  34.             } 
  35.         nodeList[ NUMNODES-1 ].next=NULL_VALUE; 
  36.         freelist=0; 
  37.         first=NULL_VALUE; 
  38.         emptyNodes=NUMNODES; 
  39.  
  40.     } 
  41.  
  42. bool isempty(  ) 
  43.     { 
  44.         if( emptyNodes==NUMNODES ) 
  45.             return 1; 
  46.         return 0; 
  47.          
  48.     } 
  49.  
  50. int insertNode(const elementType& nodedata) 
  51.     { 
  52.         int temp; 
  53.          
  54.         if( emptyNodes<=0 ) 
  55.             { 
  56.                 std::cout<<"the NodeList has full/n"
  57.                 exit( -1 ); 
  58.             } 
  59.          
  60.         temp=freelist; 
  61.         freelist=nodeList[ freelist ].next;   //從空閒鏈表中剔除開始的那個節點 
  62.         if( first==NULL_VALUE ) 
  63.             { 
  64.                 first=temp; 
  65.                 nodeList[ temp].data=nodedata; 
  66.                 nodeList[ temp].next=NULL_VALUE; 
  67.                  
  68.             } 
  69.         else 
  70.             { 
  71.                 nodeList[ temp ].data=nodedata; 
  72.                 nodeList[ temp ].next=first; 
  73.                 first=temp; 
  74.  
  75.             } 
  76.         --emptyNodes; 
  77.         return temp; 
  78.  
  79.     } 
  80.  
  81. void deleteNode(const  elementType& nodedata ) 
  82.     { 
  83.        if( first==NULL_VALUE ) 
  84.            { 
  85.                std::cout<<"the NodeList is empty/n"
  86.                exit( -1 ); 
  87.            } 
  88.        int temp_cur=first; 
  89.        int temp_pre=first; 
  90.        while( temp_cur !=NULL_VALUE) 
  91.            { 
  92.                if( nodeList[ first ].data==nodedata )    //第一個就是要刪除的節點 
  93.                    { 
  94.                        int i=first; 
  95.                        first=nodeList[ i ].next;   //處理已使用鏈 
  96.                        //處理未使用鏈 
  97.                        nodeList[i].next=freelist; 
  98.                        freelist=i; 
  99.                    } 
  100.                else if( nodeList[ temp_cur].data==nodedata ) 
  101.                    { 
  102.                        nodeList[temp_pre].next=nodeList[ temp_cur ].next;    //處理已使用的鏈表 
  103.                        //處理未使用的鏈表 
  104.                        nodeList[ temp_cur ].next=freelist; 
  105.                        freelist=temp_cur; 
  106.                         
  107.                    } 
  108.                temp_pre=temp_cur; 
  109.                temp_cur=nodeList[ temp_cur].next; 
  110.            } 
  111.        ++emptyNodes; 
  112.         
  113.     } 
  114.  
  115. void display_member( ) 
  116.     { 
  117.         if( emptyNodes==NUMNODES ) 
  118.             { 
  119.                 std::cout<<"the NodeList is empty/n"
  120.                 exit( -1 ); 
  121.             } 
  122.         int temp=first; 
  123.          
  124.         while(temp!=NULL_VALUE) 
  125.             { 
  126.                 std::cout<<nodeList[ temp ].data<<"  "
  127.                 temp=nodeList[ temp ].next; 
  128.                  
  129.             } 
  130.         std::cout<<"/n"
  131.          
  132.     } 
  133. void display_info(  ) 
  134.     { 
  135.         std::cout<<"NodeList的總容量爲:"<<NUMNODES<<"/nNodeList已經使用:" 
  136.                  <<NUMNODES-emptyNodes<<"/n剩餘可用量爲:"<<emptyNodes<<"/n"
  137.          
  138.     } 
  139. int main(  ) 
  140.     { 
  141.         initialize(  ); 
  142.         insertNode( 12 ); 
  143.         insertNode( 13 ); 
  144.         insertNode( 14 ); 
  145.         insertNode( 15 ); 
  146.         insertNode( 16 ); 
  147.         display_member(  ); 
  148.         display_info(  ); 
  149.  
  150.         deleteNode(16); 
  151.         deleteNode( 12 ); 
  152.         deleteNode( 13 ); 
  153.         display_member(  ); 
  154.         display_info(  ); 
  155.  
  156.         return 0; 
  157.          
  158.     }

第二種

第二種不是知道鏈表中首個存儲節點的位置,如果需要遍歷,則特別不方便。  

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;
}


發佈了8 篇原創文章 · 獲贊 32 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章