/**************************************************************************** Desc: Setup two child blocks for a root block. ****************************************************************************/ RCODE F_BtreeRoot::setupTree( FLMBYTE * pucMidEntry, // If !NULL entry to insert into root. eDynRSetBlkTypes eBlkType, // Leaf or non-leaf F_BtreeBlk ** ppLeftBlk, // (out) F_BtreeBlk ** ppRightBlk) // (out) { RCODE rc = NE_FLM_OK; F_BtreeBlk * pLeftBlk = NULL; F_BtreeBlk * pRightBlk = NULL; if (RC_BAD( rc = newBlk( &pLeftBlk, eBlkType))) { goto Exit; } if (RC_BAD( rc = newBlk( &pRightBlk, eBlkType))) { goto Exit; } if (eBlkType == ACCESS_BTREE_NON_LEAF) { ((F_BtreeNonLeaf *)pRightBlk)->lemBlk( lemBlk()); } // Fix up the linkages pLeftBlk->nextBlk( pRightBlk->blkAddr()); pRightBlk->prevBlk( pLeftBlk->blkAddr()); lemBlk( pRightBlk->blkAddr()); if (pucMidEntry) { // Add the midentry to the root block. Search to position and insert. searchEntry( pucMidEntry); insertEntry( pucMidEntry, pLeftBlk->blkAddr()); } m_uiLevels++; if (ppLeftBlk) { *ppLeftBlk = pLeftBlk; } if (ppRightBlk) { *ppRightBlk = pRightBlk; } Exit: return( rc); }
/**************************************************************************** Desc: Search a btree. Position for get* or for insert. ****************************************************************************/ RCODE F_BtreeRoot::search( void * pvEntry, void * pvFoundEntry) { RCODE rc = NE_FLM_OK; FLMUINT uiCurLevel = m_uiLevels - 1; // Min 2 levels FLMUINT uiBlkAddr; // Reset the stack - only needed for debugging. //f_memset( m_BTStack, 0, sizeof(F_BtreeBlk *) * FBTREE_MAX_LEVELS); // Search this root block. m_BTStack[ uiCurLevel] = this; (void) searchEntry( pvEntry, &uiBlkAddr); while( uiCurLevel--) { // Read the next block and place at uiCurLevel (backwards from FS). if( RC_BAD( rc = readBlk( uiBlkAddr, uiCurLevel ? ACCESS_BTREE_NON_LEAF : ACCESS_BTREE_LEAF, &m_BTStack[ uiCurLevel] ))) { goto Exit; } // Set the rc - only for the leaf block, otherwise rc should be ignored. rc = m_BTStack[ uiCurLevel]->searchEntry( pvEntry, &uiBlkAddr, uiCurLevel ? NULL : pvFoundEntry); } Exit: return( rc); }
/**************************************************************************** Desc: Split the root block and make two new non-leaf blocks. The secret here is that the root block never moves (cheers!). This takes a little longer but is worth the work because the root block never goes out to disk and is not in the cache. ****************************************************************************/ RCODE F_BtreeRoot::split( void * pvCurEntry, FLMUINT uiCurChildAddr) { RCODE rc = NE_FLM_OK; FLMBYTE * pucEntry; FLMBYTE * pucChildAddr; F_BtreeBlk * pLeftBlk; F_BtreeBlk * pRightBlk; F_BtreeBlk * pBlk; FLMUINT uiChildAddr; FLMUINT uiPos; FLMUINT uiEntryCount = entryCount(); FLMUINT uiMid = (uiEntryCount + 1) >> 1; if (RC_BAD( rc = setupTree( NULL, ACCESS_BTREE_NON_LEAF, &pLeftBlk, &pRightBlk))) { goto Exit; } // Call search entry once just to setup for insert. (void) pLeftBlk->searchEntry( ENTRY_POS( 0)); // Take the entries from the root block and move into leafs. for (uiPos = 0; uiPos <= uiMid; uiPos++) { pucEntry = ENTRY_POS( uiPos); pucChildAddr = pucEntry + m_uiEntrySize; uiChildAddr = (FLMUINT)FB2UD(pucChildAddr); if (RC_BAD( rc = pLeftBlk->insertEntry( pucEntry, uiChildAddr))) { goto Exit; } } // Call search entry once just to setup for insert. (void) pRightBlk->searchEntry( ENTRY_POS( 0)); for (uiPos = uiMid + 1; uiPos < uiEntryCount; uiPos++) { pucEntry = ENTRY_POS( uiPos); pucChildAddr = pucEntry + m_uiEntrySize; uiChildAddr = (FLMUINT)FB2UD(pucChildAddr); if ((rc = pRightBlk->searchEntry( pucEntry )) != NE_FLM_NOT_FOUND) { rc = RC_SET_AND_ASSERT( NE_FLM_FAILURE); goto Exit; } if (RC_BAD( rc = pRightBlk->insertEntry( pucEntry, uiChildAddr))) { goto Exit; } } // Reset the root block and insert new midpoint. entryCount( 0); lemBlk( pRightBlk->blkAddr()); // Duplicated just in case. pucEntry = ENTRY_POS( uiMid); if ((rc = searchEntry( pucEntry )) != NE_FLM_NOT_FOUND) { rc = RC_SET_AND_ASSERT( NE_FLM_FAILURE); goto Exit; } if (RC_BAD( rc = insertEntry( pucEntry, pLeftBlk->blkAddr() ))) { goto Exit; } // Insert the current entry (parameters) into the left or right blk. // This could be done a number of different ways. (void) searchEntry( pvCurEntry, &uiChildAddr); if (RC_BAD( rc = readBlk( uiChildAddr, ACCESS_BTREE_NON_LEAF, &pBlk))) { goto Exit; } (void) pBlk->searchEntry( pvCurEntry); if (RC_BAD( rc = pBlk->insertEntry( pvCurEntry, uiCurChildAddr))) { goto Exit; } Exit: return( rc); }
/**************************************************************************** Desc: Move first half of entries into new block. Reset previous block to point to new block. Add new last entry in new block to parent. Fixup prev/next linkages. ****************************************************************************/ RCODE F_BtreeBlk::split( F_BtreeRoot * pRoot, FLMBYTE * pucCurEntry, // (in) Contains entry to insert FLMUINT uiCurBlkAddr, // (in) Blk addr if non-leaf FLMBYTE * pucParentEntry, // (out) Entry to insert into parent. FLMUINT * puiNewBlkAddr) // (out) New blk addr to insert into parent. { RCODE rc = NE_FLM_OK; F_BtreeBlk * pPrevBlk; F_BtreeBlk * pNewBlk = NULL; FLMBYTE * pucEntry = NULL; FLMBYTE * pucMidEntry; FLMBYTE * pucChildAddr; FLMUINT uiChildAddr; FLMUINT uiPrevBlkAddr; FLMUINT uiMid; FLMUINT uiPos; FLMUINT uiMoveBytes; FLMBOOL bInserted = FALSE; // Allocate a new block for the split. if (RC_BAD( rc = pRoot->newBlk( &pNewBlk, blkType() ))) { goto Exit; } pNewBlk->AddRef(); // Pin the block - may get flushed out. // the last half into the new block, but that would force the parent // entry to be changed. This may take a little longer, but it is much // more easier to code. // Call search entry once just to setup for insert. (void) pNewBlk->searchEntry( ENTRY_POS( 0)); // get the count and move more then half into the new block. uiMid = (entryCount() + 5) >> 1; uiChildAddr = FBTREE_END; for (uiPos = 0; uiPos < uiMid; uiPos++) { pucEntry = ENTRY_POS( uiPos); if (blkType() != ACCESS_BTREE_LEAF) { pucChildAddr = pucEntry + m_uiEntrySize; uiChildAddr = (FLMUINT)FB2UD(pucChildAddr); } // m_uiPosition automatically gets incremented. if (RC_BAD( rc = pNewBlk->insertEntry( pucEntry, uiChildAddr))) { RC_UNEXPECTED_ASSERT( rc); goto Exit; } } if (m_uiPosition < uiMid) { // Insert this entry now bInserted = TRUE; (void) pNewBlk->searchEntry( pucCurEntry); if (RC_BAD( rc = pNewBlk->insertEntry( pucCurEntry, uiCurBlkAddr))) { goto Exit; } } // Let caller insert into parent entry. This rids us of recursion. f_memcpy( pucParentEntry, pucEntry, m_uiEntrySize); // Move the rest down pucEntry = ENTRY_POS( 0); pucMidEntry = ENTRY_POS( uiMid); entryCount( entryCount() - uiMid); uiMoveBytes = entryCount() * (m_uiEntrySize + m_uiEntryOvhd); flmAssert( uiMoveBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr)); f_memmove( pucEntry, pucMidEntry, uiMoveBytes); if( !bInserted) { // m_uiPosition -= uiMid; (void) searchEntry( pucCurEntry); if (RC_BAD( rc = insertEntry( pucCurEntry, uiCurBlkAddr))) { goto Exit; } } // VISIT: Could position stack to point to current element to insert. // Fixup the prev/next block linkages. if (prevBlk() != FBTREE_END) { if (RC_BAD( rc = pRoot->readBlk( prevBlk(), blkType(), &pPrevBlk ))) { goto Exit; } pPrevBlk->nextBlk( pNewBlk->blkAddr()); uiPrevBlkAddr = pPrevBlk->blkAddr(); } else { uiPrevBlkAddr = FBTREE_END; } pNewBlk->prevBlk( uiPrevBlkAddr); pNewBlk->nextBlk( blkAddr()); prevBlk( pNewBlk->blkAddr()); *puiNewBlkAddr = pNewBlk->blkAddr(); Exit: if (pNewBlk) { pNewBlk->Release(); } return( rc); }
int main() { setlocale(LC_ALL, "Portuguese"); int lin, col; Point pos; Stack *ways; BoolPos currentSituation; int i; FILE *arquivo; arquivo = fopen("labirinto.txt", "r"); if(arquivo == NULL) { printf("Erro ao carregar o labirinto, arquivo não pode ser aberto."); return 0; } fscanf(arquivo, "%i %i", &lin, &col); printf("Labirinto %i x %i\n\n", lin, col); // Alocate +1 to acomodate the \0 at end of final line char (*maze)[col] = (char(*)[col]) malloc((sizeof(char)*lin*col) + 1); for(i=0; i<lin; i++) { fscanf(arquivo, "%s", maze[i]); } if (!searchEntry(lin, col, maze, &pos)) { printf("\nNão há entrada para esse labirinto, impossível continuar"); return 0; } ways = createStack(lin * col); push(ways, pos); maze[pos.x][pos.y] = 'v'; while(maze[pos.x][pos.y] != MAZE_OUT) { checkPositions(¤tSituation, &pos, lin, col, maze); if(maze[pos.x][pos.y] == MAZE_WAY) { maze[pos.x][pos.y] = 'v'; //Move } printf("\nTentativa: %i x %i", pos.x, pos.y); if(currentSituation.left == 0 && currentSituation.bottom == 0 && currentSituation.right == 0 && currentSituation.top == 0) { if (!pop(ways, &pos)) { printf("\nEntrada encontrada não leva para uma saída!\n"); if(searchEntry(lin, col, maze, &pos)) { printf("Nova entrada encontrada! Resolvendo...\n"); push(ways, pos); } else { printf("\n\nNão foi possível encontrar o caminhos a(s) entrada(s) encontrada(s) não levam à uma saída!\n"); break; } } } else { push(ways, pos); } } printf("\n\nLabirinto descoberto com sucesso!\nO caminho é:\n\n"); while(pop(ways, &pos) == TRUE) { printf("%iº passo: %i x %i\n", ways->topo +1, pos.x, pos.y); } deinitStack(ways); printf("\n\n"); free(maze); fclose(arquivo); system("Pause"); return 0; }
V* search (const K& key) { Entry* e = searchEntry(key); return (e) ? &e->value : NULL; }
K* searchKey (const K& key) { Entry* e = searchEntry(key); return (e) ? &e->key : NULL; }