【问题标题】:Removing a node From Doubly Threaded LnkLst从双线程 LnkLst 中删除节点
【发布时间】:2010-11-27 00:05:47
【问题描述】:

我试图从双线程链表中删除单个节点。

我的工作..它的效率非常低。

我想知道是否可以获得一些专家建议或一些终止条件提示。

这是我从一组评级节点中删除一个节点的函数,存储在 headByRating 和一组名称节点中,存储在 headByName 中。所有这些都已排序....

bool list::remove (const char * const name) { 节点 *currByName = headByName; 节点 *currByRating = headByRating; 节点 *prev_node = NULL; while ( NULL != currByName && (strcmp(name, currByName->item.getName())!= 0)) { prev_node = currByName; currByName = currByName->nextByName; prev_node->nextByName = currByName; } 如果(currByName == headByName) { currByName = currByName->nextByName; headByName = currByName; } 否则如果(currByName->nextByName == NULL) {//那么我们必须在最后 currByName = prev_node; currByName->nextByName = NULL; //返回真; } 别的 { currByName = prev_node; currByName->nextByName = currByName->nextByName->nextByName; //返回真; } 而 ( NULL != currByRating && ( strcmp( 名称, currByRating->item.getName() ) != 0 ) ) { prev_node = currByRating; currByRating = currByRating->nextByRating; prev_node->nextByRating = currByRating; } if ( currByRating == headByRating ) // 是头部吗? { currByRating = currByRating->nextByRating; headByRating = currByRating; 返回真; } else if ( currByRating->nextByRating == NULL ) // 可能是尾巴吗? { currByRating = prev_node; currByRating->nextByRating = NULL; 返回真; } 别的 { currByRating = prev_node; currByRating->nextByRating = currByRating->nextByRating->nextByRating; 返回真; } 返回假; }

是的,我只需要帮助简化代码,使其更高效。如果可能的话,我希望只组合和使用一个while循环。

【问题讨论】:

    标签: c++


    【解决方案1】:

    两个选择:

    1) 使用解决问题的高级库。 Boost MultiIndex 容器允许与多个有序/映射组织共享节点。

    2) 不要使用两个(按等级和名称排序)单链表,而是使用两个双链表。然后删除给定节点是 O(1)。要通过名称快速找到节点,您可以使用有效的映射(哈希表或平衡树)。如果您不介意扫描一个列表来查找节点,那么该列表不需要双向链接。

    至于链表的删除,你怀疑你的代码可以被极大地简化是对的。要么:

    1) 对空列表使用哨兵(虚拟)节点;这样,实际列表项总是存在“上一个节点”

    2)在单链表删除中,不是“指向上一个节点的指针”,而是存储“指向“指向该节点的下一个指针”的指针。

    这就是我所说的 2):

    node **pn=&headByRating; // we will update headByRating=n via (*pn)=n if needed
    node *c=*pn;  // we will have c == *pn except momentarily
    while ( c && strcmp(name, c->item.getName()) {
        pn=&c->nextByRating; // c is now the previous node
        c=*pn; // c is *pn again
    }
    // now (*pn) points to the node we want to delete, i.e. c
    *pn=c->next; // (*pn) skips right over c now.
    // delete c; // or else you leak memory; you didn't specify how nodes are allocated
    return true;
    

    这应该等同于您的:

    while ( NULL != currByRating && 
          ( strcmp( name, currByRating->item.getName() ) != 0 ) )
    {
        prev_node = currByRating;
        currByRating = currByRating->nextByRating;
        prev_node->nextByRating  = currByRating;
    }
        if ( currByRating == headByRating ) // was it the head?
        {
            currByRating = currByRating->nextByRating;
            headByRating = currByRating;
            return true;
        }
        else if ( currByRating->nextByRating == NULL ) // could it be the tail?
        {
            currByRating = prev_node;
            currByRating->nextByRating = NULL;
            return true;
        }
        else
        {
            currByRating = prev_node;
            currByRating->nextByRating = currByRating->nextByRating->nextByRating;
            return true;
        }
    

    【讨论】:

    • 如果是作业(不能使用Boost),那么如果希望它快(跳过第二次遍历),则需要对两个订单中的第二个使用双向链表。您还可以考虑使用 std::map 或哈希查找按名称查找节点,而不是通过列表进行搜索。我简化单链表删除的建议不会让任何事情变得更快;它只会保存代码。
    • 我已经通过插入排序“insort”函数分配了节点: node *current_node = new object( object_t );其中 object_t 正在为每个节点传入。我用 current_node 分配每个节点。
    • 是的,它是等价的(在它的作用上)。您不必以任何不同的方式对待“tail is NULL”的情况。并且通过使用“node **pn”,您不必区别对待“已删除的节点是列表的头”。
    • 由于您为所有节点分配了新的,请确保在最后一次使用后删除它们(取消注释我的“删除 c”)。
    【解决方案2】:

    它可能会解决,但不知何故,我认为我可以不用两个 while 循环..和重新声明..

    节点 **previous_node = &headByRating; // 如果需要,我们将通过 (*prev_node)=n 更新 headByRating 节点 *current_node = *previous_node; // 我们将有 current == *prev_node 除了暂时 while ( current_node && strcmp(name, current_node->item.getName() ) != 0 ) { previous_node = &current_node->nextByRating; // c 现在是前一个节点 current_node = *previous_node; // 当前又是 *prev_node } // 现在 (*prev_node) 指向我们要删除的节点;当前的 *previous_node = current_node->nextByRating; // (*prev_node) 现在跳过当前。 节点 **prev_node = &headByName; 节点 *cur_node = *prev_node; while ( current_node && strcmp(name, cur_node->item.getName() ) != 0 ) { prev_node = &cur_node->nextByName; cur_node = *prev_node; } *prev_node = cur_node->nextByName; 删除 current_node;// 否则 当前节点=空; 返回真; }

    我会研究这个 =) 感谢 wrang wrang 的出色表现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-14
      • 2013-09-01
      • 2013-10-14
      相关资源
      最近更新 更多