You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法理解双向链表head与tail赋值,remove函数失效求助

双向链表insert/remove函数修复方案

问题描述

我搞不懂双向链表的head和tail属性该怎么赋值,实现remove函数一直不正常。肯定是LinkedList::insert()和LinkedList::remove()里的head、tail处理出问题了。

在LinkedList::remove()里,current变量不知道该赋啥值:用head的话会拿到前一个节点的值;用head.next直接抛异常。还有previous指针的用法也有问题,同样会引发异常。查过相关案例,但没找到解决办法。

相关代码

Node头文件

#pragma once

class Node
{
public:
    int data;
    Node* next;
    Node* previous;
};

LinkedList头文件

class LinkedList
{
private:
    int length;
    Node* head;
    Node* tail;

public:
    LinkedList();
    void remove(int deleted);
    void insert(int data);
    void display();
    int getLength();
};

LinkedList实现文件

#include <iostream>
#include "LinkedList.h"
#include "Node.h"

using namespace std;

//Define variables used in the class
LinkedList::LinkedList()
{
    length = 0;
    head = NULL;
    tail = NULL;
}

//Define the remove function
void LinkedList::remove(int deletedNode)
{ 
    struct Node* current = head;
    while (current)
    {
        if (current->data == deletedNode)
        {
            if (current->next == NULL)
            {
                current->previous->next = NULL;
                current = NULL;
            }
            else if (head == NULL)
            {
                current->next->previous = NULL;
                current = NULL;
            }
            else
            {
                current->previous->next = current->next;
                current->next->previous = current->previous;
                current = NULL;
            }
        }
        current = current->next;
    }
}

//Define insert function
void LinkedList::insert(int num1)
{
    Node* node = new Node(); //Create new node
    node->data = num1; //Assign new number to node's data variable
    node->next = head; //Assign the current contents of the head variable to the new node's next pointer
    node->previous = tail; //Assign the current contents of the tail variable to the new node's previous pointer
    head = node; //Assign the new node to the head variable
    tail = node->previous;

    length++; //Increase the list's length by one
}

//Define display function
void LinkedList::display()
{
    Node* curr = this->head;
    int i = 1;
    while (curr)
    {
        cout << "Value of node #" << i << " is " << curr->data << endl;
        curr = curr->next;
        i++;
    }
}

//Define getLength function
int LinkedList::getLength()
{
    return length;
}

主函数文件

#include <iostream>
#include "LinkedList.h"
#include "Node.h"
#include <time.h>

using namespace std;

int main()
{
    int userRemove = 1;

    LinkedList list;

    // Define & start clock
    clock_t start, end;
    start = clock();

    for (int i = 1; i < 101; i++)
    {
        list.insert(rand() % 101);
    }

    // Display list
    list.display();

    // End clock
    end = clock();

    //Display duration it took to display list
    cout << endl << "It took " << (end - start) << " milliseconds to list & display all nodes." << endl;

    //Display total number of nodes
    int len = list.getLength();
    cout << endl << "# of nodes = " << len << endl;

    //Ask user for node number to remove
    while (userRemove != 0)
    {
        cout << endl << "Please enter the number of the node you wish to delete or press '0' to exit: " << endl;
        cin >> userRemove;
        list.remove(userRemove);
        cout << endl << "The first node containing " << userRemove << " has been removed." << endl;
        //Display list and list length after removal
        list.display();
        cout << endl << "# of nodes = " << len << endl;
    }
}

错误分析与修复

1. insert函数的核心错误

原insert函数的head/tail赋值逻辑完全错误,导致链表结构混乱:

  • 新节点插在头部时,previous应该是nullptr(头部节点没有前驱),而不是tail
  • 原链表不为空时,需要把原head节点的previous指向新节点,否则双向链表的前驱链断裂
  • tail的赋值逻辑错误,原代码把tail设为node->previous(也就是空),正确逻辑是:如果链表原本为空,新节点同时是head和tail;否则tail保持不变

修改后的insert函数:

void LinkedList::insert(int num1)
{
    Node* node = new Node();
    node->data = num1;
    node->next = head;
    node->previous = nullptr; // 头部节点无前驱

    if (head != nullptr) {
        head->previous = node; // 原head的前驱指向新节点
    } else {
        tail = node; // 空链表时,新节点同时是tail
    }

    head = node; // 更新head为新节点
    length++;
}

2. remove函数的核心错误

原remove函数存在多个逻辑漏洞,导致空指针异常和链表结构错误:

  • 判断顺序错误:应该先判断是否是head节点,再判断是否是tail节点
  • 删除节点时未更新head/tail指针,导致后续遍历出错
  • 未释放删除节点的内存,造成内存泄漏
  • 找到目标节点后未退出循环,继续遍历会访问空指针
  • 未处理删除节点后length减1的逻辑

修改后的remove函数:

void LinkedList::remove(int deletedNode)
{
    if (head == nullptr) {
        return; // 空链表直接返回
    }

    Node* current = head;
    while (current) {
        if (current->data == deletedNode) {
            // 情况1:删除的是head节点
            if (current == head) {
                head = current->next;
                if (head != nullptr) {
                    head->previous = nullptr;
                } else {
                    tail = nullptr; // 删除最后一个节点时,tail也要置空
                }
            }
            // 情况2:删除的是tail节点
            else if (current == tail) {
                tail = current->previous;
                tail->next = nullptr;
            }
            // 情况3:删除中间节点
            else {
                current->previous->next = current->next;
                current->next->previous = current->previous;
            }

            delete current; // 释放内存
            length--; // 长度减1
            break; // 找到第一个匹配节点后退出循环
        }
        current = current->next;
    }
}

3. 主函数的小问题

原主函数中len只初始化了一次,删除节点后不会更新,导致显示的长度始终是初始值。修改主函数中显示长度的部分:

// 替换原有的长度输出代码
cout << endl << "# of nodes = " << list.getLength() << endl;

验证效果

修改后,插入节点时链表的head和tail会正确维护,删除节点时无论删除头部、尾部还是中间节点,都不会出现空指针异常,链表结构保持完整,长度也会正确更新。

内容的提问来源于stack exchange,提问作者Sima Elsherif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:55:02