迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > C++ >

C++ 中链表的复制构造函数

作者:迹忆客 最近更新:2023/03/15 浏览次数:

这篇简短的文章是关于具有深拷贝构造函数的基于 C++ 的链表实现。

C++ 中的复制构造函数

调用复制构造函数以使用同一类的另一个对象初始化对象。复制构造函数在多种情况下被调用,例如:

  • 当使用另一个对象复制一个对象时。
  • 当对象作为函数的值返回时。
  • 当对象作为值传递给函数时。

在每个类中,总会有一个默认的拷贝构造函数,但它不执行深拷贝,而是执行浅拷贝。只有指针的地址被浅拷贝复制,并且两个对象(即调用者和传递的对象)都指向同一个内存。

相反,在深拷贝中,数据成员的值被复制到目标对象数据成员。

C++ 中的链表

链表数据结构以可以动态增长的数据节点的形式存储数据。它不需要连续的内存,因此可以有效地存储在内存中的任何位置。

C++ 中的链表实现

让我们开始实现链表。首先,我们需要创建一个类来获取数据节点:

template <class T >
class Node
{
public:
    T info;
    Node<T>* next;

    Node ( ){
        next = 0;
    }
    Node ( T val ){
        info = val;
        next = 0;
    }
};

Node 类有两个成员——一个用于存储数据(即 info),另一个是指向该类本身的指针,用于存储下一个节点的地址。该类被模板化,以便可以创建任何数据类型的列表。

上面的实现提供了两个构造函数。第一个是默认构造函数,另一个是参数化的。

我们来看一下链表的模板类:

template <class T>
class LSLL
{
private:
    Node<T> * head;
public:
    LSLL ( ){
        head = 0;
    }
};

LSLL 类只有一个指向 Node 类的指针,用于保存链表第一个节点的地址。

为了向用户提供将一个链表对象深度复制到另一个的功能,我们需要提供一个用户定义的复制构造函数实现,如下所示:

LSLL(LSLL& PassedObj)
{
    if (PassedObj.head == NULL) {
        head = NULL;
    }
    else {
        //copy all nodes of PassedObj to the caller object
        //attach first node to the head of the caller object
        Node<T>* newNode = new Node<T>();
        newNode->info = PassedObj.head->info;
        newNode->next = NULL;
        head = newNode;

        //Now deep-copy all the remaining nodes of the Passed linked list object
        Node<T>* PassedItr = PassedObj.head->next;
        Node<T>* CallerItr = head;
        while (PassedItr != NULL)
        {
            CallerItr->next = new Node<T>();
            CallerItr->next->info = PassedItr->info;
            CallerItr->next->next = NULL;
            CallerItr = CallerItr->next; //move to newly added node
            PassedItr = PassedItr->next; //move one node further
        }
    }
}

上面的代码段创建了传递对象的第一个节点的深层副本,并将其附加到调用者列表对象的 head。之后,传递对象的所有剩余节点都被深度复制并附加到调用者链表节点。

让我们对整个实现有一个认知的看法。

#include <iostream>
using namespace std;

template <class T >
class Node
{
public:
    T info;
    Node<T>* next;

    Node()
    {
        next = NULL;
    }
    Node(T val)
    {
        info = val;
        next = NULL;
    }
};

template <class T>
class LSLL
{
private:
    Node<T>* head;
public:
    LSLL()
    {
        head = NULL;
    }
    LSLL(LSLL& PassedObj)
    {

        if (PassedObj.head == NULL) {
            head = NULL;
        }
        else {
            //copy all nodes of PassedObj to the caller object
            //attach first node to the head of the caller object
            Node<T>* newNode = new Node<T>();
            newNode->info = PassedObj.head->info;
            newNode->next = NULL;
            head = newNode;

            //Now deep-copy all the remaining nodes of the Passed linked list object
            Node<T>* PassedItr = PassedObj.head->next;
            Node<T>* CallerItr = head;
            while (PassedItr != NULL)
            {
                CallerItr->next = new Node<T>();
                CallerItr->next->info = PassedItr->info;
                CallerItr->next->next = NULL;
                CallerItr = CallerItr->next; //move to newly added node
                PassedItr = PassedItr->next; //move one node further
            }
        }
    }
    void insertAtHead(T val)
    {
        Node<T>* x = new Node<T>(val);
        x->next = head;
        head = x;
    }
    void displayAll()
    {
        Node<T>* x = head;
        {
            while (x != 0)
            {
                cout << x->info << endl;
                x = x->next;
            }
        }
    }
    int isEmpty()
    {
        if (head == 0)
            return 1;
        return 0;
    }
    void insetAtTail(T val)
    {
        Node<T>* x = head;
        if (isEmpty())
        {
            insertAtHead(val);
            return;
        }

        while (x->next != 0)
        {
            x = x->next;
        }
        x->next = new Node<T>(val);
    }
    void insertAfter(T key, T val)
    {
        if (isEmpty())
            return;

        Node<T>* x = head;
        while (x != 0 && x->info == key)
            x = x->next;

        if (!x)
            return;

        Node<T>* temp = new Node<T>(val);

        temp->next = x->next;
        x->next = x;
    }
};
int main()
{
    LSLL<int> list;
    list.insertAtHead(200);
    list.insertAtHead(100);
    list.insetAtTail(300);
    list.displayAll();

    LSLL<int> list2(list);
    cout << "List2: " << endl;
    list2.displayAll();
    return 0;
}

主驱动代码首先创建一个 list 对象,在其中插入三个节点,然后调用 displayAll 函数。之后,它创建一个新的链表对象 list2 并以 list 作为参数调用其参数化的复制构造函数。

请注意,list2 对象是调用者对象,而 list 是传递对象。

输出:

100
200
300
List2:
100
200
300

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Arduino 中停止循环

发布时间:2024/03/13 浏览次数:444 分类:C++

可以使用 exit(0),无限循环和 Sleep_n0m1 库在 Arduino 中停止循环。

Arduino 复位

发布时间:2024/03/13 浏览次数:315 分类:C++

可以通过使用复位按钮,Softwarereset 库和 Adafruit SleepyDog 库来复位 Arduino。

Arduino 的字符转换为整型

发布时间:2024/03/13 浏览次数:181 分类:C++

可以使用简单的方法 toInt()函数和 Serial.parseInt()函数将 char 转换为 int。

Arduino 串口打印多个变量

发布时间:2024/03/13 浏览次数:381 分类:C++

可以使用 Serial.print()和 Serial.println()函数在串口监视器上显示变量值。

Arduino if 语句

发布时间:2024/03/13 浏览次数:123 分类:C++

可以使用 if 语句检查 Arduino 中的不同条件。

Arduino ICSP

发布时间:2024/03/13 浏览次数:214 分类:C++

ICSP 引脚用于两个 Arduino 之间的通信以及对 Arduino 引导加载程序进行编程。

使用 C++ 编程 Arduino

发布时间:2024/03/13 浏览次数:127 分类:C++

本教程将讨论使用 Arduino IDE 在 C++ 中对 Arduino 进行编程。

Arduino 中的子程序

发布时间:2024/03/13 浏览次数:168 分类:C++

可以通过在 Arduino 中声明函数来处理子程序。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便