实训11_复杂类的实现_LinkedList类的实现

第1关:构造函数与析构函数的实现

任务描述

LinkedList 类是一个比较复杂的类,首先需要实现其构造函数。要求用户为 LinkedList 类提供 4 种构造函数。分别是:

默认构造函数

使用该函数构造出的数组对象,逻辑上是空的

拷贝构造函数

使用该函数构造出的输出对象,逻辑上的内容应与参数一模一样

原生输出构造函数

给定一个C++的原生数组,构造出内容一模一样的数组对象

填充构造函数

给定参数 n 与 value,构造出一个数组对象,其内容是 n 个 value。

在构造函数中,涉及到申请内存。凡是与系统资源打交道的代码一定要做异常检测。内存就是一种系统资源,所以一定要坚持申请内存是否成功。不过本任务忽略这一步。

此外,还需要实现析构函数。因为 LinkedListArrayList 类一样,必须要自行提供析构函数。

相关知识

从数据结构的角度,LinkedList 类就代表链表。要实现链表,首先就需要定义链表节点。因为此处实现的是单链表,所以表示链表节点的结构体定义如下:

 
  1. struct Node{
  2. int data; //仍然假定只保存int类型数据
  3. Node *next;//指针
  4. //为该结构体提供一个构造函数
  5. Node(int a=0,Node*b=nullptr):data(a),next(b){}
  6. };

同时需要注意,这个结构体与链表有关,所以一般定义在链表类的内部,是一个内部结构体。

编程要求

根据提示,在右侧编辑器的Begin-End区域内补充代码。

测试说明

该项目一共有3个文件,main.cpp、LinkedList.h 和 LinkedList.cpp。其中 main.cpp 是测试文件,LinkedList.h 包含 LinkedList 类的定义和成员函数声明。用户仅能修改 LinkedList.cpp 中的内容,在其中实现LinkedList的成员函数。 LinkedList.h 的内容如下

 
  1. #ifndef _LINKEDLIST_H_
  2. #define _LINKEDLIST_H_
  3. class LinkedList{
  4. public:
  5. //这是单链表节点的结构体
  6. struct Node{
  7. int data;
  8. Node *next;
  9. Node(int a=0,Node *b=nullptr):data(a),next(b){}
  10. };
  11. private:
  12. Node *head;//链表的头结点
  13. int size; //保存数据的数量,这是一个冗余数据
  14. public:
  15. //默认构造函数,构造一个逻辑为空的链表
  16. LinkedList();
  17. //拷贝构造函数,构造一个逻辑上与参数内容相同的链表
  18. LinkedList(const LinkedList&rhs);
  19. //原生数组构造函数,构造一个内容与给定数组相同的链表
  20. LinkedList(int const a[],int n);
  21. //填充构造函数,构造一个内容为n个value的链表
  22. LinkedList(int n,int value);
  23. //析构函数,一定要自行实现,否则有内存泄漏
  24. ~LinkedList();
  25. //无话可说
  26. int getSize()const{return size;}
  27. };
  28. #endif // _LINKEDLIST_H_

main.cpp 的内容如下

 
  1. #include <iostream>
  2. #include "LinkedList.h"
  3. using namespace std;
  4. int A[] = {100,200,400,800,1600};
  5. int main(){
  6. LinkedList a,b(A,4);
  7. LinkedList c(b),d(8,6);
  8. cout<<a.getSize()<<" "<<b.getSize()<<" "<<c.getSize()<<" "<<d.getSize()<<endl;
  9. return 0;
  10. }

代码

/********** BEGIN **********/

#include "LinkedList.h"

#include <iostream>

using namespace std;



LinkedList::LinkedList(){

   

    head=nullptr;

    size=0;

}

LinkedList::LinkedList(const LinkedList &rhs)  {

    head=nullptr;

    size=rhs.size;

    Node *temp = rhs.head;

    Node *last = nullptr;

    while (temp != nullptr) {

        Node *newNode = new Node(temp->data);

        if (head == nullptr) {

            head = newNode;

            last = newNode;

        } else {

            last->next = newNode;

            last = newNode;

        }

        temp = temp->next;

    }

}

LinkedList::LinkedList(int const a[], int n) : head(nullptr), size(n) {

    Node *last = nullptr;

    for (int i = 0; i < n; i++) {

        Node *newNode = new Node(a[i]);

        if (head == nullptr) {

            head = newNode;

            last = newNode;

        } else {

            last->next = newNode;

            last = newNode;

        }

    }

}



LinkedList::LinkedList(int n, int value) : head(nullptr), size(n) {

    Node *last = nullptr;

    for (int i = 0; i < n; i++) {

        Node *newNode = new Node(value);

        if (head == nullptr) {

            head = newNode;

            last = newNode;

        } else {

            last->next = newNode;

            last = newNode;

        }

    }

}



