【问题标题】:Deletion of second largest element from a singly linked list从单链表中删除第二大元素
【发布时间】:2017-11-17 15:58:20
【问题描述】:

我目前正在尝试为自己编写一个数据结构框架。在普通情况下,从单链表中删除第二大节点完美无缺。但在一个特定的方面失败了。这是我已经尝试过的:

//node.h
typedef struct Node {
    int value;
    struct Node *nextNode;
} Node;

//linkedlist.h
typedef struct LinkedList{
    Node *head;
    int count;
} LinkedList;

//liblinkedlist.c
int deleteSecondLargest(LinkedList *list){
    if(list->count==0)
        return 1;
    if(list->count==1)
        return 2;
    Node *temp = list->head;
    Node *largest = temp;
    Node *prev = NULL;
    Node *prev1 = NULL;
    Node *ptr = temp;

    //finding the second largest node
    while(temp!=NULL){
        if(temp->value > largest->value){
            largest = temp;
        }
        else if((temp->value!=largest->value) && (temp->value > ptr->value)){//here's the code failing
            prev1 = prev;
            ptr = temp;
        }
        prev = temp;
        temp = temp->nextNode;
    }

    //deleting it
    if(ptr==list->head)
        list->head = list->head->nextNode;
    else
        prev1->nextNode = ptr->nextNode;
    free(ptr);
    list->count--;
    return 0;
}

只要列表中的项目按 1332->34->N 的顺序排列,注释块中的代码就会失败。 我可以理解为什么它失败了,因为 tempptr 都持有 1332 而 else if 在第二次迭代中返回 false,但我找不到任何解决方案。此外,函数所在的文件已在函数定义上方进行了注释。 有什么帮助吗?

【问题讨论】:

  • 请修改您的代码以获得minimal reproducible example
  • 单步执行我脑海中的代码(根据您显示的示例列表),就我所见,它应该可以正常工作。您能否详细说明“失败”部分? 如何失败了?您是否在调试器中逐行执行代码(直到函数结束)?
  • @alexeykuzmin0 如果我理解正确的话,这已经在方法中完成了。我已经更新了 cmets。立即查看。
  • @Someprogrammerdude 当节点为 1334 和 34 时,代码将失败。temp 和 ptr 都被初始化为 1334。现在在 while 循环中,在第二次迭代中,else if 分支应该为 true我的代码工作。但这并不是ptr 持有1334temp 持有34temp 不大于 ptr,因此整个分支失败。
  • 在 temp 和 ptr 都等于 1332 的步骤中,if 语句在到达 isValueGreater 部分之前不应该失败吗?因为两者都相等,所以 isValueEqual 为真-> if 语句失败...

标签: c++ c data-structures linked-list singly-linked-list


【解决方案1】:

据我所知,您的代码的第一部分存在问题:在单链表中查找第二大元素。

其实这段代码存在三个问题:

  1. ptr 使用第一个元素进行初始化,该元素可能太大而不能成为第二个最大值。
  2. 没有节点从largest 降级到ptr。这意味着,对于列表 34 -> 1332 -> N,您的代码也不起作用。
  3. 如果两个最大值具有相同的值,则忽略第二个。这意味着,对于列表 123 -> 123 -> N,您的代码也不起作用。

求两个最大值的算法如下:

  1. 初始化:使用可能的最低值或特殊的“未初始化”标志初始化两个当前最大值。
  2. 循环遍历所有元素:
    1. 使用当前值更新两个最大值。

实施:

// Initialization
Node *largest = nullptr; // for maximum, nullptr means "not initialized"
Node *largest2 = nullptr; // for second maximum, nullptr means "not initialized"
Node *prev_largest = nullptr; // for previous node for maximum
Node *prev_largest2 = nullptr; // for previous node for second maximum

// Iterations
for (Node *cur = list->head, *prev = nullptr; // start of the loop: current node is head, prev is null
    cur != nullptr; // end of the loop: current node is null
    prev = cur, cur = cur->nextNode) { // loop iteration: move both current and prev nodes forward

    if (largest == nullptr || cur->value > largest->value) { // check if we need to update maximum
        // the node which was maximum is now second maximum
        prev_largest2 = prev_largest;
        largest2 = largest;
        // current node is now maximum
        prev_largest = prev;
        largest = cur;
    } else if (largest2 == nullptr || cur->value > largest2->value) { // check if we need to update second maximum
        // current node is now second maximum
        prev_largest2 = prev;
        largest2 = cur;
    }
}
// End of algorithm
// Second maximum is now in variable largest2
// Previous node for second maximum is now in variable prev_largest2

另外,请注意,即使您的列表包含少于 2 个元素,此算法也有效(在这种情况下,largest2 将在末尾为 nullptr)。

【讨论】:

  • 是的。做到了。这是一个小小的致敬:commit
  • 顺便说一句 1 和 2 是问题。 3 是故意的。
  • @Subhranil 好的,那么请注意,在此答案中,代码 #3 是固定的:如果列表中有两个相同的最大值,则 largest2 将指向它们的右侧,而不是指向第三个。无论如何,这应该不难解决。
  • 如果列表只包含一个元素,那么搜索第二大元素是没有意义的。这就是为什么我将其作为错误捕获。
猜你喜欢
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
  • 2012-05-18
  • 2020-10-29
  • 2019-12-29
  • 2018-07-08
  • 1970-01-01
相关资源
最近更新 更多