C++ 中链表的复制构造函数
这篇简短的文章是关于具有深拷贝构造函数的基于 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
相关文章
在 C++ 中通过掷骰子生成随机值
发布时间:2023/04/09 浏览次数:169 分类:C++
-
本文解释了如何使用时间因子方法和模拟 C++ 中的掷骰子的任意数方法生成随机数。了解它是如何工作的以及它包含哪些缺点。提供了一个 C++ 程序来演示伪数生成器。
在 C++ 中使用模板的链表
发布时间:2023/04/09 浏览次数:158 分类:C++
-
本文解释了使用模板在 C++ 中创建链表所涉及的各个步骤。工作程序演示了一个链表,该链表使用模板来避免在创建新变量时声明数据类型的需要。
在 C++ 中添加定时延迟
发布时间:2023/04/09 浏览次数:142 分类:C++
-
本教程将为你提供有关在 C++ 程序中添加定时延迟的简要指南。这可以使用 C++ 库为我们提供的一些函数以多种方式完成。
在 C++ 中创建查找表
发布时间:2023/04/09 浏览次数:155 分类:C++
-
本文重点介绍如何创建查找表及其在不同场景中的用途。提供了三个代码示例以使理解更容易,并附有代码片段以详细了解代码。
如何在 C++ 中把字符串转换为小写
发布时间:2023/04/09 浏览次数:63 分类:C++
-
介绍了如何将 C++ std::string 转换为小写的方法。当我们在考虑 C++ 中的字符串转换方法时,首先要问自己的是我的输入字符串有什么样的编码
如何在 C++ 中确定一个字符串是否是数字
发布时间:2023/04/09 浏览次数:163 分类:C++
-
本文介绍了如何检查给定的 C++ 字符串是否是数字。在我们深入研究之前,需要注意的是,以下方法只与单字节字符串和十进制整数兼容。
如何在 c++ 中查找字符串中的子字符串
发布时间:2023/04/09 浏览次数:65 分类:C++
-
本文介绍了在 C++ 中检查一个字符串是否包含子字符串的多种方法。使用 find 方法在 C++ 中查找字符串中的子字符串
如何在 C++ 中把字符串转换为 Char 数组
发布时间:2023/04/09 浏览次数:107 分类:C++
-
本文介绍了在 C++ 中把字符串转换为 char 数组的多种方法。使用 std::basic_string::c_str 方法将字符串转换为 char 数组