|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 丶不离不弃 于 2019-11-12 14:27 编辑
链表的增加和删减,前面是析构器和复制构造器以及move构造器,能看看为啥我的程序编译没有问题但是什么结果都没出来呢?
老师给我们写了一个例子,但是总感觉有点问题,而且不是太懂。。。
如下:
- #include <iostream>
- using namespace std;
- class LinkedList {
- private:
- class Node { // LinkedList::Node
- public:
- int data;
- Node* next;
- Node(int v, Node* n) : data(v) {}
- };
- Node* head;
- public:
- LinkedList() : head(nullptr) {}
- ~LinkedList() {
- Node* q;
- for (Node* p = head; p != nullptr; p = q) {
- q = p->next;
- delete p;
- }
- }
- // if you do not want to implement copy constructor use =delete (C++11)
- // LinkedList(const LinkedList& orig) = delete;
- // LinkedList& operator =(const LinkedList& orig) = delete;
- // LinkedList(LinkedList&& orig) {}
- LinkedList(const LinkedList& orig) {
- if (orig.head== nullptr) {
- head = nullptr;
- return;
- }
- head = new Node(orig.head->data, nullptr);
- Node* p = orig.head->next;
- if (p == nullptr)
- return;
- // there are at least 2 nodes
- Node* q = head;
- for (; p != nullptr; p = p->next, q = q->next)
- q->next = new Node(p->data, nullptr);
- }
-
- LinkedList& operator =(LinkedList copy) {
- swap(head, copy.head);
- return *this;
- }
- /*
- _______
- temp->| data|
- | next|--> head
- -------
- */
- void addStart(int v) {
- #if 0
- Node* temp = new Node();
- temp->data = v;
- temp->next = head;
- head = temp;
- #endif
- head = new Node(v, head);
- }
-
- void addEnd(int v) {
- if (head == nullptr) {
- head = new Node(v, nullptr);
- return;
- }
- Node* p;
- for (p = head; p->next != nullptr; p = p->next)
- ;
- // p = pointing to the last element
- p->next = new Node(v, nullptr);
- }
- friend ostream& operator <<(ostream& s, const LinkedList& list) {
- for (Node* p = list.head; p != nullptr; p =p->next)
- s << p->data << ' ';
- return s;
- }
- };
- int main() {
- LinkedList a; // a is empty
- a.addStart(3);
- a.addEnd(1);
- a.addStart(4);
- cout << a;
- }
复制代码
附上老师的要求,要求将public里面的内容写完整,使得main函数的功能得以实现:
- class LinkedList2 {
- private:
- class Node { // LinkedList2::Node
- public:
- int val;
- Node* next;
- };
- Node* head;
- Node* tail;
- public:
- LinkedList2();
- ~LinkedList2() ;
- LinkedList2(const LinkedList2& orig);
- LinkedList2& operator =(const LinkedList2& orig);
- // move constructor
- LinkedList2(LinkedList2&& orig) { // steal orig data while it's dying (nice)
- }
- void addStart(int v);
- void addEnd(int v);
- void removeStart();
- void removeEnd();
- };
- /**
- head --> nullptr
- head --> [ val=3 next= nullptr ]
- head --> [val=1 next= ----> [ val=3 next= nullptr ]
- */
- int main() {
- LinkedList2 a;
- a.addStart(3); // 3 is the first element in the list
- a.addStart(1); // 1 3
- a.addStart(4); // 4 1 3
- for (int i = 1; i <= 5; i++)
- a.addEnd(i);
- a.removeStart();
- a.removeEnd();
- cout << a << '\n'; // print out the list, separated by spaces or commas
-
- LinkedList2 b = a;
- cout << b << '\n';
-
- LinkedList2 c;
- c.addStart(5);
- c = b; // wipe out c, copy in b
- cout << c << '\n';
- }
复制代码
本帖最后由 superbe 于 2019-11-15 02:10 编辑
1. 前面理解的对,后面这句话“最后创建temp来指向*p,随着*p遍历orig.list,将*q->next=temp也就是q=p?”不对,temp指向新建的一个节点,不是指向*p,从内存地址上来理解,temp节点跟*p完全不同。每次新建节点后,通过*q->next=temp;把新节点添加到本链表尾部,然后q=q->next使q后移,以便继续添加新节点。这种复制方式就是所谓的深拷贝,就是将实参链表在内存中复制了一份,互不影响。而浅拷贝只是把头尾指针赋值给head,tail,这样和实参链表实际上在内存中是同一份,其中一个delete了,等于另外一个也不能正常使用了。
2. “因为q在开始=head的原因?然后对*q的操作就等于对本链表的操作吗?”可以这么认为,根据这个head中的next成员(一个指向下一节点的指点),就可以依次顺藤摸瓜,找到链表所有节点,直到尾节点。
3. 你的意思是遍历orig.list,把所有节点指针依次给本链表?这样的话,从一开头执行本链表.head=orig.head后,实际上就已经是同一链表了(后面就不用再遍历了),从内存地址上理解一下。但这是不行的,涉及到内存分配的复制构造函数,应该使用深拷贝(见1.)。
4. 上面的代码copy constructor和new way operator=,本链表和原链表地址不同。而move constructor,本链表和原链表地址相同。这个operator=是这样的,由于不是按引用传递,传参时会调用copy constructor创建一个链表,然后operator=通过swap获得了该链表的head和tail,只要确定了head和tail那么本链表也就确定了。退出operator=时,由于orig是临时变量,会调用析构函数销毁创建的链表(由于swap,其实是本链表原来的旧链表)。我原来的理解也是不太对的。
5. “无论这个链表又多长?如果head=null”,这是不可能的,正常的链表只要链表中有节点,head就不会为null,至少也应该有一个节点就是head本身,通过head才能找到后续节点,head怎么能为null呢。当head为null,说明链表为空,如果需要在最后添加一个节点,那就只好新建一个节点把它做为head。
6. Node* temp=new Node这句new Node会分配一块内存并把地址给temp。Node* q;的话,只是声明一个指针变量,并没有给它赋值,不确定它里面保存的是什么值。
Node* q=head;就是声明的同时也给它赋值一个地址了。添加节点时需要创建一个真正的内存中的节点,当然要new了,删除节点时delete要求提供一个指针就可以把指向的内存释放,当然就不用new了。
|
|