LinkedList::~LinkedList() {

    Node *temp = head;

    while (temp != nullptr) {

        Node *nextNode = temp->next;

        delete temp;

        temp = nextNode;

    }

}

 第2关:成员函数的实现

 任务描述

LinkedList 类实现增、删、查、改 4 种功能函数,同时为了显示输出,再实现一个 disp 函数,将数组内容输出到显示器。用户仍然要自行实现上一关中的构造函数与析构函数。

 
  1. void insert(int pos,int value);

insert 函数在 pos 位置(从 0 开始编号)插入一个值为 value 的元素;

 
  1. void remove(int pos);

remove 函数将 pos 位置上的元素删除;

 
  1. int at(int pos)const;

at 函数返回 pos 位置上元素的值;

 
  1. void modify(int pos,int newValue);

modify 函数将 pos 位置上的元素值修改为 newValue;

 
  1. void disp()const;

disp函数将所保存的数据输出到屏幕,输出为一行,每个数据后面接一个空格。

通过观察可以,增、删、查、改都需要实现一个共同的功能,即:找到对应节点的指针。因此,再增加一个辅助函数:

 
  1. Node *advance(int pos)const

返回指定位置的指针。 同时,由于这个函数是用于实现内部功能,所以将其设置为 private

相关知识

对于增、删操作而言,都需要找到待操作节点的前一个节点。因此,如果是普通单链表,就有一个问题:头节点没有前一个节点。因此对头结点做增、删需要特殊的操作。 因此,这里建议使用带空头节点的链表。这样一来,所有合法位置上的增、删操作就可以保持一致了。 删除节点,一定要记住释放相应的内存

编程要求

根据提示,在右侧编辑器的Begin-End区域内补充代码。

测试说明

该项目一共有3个文件,main.cpp、LinkedList.h 和 LinkedList.cpp。其中 main.cpp 是测试文件,LinkedList.h 包含 LinkedList 类的定义和成员函数声明。用户仅能修改 LinkedList.cpp 中的内容,在其中实现 LinkedList 的成员函数。

 
  1. #ifndef _LINKEDLIST_H_
  2. #define _LINKEDLIST_H_
  3. class LinkedList{
  4. public:
  5. //这是单链表节点的结构体
  6. struct Node{
  7. int data;
  8. Node *next;
  9. Node(int a=0,Node *b=nullptr):data(a),next(b){}
  10. };
  11. private:
  12. Node *head;//链表的头结点
  13. int size; //保存数据的数量,这是一个冗余数据
  14. public:
  15. //默认构造函数,构造一个逻辑为空的链表
  16. LinkedList();
  17. //拷贝构造函数,构造一个逻辑上与参数内容相同的链表
  18. LinkedList(const LinkedList&rhs);
  19. //原生数组构造函数,构造一个内容与给定数组相同的链表
  20. LinkedList(int const a[],int n);
  21. //填充构造函数,构造一个内容为n个value的链表
  22. LinkedList(int n,int value);
  23. //析构函数,一定要自行实现,否则有内存泄漏
  24. ~LinkedList();
  25. //无话可说
  26. int getSize()const{return size;}
  27. //增删查改
  28. void insert(int pos,int value);
  29. void remove(int pos);
  30. int at(int pos)const;
  31. void modify(int pos,int newValue);
  32. void disp()const;
  33. private:
  34. //辅助函数,返回指定位置的节点的指针
  35. Node *advance(int pos)const;
  36. };
  37. #endif // _LINKEDLIST_H_

main.cpp 的内容如下:

 
  1. #include <iostream>
  2. #include "LinkedList.h"
  3. using namespace std;
  4. int main(){
  5. int n,x;
  6. LinkedList a;
  7. cin>>n;
  8. for(int i=0;i<n;++i){
  9. cin>>x;
  10. a.insert(a.getSize(),x);
  11. }
  12. a.disp();
  13. for(int i=0;i<3&&a.getSize()!=0;++i){
  14. a.remove(0);
  15. }
  16. a.disp();
  17. for(int i=0;i<a.getSize();i+=2){
  18. a.modify(i,a.at(i)*10);
  19. }
  20. a.disp();
  21. return 0;
  22. }

       代码

#include "LinkedList.h"

#include <iostream>



LinkedList::LinkedList() : head(nullptr), size(0) {}




LinkedList::LinkedList(const LinkedList& rhs) : head(nullptr), size(rhs.size) {

    if (rhs.head != nullptr) {

        Node* rhsCurr = rhs.head;

        head = new Node(rhsCurr->data);

        Node* curr = head;

        rhsCurr = rhsCurr->next;

        while (rhsCurr != nullptr) {

            curr->next = new Node(rhsCurr->data);

            curr = curr->next;

            rhsCurr = rhsCurr->next;

        }

    }

}



LinkedList::LinkedList(int const a[], int n) : head(nullptr), size(n) {

    if (n > 0) {

        head = new Node(a[0]);

        Node* curr = head;

        for (int i = 1; i < n; i++) {

            curr->next = new Node(a[i]);

            curr = curr->next;

        }

    }

}



