[英]Implementing copy constructor in a single linked list C++
我有一個C ++代碼:
#include <iostream>
using namespace std;
struct Node;
typedef Node *NodePtr;
struct Node
{
int Item;
NodePtr Next;
};
class LinkedList
{
public:
LinkedList(); // default constructor
~LinkedList(); // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
};
LinkedList::LinkedList()
{
Head = NULL; //declare head as null
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr Crnt;
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
//if head is in null declare the added node as head
if (Head == NULL)
{
Head = node;
}
else
{ //set the current to head, move the current node to current next node
Crnt = Head;
while (Crnt->Next != NULL)
{
Crnt = Crnt->Next;
}
//Add item to the tail of the linked list
Crnt->Next = node;
}
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb;
return 0;
}
所以我的問題是如何實現一個復制構造函數(假設在對象lb上),它創建了list參數的深層副本,還添加了用於在空和非空列表上測試復制構造函數的代碼? 提前致謝。
編程的一個重要規則是不要重復自己(DRY)。 如果您有一個添加的功能,並且您知道它可以正常工作,請繼續將其用於與添加相關的作業。 這意味着保持添加死愚蠢和多才多藝符合您的最佳利益。
應用DRY原理,復制構造函數(假設AddTail
方法正常工作)非常簡單:為源列表中的每個節點調用AddTail
。
LinkedList::LinkedList(const LinkedList & src):Head(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
由於Copy和Swap Idiom ,擁有一個工作副本構造函數使得賦值運算符也很簡單:
LinkedList & LinkedList::operator=(LinkedList src)
// pass by reference performs the copy
{
std::swap(Head, src.Head); // now just swap the head of the copy
// for the head of the source
return *this;
} // destructor fires for src and cleans up all the nodes that were on this list
為了完成三個三法則,我們需要一個析構函數。 這與復制構造函數一樣是DRY的應用程序:反復調用節點刪除功能,直到列表為空。 刪除函數幾乎是任何鏈表的必然要求,所以在這里我假設有一個名為Remove
。
LinkedList::~LinkedList()
{
while (Head != nullptr)
{
NodePtr temp = Head;
Remove(Head);
delete temp;
}
}
因此,現在基於鏈接列表無法運行的兩個功能,我們已經實現了基本維護所需的所有其他功能。 您所需要的只是經過測試和無錯誤的Add
和Remove
功能,其余的幾乎是免費的。
而且因為AddTail
函數擊中了我的一個寵物洞......這是一個大大降低函數復雜性的技巧:
void LinkedList::AddTail(int Item)
{
NodePtr *Crnt = &Head; // instead of pointing where Head points, point at
// Head now we don't care if it is head or any
// other node's Next. They are all abstracted to
// the same thing: A pointer to where the next
// node can be found
while (*Crnt != NULL) // keep looking until end of list
{
Crnt = &(*Crnt)->Next; // by pointing at the next Next pointer
}
//Add item to the tail of the linked list
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
*Crnt = node; // Now just plop the new node over top of the terminating NULL
}
我沒有實現的Remove
函數使用相同的指針 - 指針技巧。
試試這個( https://ideone.com/9lywXc使用您原來發布的代碼)
LinkedList::LinkedList(const LinkedList& other):Head(nullptr)
{
cout << "copy constructor called:\n";
if(other.Head == nullptr) return;
NodePtr dummyHead = new Node;
NodePtr curr = dummyHead;
NodePtr othcurr = other.Head;
for(; othcurr!=nullptr; othcurr = othcurr->Next)
{
curr->Next = new Node;
curr = curr->Next;
cout << (curr->Item = othcurr->Item) << ",";
curr->Next = nullptr;
}
Head = dummyHead->Next;
delete dummyHead;
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
return 0;
}
輸出:
復制構造函數調用:
30,60,90,
這是對user4581301之前的答案的改進,因此復制構造函數在輸入列表大小上是O(n)。 在封裝列表類中使用一個額外的指針跟蹤尾部:
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
//KEEP TRACK OF TAIL POINTER WITH EXTRA MEMBER
NodePtr Tail;
};
//via user4581301 response
LinkedList::LinkedList(const LinkedList & src):Head(nullptr),Tail(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr np = new Node{Item,nullptr};
if(Tail == nullptr && Head == nullptr)
Head = Tail = np;
else
{
Tail->Next = np;
Tail = Tail->Next;
}
}
關於測試:您可以添加功能來吐出列表的內容。 或者您可以將其子類化為測試擴展。 或者你可以使用operator <<()破壞這樣的封裝:
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
//breaks encapsulation but make some nice sugar to look inside
friend ostream& operator<<(ostream& s, LinkedList& l)
{
s << "list contents: ";
NodePtr c = l.Head;
for(; c!=nullptr;c=c->Next)
s << c->Item << " ";
s << endl;
return s;
}
private:
NodePtr Head;
NodePtr Tail;
};
以便
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
cout << lb;
return 0;
}
吐出:列表內容:30 60 90
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.