tokyo cabinet源代码分析(6)

2.5数据记录的删除

主要流程为二叉树节点删除。

二叉树中删除记录的过程: /*记录在二叉树中的删除过程 *通过HASH函数将key映射到TCMAP数组的一个元素, *然后通过tcmapout进行相应的删除工作*/ /* Remove a record of an on-memory hash database. */ bool tcmdbout(TCMDB *mdb, const void *kbuf, int ksiz){ assert(mdb && kbuf && ksiz >= 0); unsigned int mi; TCMDBHASH(mi, kbuf, ksiz); if(pthread_rwlock_wrlock((pthread_rwlock_t *)mdb->mmtxs + mi) != 0) return false; bool rv = tcmapout(mdb->maps[mi], kbuf, ksiz); pthread_rwlock_unlock((pthread_rwlock_t *)mdb->mmtxs + mi); return rv; }

通过tcmapout进行删除。

/* Remove a record of a map object. */ bool tcmapout(TCMAP *map, const void *kbuf, int ksiz){ assert(map && kbuf && ksiz >= 0); if(ksiz > TCMAPKMAXSIZ) ksiz = TCMAPKMAXSIZ; uint32_t hash; /*HASH映射到buckets数组的一个元素*/ TCMAPHASH1(hash, kbuf, ksiz); int bidx = hash % map->bnum; TCMAPREC *rec = map->buckets[bidx]; TCMAPREC **entp = map->buckets + bidx; TCMAPHASH2(hash, kbuf, ksiz); hash &= ~TCMAPKMAXSIZ; /*遍历二叉树,进行相应的删除*/ while(rec){ uint32_t rhash = rec->ksiz & ~TCMAPKMAXSIZ; uint32_t rksiz = rec->ksiz & TCMAPKMAXSIZ; /*如果HASH不相同,循环遍历左子树或者右子树*/ if(hash > rhash){ entp = &(rec->left); rec = rec->left; } else if(hash < rhash){ entp = &(rec->right); rec = rec->right; } else { /*如果相同,则比较KEY值 *不相同继续遍历*/ char *dbuf = (char *)rec + sizeof(*rec); int kcmp = TCKEYCMP(kbuf, ksiz, dbuf, rksiz); if(kcmp < 0){ entp = &(rec->left); rec = rec->left; } else if(kcmp > 0){ entp = &(rec->right); rec = rec->right; } else { /*key相同,record记录减一*/ map->rnum--; map->msiz -= rksiz + rec->vsiz; /*将删除的record节点的前续、后继节点进行重新连接*/ if(rec->prev) rec->prev->next = rec->next; if(rec->next) rec->next->prev = rec->prev; if(rec == map->first) map->first = rec->next; if(rec == map->last) map->last = rec->prev; if(rec == map->cur) map->cur = rec->next; /*如果该删除节点只有左子树,则直接跳过该节点 *指向它的左子树节点*/ if(rec->left && !rec->right){ *entp = rec->left; } /*如果只有右子树,则直接跳过该节点 *指向它的右子树节点*/ else if(!rec->left && rec->right){ *entp = rec->right; /*如果没有子树,直接将节点删除*/ } else if(!rec->left && !rec->left){ *entp = NULL; } else { /*如果相同,即需要删除该节点 *entp指向它的左子树,然后遍历左子树的 右子树,到最右边的叶子节点(即:值最大的节点), 将原先节点的右子树,作为最大节点的右子树*/ *entp = rec->left; TCMAPREC *tmp = *entp; while(tmp->right){ tmp = tmp->right; } tmp->right = rec->right; } TCFREE(rec); return true; } } } return false; }

在删除过程中,方法和通常介绍的方法有所不同。如果被删除节点A有左、右子树,那么左子树都小于它,
右子树大于它。而A节点的左子树的最右节点是它左子树中最大的节点,如果删除了A节点,那么它的右子树节点均大于左子树,所以可以直接将它右子树,连接到左子树中最大节点的右子树中。

 

 

你可能感兴趣的:(工作,null,代码分析)