LinkedList::LinkedList(int n, int value) : head(nullptr), size(n) {

    if (n > 0) {

        head = new Node(value);

        Node* curr = head;

        for (int i = 1; i < n; i++) {

            curr->next = new Node(value);

            curr = curr->next;

        }

    }

}



// 析构函数

LinkedList::~LinkedList() {

    Node* curr = head;

    while (curr != nullptr) {

        Node* next = curr->next;

        delete curr;

        curr = next;

    }

}



// 辅助函数,返回指定位置的节点的指针

LinkedList::Node* LinkedList::advance(int pos) const {

    if (pos < 0 || pos >= size) {

        return nullptr;

    }

    Node* current = head;

    for (int i = 0; i < pos; i++) {

        current = current->next;

    }

    return current;

}



// 插入函数

void LinkedList::insert(int pos, int value) {

    if (pos < 0 || pos > size) {

        std::cout << "Invalid position for insertion" << std::endl;

        return;

    }

    if (pos == 0) {

        Node* newNode = new Node(value, head);

        head = newNode;

    } else {

        Node* prev = advance(pos - 1);

        Node* newNode = new Node(value, prev->next);

        prev->next = newNode;

    }

    size++;

}



// 删除函数

void LinkedList::remove(int pos) {

    if (pos < 0 || pos >= size) {

        std::cout << "Invalid position for removal" << std::endl;

        return;

    }

    Node* toDelete;

    if (pos == 0) {

        toDelete = head;

        head = head->next;

    } else {

        Node* prev = advance(pos - 1);

        toDelete = prev->next;

        prev->next = toDelete->next;

    }

    delete toDelete;

    size--;

}



// 获取指定位置的值

int LinkedList::at(int pos) const {

    if (pos < 0 || pos >= size) {

        std::cout << "Invalid position" << std::endl;

        return -1; // Assuming -1 as an invalid value

    }

    Node* node = advance(pos);

    return node->data;

}



// 修改指定位置的值

void LinkedList::modify(int pos, int newValue) {

    if (pos < 0 || pos >= size) {

        std::cout << "Invalid position for modification" << std::endl;

        return;

    }

    Node* node = advance(pos);

    node->data = newValue;

}



// 显示链表内容

void LinkedList::disp() const {

    Node* curr = head;

    while (curr != nullptr) {

        std::cout << curr->data << " ";

        curr = curr->next;

    }

    std::cout << std::endl;

}

第3关:运算符重载 

任务描述

LinkedList 类做相关的运算符重载,包括:2 个赋值运算符(简单赋值与加号赋值)、1 个算术运算符(加号)、6 个关系运算符、1 个流输出运算符和 2 个方括号运算符(const 版本与非 const 版本)。 加号运算完成连接操作,而关系运算按照字典序比较。

相关知识

方括号运算符必须返回引用,因为如果不返回引用,该重载的方括号就不能像 C++ 内置的方括号一样使用。不返回引用,如下代码逻辑上就不能成功运行。

 
  1. LinkedList a;
  2. a[2] = 8;

此处方括号可以重载 2 个版本,const 版本与非 const 版本,分别是:

 
  1. int& operator [] (int pos);
  2. const int& operator [] (int pos)const;

另外,考虑到开发的效率,必须使用函数复用来解决运算符重载。也就是有一些运算符重载可以使用已有的另外的运算符重载来实现。典型的如先重载等于号运算符,再使用等于号来实现不等于号。 注意,上述 2 个方括号运算符重载也可以使用函数复用。与 ArrayList 相比,这里的方括号运算符采用函数复用具有一定的现实意义。

编程要求

根据提示,在右侧编辑器的Begin-End区域内补充代码。

测试说明

本关一共 5 个文件。其中,LinkedList.h 是头文件,包含了 LinkedList 类的定义,其中包括以成员函数形式重载的运算符(简单赋值运算符,加号赋值运算符,方括号运算符)。LinkedListOp.h 是头文件,包含了以非成员函数形式重载的与 LinkedList 类有关的运算符(加号运算符,关系运算符,流输出运算符)。 LinkedList.cpp 和 LinkedListOp.cpp 是实现文件,用户需要自行实现其中的内容。 main.cpp 是运行文件。 LinkedList.h 的内容如下:

 
  1. #ifndef _LINKEDLIST_H_
  2. #define _LINKEDLIST_H_
  3. class LinkedList{
  4. public:
  5. //这是单链表节点的结构体
  6. struct Node{
  7. int data;
  8. Node *next;
  9. Node(int a=0,Node *b=nullptr):data(a),next(b){}
  10. };
  11. private:
  12. Node *head;//链表的头结点
  13. int size; //保存数据的数量,这是一个冗余数据
  14. public:
  15. //默认构造函数,构造一个逻辑为空的链表
  16. LinkedList();
  17. //拷贝构造函数,构造一个逻辑上与参数内容相同的链表
  18. LinkedList(const LinkedList&rhs);
  19. //原生数组构造函数,构造一个内容与给定数组相同的链表
  20. LinkedList(int const a[],int n);
  21. //填充构造函数,构造一个内容为n个value的链表
  22. LinkedList(int n,int value);
  23. //析构函数,一定要自行实现,否则有内存泄漏
  24. ~LinkedList();
  25. //无话可说
  26. int getSize()const{return size;}
  27. //增删查改
  28. void insert(int pos,int value);
  29. void remove(int pos);
  30. int at(int pos)const;
  31. void modify(int pos,int newValue);
  32. void disp()const;
  33. private:
  34. //辅助函数,返回指定位置的节点的指针
  35. Node *advance(int pos)const;
  36. public:
  37. //赋值运算符重载
  38. LinkedList& operator = (const LinkedList&rhs);
  39. LinkedList& operator += (const LinkedList&rhs);
  40. //方括号运算符重载
  41. int& operator [] (int pos);
  42. const int& operator [] (int pos)const;
  43. };
  44. #endif // _LINKEDLIST_H_

