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

如何实现带计数字段的链表复制函数并返回新链表头指针?

嘿,我来帮你搞定这个带count字段的链表复制问题!首先咱们先捋捋你现有代码里的几个关键bug(这些会导致程序跑不起来或者行为异常),然后再实现链表复制的核心功能。

现有代码的主要问题
  • 构造函数逻辑错误:你的set类构造函数里一开始就遍历delete节点,但此时head是NULL,这个循环完全没必要,反而容易触发未定义行为,应该只初始化head为NULL即可。
  • isLast函数空指针问题:last指针没有初始化就直接访问last->next,会导致程序崩溃,正确做法是先遍历到链表末尾再判断。
  • insert函数链接缺失:插入新节点时,你创建了新节点但没有把它链接到原链表的末尾,需要先找到最后一个节点再完成链接。
  • deleteLast函数语法错误:Snode *current= new head;是非法写法,应该直接用Snode *current = head;,而且不需要用new创建previous指针。
  • count函数逻辑混乱:循环里每次都会输出内容,不管有没有找到目标字符,而且最后返回temp->count时temp可能已经是NULL,会导致崩溃。
  • remove函数赋值错误:while(current->next=NULL)是赋值操作而非判断,应该改成while(current->next != NULL),而且参数temp的作用不明确,应该从head开始遍历找目标节点。
实现链表复制函数

要复制整个链表到新内存,我们需要遍历原链表的每个节点,为每个节点分配新的内存空间,复制data和count字段,再把这些新节点依次链接起来,最后返回新链表的头节点。因为head是set类的私有成员,所以我们在类中添加一个成员函数来实现这个功能最合理。

修正后的完整代码(包含复制功能)

#include <iostream>
using namespace std;

struct Snode {
    char data;
    int count = 1;
    Snode *next = NULL;
    Snode(char a) : data(a) {}
};

class set {
private:
    Snode *head;
public:
    // 修正构造函数:仅初始化head为NULL
    set() : head(NULL) {}

    // 析构函数保持正常逻辑
    ~set() {
        Snode *temp = head;
        while (temp != NULL) {
            head = head->next;
            delete temp;
            temp = head;
        }
    }

    bool isAvailable(char value) {
        Snode *temp = head;
        while (temp != NULL) {
            if (temp->data == value)
                return true;
            temp = temp->next;
        }
        return false;
    }

    bool isFirst(char value) {
        if (head == NULL) return false;
        return (head->data == value);
    }

    // 修正isLast函数
    bool isLast(char value) {
        if (head == NULL) return false;
        Snode *last = head;
        while (last->next != NULL) {
            last = last->next;
        }
        return (last->data == value);
    }

    void display() {
        Snode *temp = head;
        while (temp != NULL) {
            cout << temp->data << " " << temp->count << "\n";
            temp = temp->next;
        }
    }

    // 修正insert函数:补全新节点链接逻辑
    void insert(char value) {
        if (head == NULL) {
            Snode *temp = new Snode(value);
            temp->count = 1;
            head = temp;
        } else {
            if (isAvailable(value)) {
                Snode *temp = head;
                while (temp->data != value)
                    temp = temp->next;
                temp->count += 1;
            } else {
                Snode *temp = new Snode(value);
                temp->count = 1;
                temp->next = NULL;
                // 找到原链表最后一个节点
                Snode *last = head;
                while (last->next != NULL) {
                    last = last->next;
                }
                last->next = temp;
            }
        }
    }

    // 修正count函数
    int count(char value) {
        Snode *temp = head;
        while (temp != NULL) {
            if (temp->data == value) {
                cout << temp->count << endl;
                return temp->count;
            }
            temp = temp->next;
        }
        cout << "This character is not in the list" << endl;
        return -1; // 返回-1标记未找到
    }

    void deleteFirst() {
        if (head == NULL) return;
        Snode *temp = head;
        head = head->next;
        delete temp;
    }

    // 修正deleteLast函数
    void deleteLast() {
        if (head == NULL) return;
        // 处理只有一个节点的情况
        if (head->next == NULL) {
            delete head;
            head = NULL;
            return;
        }
        Snode *current = head;
        Snode *previous = NULL;
        while (current->next != NULL) {
            previous = current;
            current = current->next;
        }
        previous->next = NULL;
        delete current;
    }

    // 修正remove函数
    void remove(char value) {
        if (!isAvailable(value)) {
            cout << "Not available" << endl;
            return;
        }
        Snode *temp = head;
        Snode *prev = NULL;
        // 定位目标节点
        while (temp != NULL && temp->data != value) {
            prev = temp;
            temp = temp->next;
        }
        if (temp->count == 1) {
            if (isFirst(value)) {
                deleteFirst();
            } else if (isLast(value)) {
                deleteLast();
            } else {
                prev->next = temp->next;
                delete temp;
            }
        } else {
            temp->count--;
        }
    }

    // 新增:复制链表到新内存,返回新链表头节点
    Snode* copyLinkedList() {
        if (head == NULL) {
            return NULL; // 原链表为空,直接返回NULL
        }
        // 创建新链表的头节点
        Snode *newHead = new Snode(head->data);
        newHead->count = head->count;
        Snode *currentOriginal = head->next;
        Snode *currentNew = newHead;

        // 遍历原链表,逐个复制节点
        while (currentOriginal != NULL) {
            Snode *newNode = new Snode(currentOriginal->data);
            newNode->count = currentOriginal->count;
            // 链接到新链表末尾
            currentNew->next = newNode;
            // 移动指针继续遍历
            currentNew = newNode;
            currentOriginal = currentOriginal->next;
        }
        currentNew->next = NULL; // 新链表末尾置空,保证结构正确
        return newHead;
    }

    // 静态工具函数:打印复制后的链表(用于测试)
    static void printCopiedList(Snode *head) {
        Snode *temp = head;
        while (temp != NULL) {
            cout << temp->data << " " << temp->count << "\n";
            temp = temp->next;
        }
    }
};

int main() {
    set mySet;
    mySet.insert('c');
    mySet.insert('a');
    mySet.insert('a');
    mySet.insert('c');
    mySet.insert('c');

    cout << "原链表内容:" << endl;
    mySet.display();

    // 复制链表
    Snode *copiedHead = mySet.copyLinkedList();
    cout << "\n复制后的链表内容:" << endl;
    set::printCopiedList(copiedHead);

    // 手动释放复制后的链表内存,避免内存泄漏
    Snode *temp = copiedHead;
    while (temp != NULL) {
        Snode *next = temp->next;
        delete temp;
        temp = next;
    }

    return 0;
}

复制函数核心逻辑说明

  1. 空链表判断:如果原链表为空,直接返回NULL,避免无效操作。
  2. 创建新头节点:为原链表的头节点分配新内存,复制data和count字段。
  3. 遍历复制节点:用两个指针分别遍历原链表和新链表,为每个原节点创建对应的新节点,复制数据后链接到新链表末尾。
  4. 末尾置空:新链表最后一个节点的next设为NULL,保证链表结构完整。
  5. 内存释放:使用完复制后的链表后,要手动释放其内存,避免内存泄漏。

这样得到的新链表完全独立于原链表,修改任意一方都不会影响另一方,所有节点都在新的内存区域。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:19:11