LinkedListOp.h 的内容如下:

 
  1. #ifndef _LINKEDLISTOP_H_
  2. #define _LINKEDLISTOP_H_
  3. #include "LinkedList.h"
  4. #include <iostream>
  5. //加号运算符重载,加法实现连接功能
  6. const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
  7. //关系运算符重载,按照字典序比较顺序表
  8. bool operator == (const LinkedList&lhs,const LinkedList&rhs);
  9. bool operator != (const LinkedList&lhs,const LinkedList&rhs);
  10. bool operator < (const LinkedList&lhs,const LinkedList&rhs);
  11. bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
  12. bool operator > (const LinkedList&lhs,const LinkedList&rhs);
  13. bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
  14. //流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
  15. using std::ostream;
  16. ostream& operator << (ostream&os,const LinkedList&rhs);
  17. #endif // _LINKEDLISTOP_H_

main.cpp 的内容如下:

 
  1. #include <iostream>
  2. #include "LinkedList.h"
  3. #include "LinkedListOp.h"
  4. #include <stdio.h>
  5. using namespace std;
  6. int main(){
  7. int n,m;
  8. cin>>n>>m;
  9. LinkedList a(n,0),b(m,0),c;
  10. for(int i=0;i<n;++i) cin>>a[i];
  11. for(int i=0;i<m;++i) cin>>b[i];
  12. c = a += b;
  13. cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
  14. cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
  15. cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
  16. cout<<a<<endl;
  17. cout<<b<<endl;
  18. cout<<c<<endl;
  19. return 0;
  20. }

代码

#include "LinkedList.h"
#include <iostream>
using namespace std;



LinkedList::LinkedList(){
    head = new Node();
    size = 0;
}
LinkedList::LinkedList(const LinkedList&rhs){
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    Node *p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
}
LinkedList::LinkedList(int const a[],int n){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(a[i]);
        p = p->next;
        size++;
    }
}
LinkedList::LinkedList(int n,int value){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(value);
        p = p->next;
        size++;
    }
}
LinkedList::~LinkedList(){
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
}
void LinkedList::insert(int pos,int value){
    Node *p = advance(pos);
    Node *temp = new Node(value,p->next);
    p->next = temp;
    size++;
}
void LinkedList::remove(int pos){
    Node *p = advance(pos);
    Node *temp = p->next;
    p->next = temp->next;
    delete temp;
    size--;
}
int LinkedList::at(int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
void LinkedList::modify(int pos,int newValue){
    Node *p = advance(pos);
    p->next->data = newValue;
}
void LinkedList::disp()const{
    Node *p = head->next;
    while(p){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
LinkedList::Node *LinkedList::advance(int pos)const{
    Node *p = head;
    for(int i=0;i<pos;++i){
        p = p->next;
    }
    return p;
}
LinkedList& LinkedList::operator = (const LinkedList&rhs){
    if(this == &rhs) return *this;
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
LinkedList& LinkedList::operator += (const LinkedList&rhs){
    Node *p = head;
    while(p->next){
        p = p->next;
    }
    Node *temp = rhs.head->next;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
int& LinkedList::operator [] (int pos){
    Node *p = advance(pos);
    return p->next->data;
}
const int& LinkedList::operator [] (int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
#include "LinkedListOp.h"
#include<iostream>
using namespace std;
const LinkedList operator  +(const LinkedList&lhs,const LinkedList&rhs){
    LinkedList temp(lhs);
    for(int i=0;i<rhs.getSize();++i){
        temp.insert(temp.getSize(),rhs[i]);
    }
    return temp;
}
bool operator == (const LinkedList&lhs,const LinkedList&rhs){
    if(lhs.getSize()!=rhs.getSize()) return false;
    for(int i=0;i<lhs.getSize();++i){
        if(lhs[i]!=rhs[i]) return false;
    }
    return true;
}
bool operator != (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs==rhs);
}
bool operator < (const LinkedList&lhs,const LinkedList&rhs){
    for(int i=0;i<lhs.getSize()&&i<rhs.getSize();++i){
        if(lhs[i]<rhs[i]) return true;
        if(lhs[i]>rhs[i]) return false;
    }
    return lhs.getSize()<rhs.getSize();
}
bool operator <= (const LinkedList&lhs,const LinkedList&rhs){
    return lhs<rhs||lhs==rhs;
}
bool operator > (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs<=rhs);
}
bool operator >= (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs<rhs);
}
ostream& operator << (ostream&os,const LinkedList&rhs){
    for(int i=0;i<rhs.getSize();++i){
        os<<rhs[i]<<" ";
    }
    return os;
}

第4关:友元函数实现运算符重载

任务描述

本关与上一关类似,实现与 LinkedList 有关的运算符重载。不过,非成员函数形式的运算符重载,均会被声明为 LinkedList 类的友元函数。

相关知识

在上一关中,如果要实现与 LinkedList 类相关的非成员函数形式的运算符重载,其实现过程中必然会调用 LinkedList 中的 public 成员函数。以流输出运算符重载为例,其实现过程必然为如下两种之一:

 
  1. ostream& operator << (ostream&os,const LinkedList&rhs){
  2. for(int i=0;i<rhs.getSize();++i){
  3. os<<rhs.at(i)<<" ";
  4. }
  5. return os;
  6. }

或者

 
  1. ostream& operator << (ostream&os,const LinkedList&rhs){
  2. for(int i=0;i<rhs.getSize();++i){
  3. os<<rhs[i]<<" ";
  4. }
  5. return os;
  6. }

但很遗憾,这两种实现方式有着同样的问题——效率问题。仔细考查 at 函数即可知道,调用 at(i) 函数就会循环 i 次。假设链表一共包含 n 个数据,那么流输出运算符循环的次数为:

1+2+...+n=21​n(n+1)

而很明显,我们期望的循环次数应该就是 n。使用算法中的术语描述,就是:流输出运算符的时间复杂度应该是 O(n),但是此处这个实现却是 O(n2) 。这是一个质的下降,是不能忍受的。其他非成员函数形式的运算符重载,也有类似问题,包括加号运算符和关系运算符。 因此,我们需要重新设计 LinkedList 类,使得这些运算符都只需要循环 n 次即可解决问题。 其中一种方法就是将这些运算符重载均声明为友元函数,这样就可以在这些函数中直接操作链表的指针,从而达到目的。

编程要求

根据提示,在右侧编辑器的Begin-End区域内补充代码。

测试说明

本关一共 5 个文件。其中,LinkedList.h 是头文件,包含了 LinkedList 类的定义,其中包括以成员函数形式重载的运算符(简单赋值运算符,加号赋值运算符,方括号运算符)。LinkedListOp.h 是头文件,包含了以非成员函数形式重载的与 LinkedList 类有关的运算符(加号运算符,关系运算符,流输出运算符)。 LinkedList.cpp 和 LinkedListOp.cpp 是实现文件,用户需要自行实现其中的内容。 main.cpp 是运行文件。 LinkedList.h 的内容如下:

 
  1. #ifndef _LINKEDLIST_H_
  2. #define _LINKEDLIST_H_
  3. #include <iostream>
  4. using namespace std;
  5. class LinkedList{
  6. public:
  7. //这是单链表节点的结构体
  8. struct Node{
  9. int data;
  10. Node *next;
  11. Node(int a=0,Node *b=nullptr):data(a),next(b){}
  12. };
  13. private:
  14. Node *head;//链表的头结点
  15. int size; //保存数据的数量,这是一个冗余数据
  16. public:
  17. //默认构造函数,构造一个逻辑为空的链表
  18. LinkedList();
  19. //拷贝构造函数,构造一个逻辑上与参数内容相同的链表
  20. LinkedList(const LinkedList&rhs);
  21. //原生数组构造函数,构造一个内容与给定数组相同的链表
  22. LinkedList(int const a[],int n);
  23. //填充构造函数,构造一个内容为n个value的链表
  24. LinkedList(int n,int value);
  25. //析构函数,一定要自行实现,否则有内存泄漏
  26. ~LinkedList();
  27. //无话可说
  28. int getSize()const{return size;}
  29. //增删查改
  30. void insert(int pos,int value);
  31. void remove(int pos);
  32. int at(int pos)const;
  33. void modify(int pos,int newValue);
  34. void disp()const;
  35. private:
  36. //辅助函数,返回指定位置的节点的指针
  37. Node *advance(int pos)const;
  38. public:
  39. //赋值运算符重载
  40. LinkedList& operator = (const LinkedList&rhs);
  41. LinkedList& operator += (const LinkedList&rhs);
  42. //方括号运算符重载
  43. int& operator [] (int pos);
  44. const int& operator [] (int pos)const;
  45. //友元函数声明
  46. friend const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
  47. friend bool operator == (const LinkedList&lhs,const LinkedList&rhs);
  48. friend bool operator < (const LinkedList&lhs,const LinkedList&rhs);
  49. friend ostream& operator << (ostream&os,const LinkedList&rhs);
  50. };
  51. #endif // _LINKEDLIST_H_

LinkedListOp.h 的内容如下:

 
  1. #ifndef _LINKEDLISTOP_H_
  2. #define _LINKEDLISTOP_H_
  3. #include "LinkedList.h"
  4. #include <iostream>
  5. //加号运算符重载,加法实现连接功能
  6. const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
  7. //关系运算符重载,按照字典序比较顺序表
  8. bool operator == (const LinkedList&lhs,const LinkedList&rhs);
  9. bool operator != (const LinkedList&lhs,const LinkedList&rhs);
  10. bool operator < (const LinkedList&lhs,const LinkedList&rhs);
  11. bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
  12. bool operator > (const LinkedList&lhs,const LinkedList&rhs);
  13. bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
  14. //流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
  15. using std::ostream;
  16. ostream& operator << (ostream&os,const LinkedList&rhs);
  17. #endif // _LINKEDLISTOP_H_

main.cpp 的内容如下:

 
  1. #include <iostream>
  2. #include "LinkedList.h"
  3. #include <stdio.h>
  4. using namespace std;
  5. int main(){
  6. int n,m;
  7. cin>>n>>m;
  8. LinkedList a(n,0),b(m,0),c;
  9. for(int i=0;i<n;++i) cin>>a[i];
  10. for(int i=0;i<m;++i) cin>>b[i];
  11. c = a += b;
  12. cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
  13. cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
  14. cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
  15. cout<<a<<endl;
  16. cout<<b<<endl;
  17. cout<<c<<endl;
  18. return 0;
  19. }

代码

#include "LinkedList.h"
#include <iostream>
using namespace std;



LinkedList::LinkedList(){
    head = new Node();
    size = 0;
}
LinkedList::LinkedList(const LinkedList&rhs){
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    Node *p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
}
LinkedList::LinkedList(int const a[],int n){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(a[i]);
        p = p->next;
        size++;
    }
}
LinkedList::LinkedList(int n,int value){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(value);
        p = p->next;
        size++;
    }
}
LinkedList::~LinkedList(){
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
}
void LinkedList::insert(int pos,int value){
    Node *p = advance(pos);
    Node *temp = new Node(value,p->next);
    p->next = temp;
    size++;
}
void LinkedList::remove(int pos){
    Node *p = advance(pos);
    Node *temp = p->next;
    p->next = temp->next;
    delete temp;
    size--;
}
int LinkedList::at(int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
void LinkedList::modify(int pos,int newValue){
    Node *p = advance(pos);
    p->next->data = newValue;
}
void LinkedList::disp()const{
    Node *p = head->next;
    while(p){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
LinkedList::Node *LinkedList::advance(int pos)const{
    Node *p = head;
    for(int i=0;i<pos;++i){
        p = p->next;
    }
    return p;
}
LinkedList& LinkedList::operator = (const LinkedList&rhs){
    if(this == &rhs) return *this;
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
LinkedList& LinkedList::operator += (const LinkedList&rhs){
    Node *p = head;
    while(p->next){
        p = p->next;
    }
    Node *temp = rhs.head->next;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
int& LinkedList::operator [] (int pos){
    Node *p = advance(pos);
    return p->next->data;
}
const int& LinkedList::operator [] (int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
#include "LinkedListOp.h"
#include<iostream>
using namespace std;
const LinkedList operator  +(const LinkedList&lhs,const LinkedList&rhs){
    LinkedList temp(lhs);
    for(int i=0;i<rhs.getSize();++i){
        temp.insert(temp.getSize(),rhs[i]);
    }
    return temp;
}
bool operator == (const LinkedList&lhs,const LinkedList&rhs){
    if(lhs.getSize()!=rhs.getSize()) return false;
    for(int i=0;i<lhs.getSize();++i){
        if(lhs[i]!=rhs[i]) return false;
    }
    return true;
}
bool operator != (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs==rhs);
}
bool operator < (const LinkedList&lhs,const LinkedList&rhs){
    for(int i=0;i<lhs.getSize()&&i<rhs.getSize();++i){
        if(lhs[i]<rhs[i]) return true;
        if(lhs[i]>rhs[i]) return false;
    }
    return lhs.getSize()<rhs.getSize();
}
bool operator <= (const LinkedList&lhs,const LinkedList&rhs){
    return lhs<rhs||lhs==rhs;
}
bool operator > (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs<=rhs);
}
bool operator >= (const LinkedList&lhs,const LinkedList&rhs){
    return !(lhs<rhs);
}
ostream& operator << (ostream&os,const LinkedList&rhs){
    for(int i=0;i<rhs.getSize();++i){
        os<<rhs[i]<<" ";
    }
    return os;
}

第5关:设计成员函数来实现非成员函数形式的运算符重载

任务描述

上一关说到由于效率问题,需要使用友元函数来实现函数形式的运算符重载。本关使用另外一种方法来解决 LinkedList 非成员函数形式运算符重载的效率问题。即:首先编写类似功能的成员函数,然后在运算符重载中进行调用。

相关知识

一般而言,倾向于不使用友元函数,因为友元函数会破坏封装性。这样考虑一下,如果某个类,有一大波的友元函数需要声明,那不如直接把这个类的所有成员都声明为 public。 当然,有人会强调类只会对某几个函数声明为友元,因此封装性还是存在的。这是一个“度”的问题。 总之,还是倾向于不使用友元函数。如果必须需要使用友元,可能只能说明该类的成员函数设计的还不够完善。 例如此处,要实现 operator+ 运算符重载,则首先实现一个 opertor+= 的成员函数,然后使用 opeartor+= 去实现 operator+。这个实现在 ArrayList 类中曾经演示过。 要实现关系运算符重载,首先实现一个成员函数:

 
  1. int compareTo(const LinkedList&rhs);

该函数比较 2 个链表,如果 ∗this<rhs 则返回负数,相等则返回 0,再则返回正数。然后利用该函数实现关系运算符重载 要实现流输出运算符,则首先实现如下成员函数:

 
  1. void disp(ostream&os)const;

然后在流输出运算符中调用该函数。

编程要求

根据提示,在右侧编辑器的Begin-End区域内补充代码。

测试说明

本关一共 5 个文件。其中,LinkedList.h 是头文件,包含了 LinkedList 类的定义,其中包括以成员函数形式重载的运算符(简单赋值运算符,加号赋值运算符,方括号运算符)。LinkedListOp.h 是头文件,包含了以非成员函数形式重载的与 LinkedList 类有关的运算符(加号运算符,关系运算符,流输出运算符)。LinkedListOp.cpp 是非成员函数形式的运算符重载,已经给出了实现。 用户还需实现 LinkedList.cpp 中的内容。 main.cpp 是运行文件。

LinkedList.h 的内容如下:

 
  1. #ifndef _LINKEDLIST_H_
  2. #define _LINKEDLIST_H_
  3. #include <iostream>
  4. using namespace std;
  5. class LinkedList{
  6. public:
  7. //这是单链表节点的结构体
  8. struct Node{
  9. int data;
  10. Node *next;
  11. Node(int a=0,Node *b=nullptr):data(a),next(b){}
  12. };
  13. private:
  14. Node *head;//链表的头结点
  15. int size; //保存数据的数量,这是一个冗余数据
  16. public:
  17. //默认构造函数,构造一个逻辑为空的链表
  18. LinkedList();
  19. //拷贝构造函数,构造一个逻辑上与参数内容相同的链表
  20. LinkedList(const LinkedList&rhs);
  21. //原生数组构造函数,构造一个内容与给定数组相同的链表
  22. LinkedList(int const a[],int n);
  23. //填充构造函数,构造一个内容为n个value的链表
  24. LinkedList(int n,int value);
  25. //析构函数,一定要自行实现,否则有内存泄漏
  26. ~LinkedList();
  27. //无话可说
  28. int getSize()const{return size;}
  29. //增删查改
  30. void insert(int pos,int value);
  31. void remove(int pos);
  32. int at(int pos)const;
  33. void modify(int pos,int newValue);
  34. void disp()const;
  35. private:
  36. //辅助函数,返回指定位置的节点的指针
  37. Node *advance(int pos)const;
  38. public:
  39. //赋值运算符重载
  40. LinkedList& operator = (const LinkedList&rhs);
  41. LinkedList& operator += (const LinkedList&rhs);
  42. //方括号运算符重载
  43. int& operator [] (int pos);
  44. const int& operator [] (int pos)const;
  45. int compareTo(const LinkedList&rhs)const;
  46. void disp(ostream&os)const;
  47. };
  48. #endif // _LINKEDLIST_H_

LinkedListOp.h 的内容如下:

 
  1. #ifndef _LINKEDLISTOP_H_
  2. #define _LINKEDLISTOP_H_
  3. #include "LinkedList.h"
  4. #include <iostream>
  5. //加号运算符重载,加法实现连接功能
  6. const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
  7. //关系运算符重载,按照字典序比较顺序表
  8. bool operator == (const LinkedList&lhs,const LinkedList&rhs);
  9. bool operator != (const LinkedList&lhs,const LinkedList&rhs);
  10. bool operator < (const LinkedList&lhs,const LinkedList&rhs);
  11. bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
  12. bool operator > (const LinkedList&lhs,const LinkedList&rhs);
  13. bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
  14. //流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
  15. using std::ostream;
  16. ostream& operator << (ostream&os,const LinkedList&rhs);
  17. #endif // _LINKEDLISTOP_H_

LinkedListOp.cpp 的内容如下:

 
  1. #include "LinkedList.h"
  2. //使用成员函数operator+=来实现加号运算符重载
  3. const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs){
  4. LinkedList ans(lhs);
  5. return ans += rhs;
  6. }
  7. //使用成员函数compareTo来实现等于号运算符重载
  8. bool operator == (const LinkedList&lhs,const LinkedList&rhs){
  9. return 0 == lhs.compareTo(rhs);
  10. }
  11. //其他关系运算符重载还是使用等于号与小于号组合得到
  12. bool operator != (const LinkedList&lhs,const LinkedList&rhs){
  13. return ! ( lhs == rhs );
  14. }
  15. //使用成员函数compareTo来实现小于号运算符重载
  16. bool operator < (const LinkedList&lhs,const LinkedList&rhs){
  17. return lhs.compareTo(rhs) < 0;
  18. }
  19. bool operator <= (const LinkedList&lhs,const LinkedList&rhs){
  20. return ( lhs < rhs ) || ( lhs == rhs );
  21. }
  22. bool operator > (const LinkedList&lhs,const LinkedList&rhs){
  23. return ! ( lhs <= rhs );
  24. }
  25. bool operator >= (const LinkedList&lhs,const LinkedList&rhs){
  26. return ! ( lhs < rhs );
  27. }
  28. //使用成员函数disp来实现流输出运算符重载
  29. ostream& operator << (ostream&os,const LinkedList&rhs){
  30. rhs.disp(os);
  31. return os;
  32. }

main.cpp 的内容如下:

 
  1. #include <iostream>
  2. #include "LinkedList.h"
  3. #include <stdio.h>
  4. using namespace std;
  5. int main(){
  6. int n,m;
  7. cin>>n>>m;
  8. LinkedList a(n,0),b(m,0),c;
  9. for(int i=0;i<n;++i) cin>>a[i];
  10. for(int i=0;i<m;++i) cin>>b[i];
  11. c = a += b;
  12. cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
  13. cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
  14. cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
  15. cout<<a<<endl;
  16. cout<<b<<endl;
  17. cout<<c<<endl;
  18. return 0;
  19. }

代码

#include "LinkedList.h"
#include <iostream>
using namespace std;



LinkedList::LinkedList(){
    head = new Node();
    size = 0;
}
LinkedList::LinkedList(const LinkedList&rhs){
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    Node *p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
}
LinkedList::LinkedList(int const a[],int n){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(a[i]);
        p = p->next;
        size++;
    }
}
LinkedList::LinkedList(int n,int value){
    head = new Node();
    size = 0;
    Node *p = head;
    for(int i=0;i<n;++i){
        p->next = new Node(value);
        p = p->next;
        size++;
    }
}
LinkedList::~LinkedList(){
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
}
void LinkedList::insert(int pos,int value){
    Node *p = advance(pos);
    Node *temp = new Node(value,p->next);
    p->next = temp;
    size++;
}
void LinkedList::remove(int pos){
    Node *p = advance(pos);
    Node *temp = p->next;
    p->next = temp->next;
    delete temp;
    size--;
}
int LinkedList::at(int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
void LinkedList::modify(int pos,int newValue){
    Node *p = advance(pos);
    p->next->data = newValue;
}
void LinkedList::disp()const{
    Node *p = head->next;
    while(p){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
LinkedList::Node *LinkedList::advance(int pos)const{
    Node *p = head;
    for(int i=0;i<pos;++i){
        p = p->next;
    }
    return p;
}
LinkedList& LinkedList::operator = (const LinkedList&rhs){
    if(this == &rhs) return *this;
    Node *p = head;
    while(p){
        Node *temp = p;
        p = p->next;
        delete temp;
    }
    head = new Node();
    size = 0;
    Node *temp=rhs.head->next;
    p = head;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
LinkedList& LinkedList::operator += (const LinkedList&rhs){
    Node *p = head;
    while(p->next){
        p = p->next;
    }
    Node *temp = rhs.head->next;
    while(temp){
        p->next = new Node(temp->data);
        p = p->next;
        temp = temp->next;
        size++;
    }
    return *this;
}
int& LinkedList::operator [] (int pos){
    Node *p = advance(pos);
    return p->next->data;
}
const int& LinkedList::operator [] (int pos)const{
    Node *p = advance(pos);
    return p->next->data;
}
int LinkedList::compareTo(const LinkedList& rhs) const {
    Node* p = head->next;
    Node* q = rhs.head->next;
    while (p && q) {
        if (p->data < q->data) return -1;
        if (p->data > q->data) return 1;
        p = p->next;
        q = q->next;
    }
    if (p) return 1;
    if (q) return -1;
    return 0;
}
void LinkedList::disp(ostream&os)const{
    Node *p = head->next;
    while(p){
        os<<p->data<<" ";
        p = p->next;
    }
}

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值