第1关:构造函数与析构函数的实现
任务描述
LinkedList
类是一个比较复杂的类,首先需要实现其构造函数。要求用户为 LinkedList
类提供 4 种构造函数。分别是:
默认构造函数
使用该函数构造出的数组对象,逻辑上是空的
拷贝构造函数
使用该函数构造出的输出对象,逻辑上的内容应与参数一模一样
原生输出构造函数
给定一个C++的原生数组,构造出内容一模一样的数组对象
填充构造函数
给定参数 n 与 value,构造出一个数组对象,其内容是 n 个 value。
在构造函数中,涉及到申请内存。凡是与系统资源打交道的代码一定要做异常检测。内存就是一种系统资源,所以一定要坚持申请内存是否成功。不过本任务忽略这一步。
此外,还需要实现析构函数。因为 LinkedList
与 ArrayList
类一样,必须要自行提供析构函数。
相关知识
从数据结构的角度,LinkedList
类就代表链表。要实现链表,首先就需要定义链表节点。因为此处实现的是单链表,所以表示链表节点的结构体定义如下:
struct Node{
int data; //仍然假定只保存int类型数据
Node *next;//指针
//为该结构体提供一个构造函数
Node(int a=0,Node*b=nullptr):data(a),next(b){}
};
同时需要注意,这个结构体与链表有关,所以一般定义在链表类的内部,是一个内部结构体。
编程要求
根据提示,在右侧编辑器的Begin-End区域内补充代码。
测试说明
该项目一共有3个文件,main.cpp、LinkedList.h 和 LinkedList.cpp。其中 main.cpp 是测试文件,LinkedList.h 包含 LinkedList
类的定义和成员函数声明。用户仅能修改 LinkedList.cpp 中的内容,在其中实现LinkedList的成员函数。 LinkedList.h 的内容如下
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
class LinkedList{
public:
//这是单链表节点的结构体
struct Node{
int data;
Node *next;
Node(int a=0,Node *b=nullptr):data(a),next(b){}
};
private:
Node *head;//链表的头结点
int size; //保存数据的数量,这是一个冗余数据
public:
//默认构造函数,构造一个逻辑为空的链表
LinkedList();
//拷贝构造函数,构造一个逻辑上与参数内容相同的链表
LinkedList(const LinkedList&rhs);
//原生数组构造函数,构造一个内容与给定数组相同的链表
LinkedList(int const a[],int n);
//填充构造函数,构造一个内容为n个value的链表
LinkedList(int n,int value);
//析构函数,一定要自行实现,否则有内存泄漏
~LinkedList();
//无话可说
int getSize()const{return size;}
};
#endif // _LINKEDLIST_H_
main.cpp 的内容如下
#include <iostream>
#include "LinkedList.h"
using namespace std;
int A[] = {100,200,400,800,1600};
int main(){
LinkedList a,b(A,4);
LinkedList c(b),d(8,6);
cout<<a.getSize()<<" "<<b.getSize()<<" "<<c.getSize()<<" "<<d.getSize()<<endl;
return 0;
- }
代码
/********** 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
函数,将数组内容输出到显示器。用户仍然要自行实现上一关中的构造函数与析构函数。
void insert(int pos,int value);
insert
函数在 pos 位置(从 0 开始编号)插入一个值为 value 的元素;
void remove(int pos);
remove
函数将 pos 位置上的元素删除;
int at(int pos)const;
at
函数返回 pos 位置上元素的值;
void modify(int pos,int newValue);
modify
函数将 pos 位置上的元素值修改为 newValue;
void disp()const;
disp函数将所保存的数据输出到屏幕,输出为一行,每个数据后面接一个空格。
通过观察可以,增、删、查、改都需要实现一个共同的功能,即:找到对应节点的指针。因此,再增加一个辅助函数:
Node *advance(int pos)const
返回指定位置的指针。 同时,由于这个函数是用于实现内部功能,所以将其设置为 private
。
相关知识
对于增、删操作而言,都需要找到待操作节点的前一个节点。因此,如果是普通单链表,就有一个问题:头节点没有前一个节点。因此对头结点做增、删需要特殊的操作。 因此,这里建议使用带空头节点的链表。这样一来,所有合法位置上的增、删操作就可以保持一致了。 删除节点,一定要记住释放相应的内存。
编程要求
根据提示,在右侧编辑器的Begin-End区域内补充代码。
测试说明
该项目一共有3个文件,main.cpp、LinkedList.h 和 LinkedList.cpp。其中 main.cpp 是测试文件,LinkedList.h 包含 LinkedList
类的定义和成员函数声明。用户仅能修改 LinkedList.cpp 中的内容,在其中实现 LinkedList
的成员函数。
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
class LinkedList{
public:
//这是单链表节点的结构体
struct Node{
int data;
Node *next;
Node(int a=0,Node *b=nullptr):data(a),next(b){}
};
private:
Node *head;//链表的头结点
int size; //保存数据的数量,这是一个冗余数据
public:
//默认构造函数,构造一个逻辑为空的链表
LinkedList();
//拷贝构造函数,构造一个逻辑上与参数内容相同的链表
LinkedList(const LinkedList&rhs);
//原生数组构造函数,构造一个内容与给定数组相同的链表
LinkedList(int const a[],int n);
//填充构造函数,构造一个内容为n个value的链表
LinkedList(int n,int value);
//析构函数,一定要自行实现,否则有内存泄漏
~LinkedList();
//无话可说
int getSize()const{return size;}
//增删查改
void insert(int pos,int value);
void remove(int pos);
int at(int pos)const;
void modify(int pos,int newValue);
void disp()const;
private:
//辅助函数,返回指定位置的节点的指针
Node *advance(int pos)const;
};
#endif // _LINKEDLIST_H_
main.cpp 的内容如下:
#include <iostream>
#include "LinkedList.h"
using namespace std;
int main(){
int n,x;
LinkedList a;
cin>>n;
for(int i=0;i<n;++i){
cin>>x;
a.insert(a.getSize(),x);
}
a.disp();
for(int i=0;i<3&&a.getSize()!=0;++i){
a.remove(0);
}
a.disp();
for(int i=0;i<a.getSize();i+=2){
a.modify(i,a.at(i)*10);
}
a.disp();
return 0;
}
代码
#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++ 内置的方括号一样使用。不返回引用,如下代码逻辑上就不能成功运行。
LinkedList a;
a[2] = 8;
此处方括号可以重载 2 个版本,const
版本与非 const
版本,分别是:
int& operator [] (int pos);
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 的内容如下:
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
class LinkedList{
public:
//这是单链表节点的结构体
struct Node{
int data;
Node *next;
Node(int a=0,Node *b=nullptr):data(a),next(b){}
};
private:
Node *head;//链表的头结点
int size; //保存数据的数量,这是一个冗余数据
public:
//默认构造函数,构造一个逻辑为空的链表
LinkedList();
//拷贝构造函数,构造一个逻辑上与参数内容相同的链表
LinkedList(const LinkedList&rhs);
//原生数组构造函数,构造一个内容与给定数组相同的链表
LinkedList(int const a[],int n);
//填充构造函数,构造一个内容为n个value的链表
LinkedList(int n,int value);
//析构函数,一定要自行实现,否则有内存泄漏
~LinkedList();
//无话可说
int getSize()const{return size;}
//增删查改
void insert(int pos,int value);
void remove(int pos);
int at(int pos)const;
void modify(int pos,int newValue);
void disp()const;
private:
//辅助函数,返回指定位置的节点的指针
Node *advance(int pos)const;
public:
//赋值运算符重载
LinkedList& operator = (const LinkedList&rhs);
LinkedList& operator += (const LinkedList&rhs);
//方括号运算符重载
int& operator [] (int pos);
const int& operator [] (int pos)const;
};
#endif // _LINKEDLIST_H_
LinkedListOp.h 的内容如下:
#ifndef _LINKEDLISTOP_H_
#define _LINKEDLISTOP_H_
#include "LinkedList.h"
#include <iostream>
//加号运算符重载,加法实现连接功能
const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
//关系运算符重载,按照字典序比较顺序表
bool operator == (const LinkedList&lhs,const LinkedList&rhs);
bool operator != (const LinkedList&lhs,const LinkedList&rhs);
bool operator < (const LinkedList&lhs,const LinkedList&rhs);
bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
bool operator > (const LinkedList&lhs,const LinkedList&rhs);
bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
//流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
using std::ostream;
ostream& operator << (ostream&os,const LinkedList&rhs);
#endif // _LINKEDLISTOP_H_
main.cpp 的内容如下:
#include <iostream>
#include "LinkedList.h"
#include "LinkedListOp.h"
#include <stdio.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
LinkedList a(n,0),b(m,0),c;
for(int i=0;i<n;++i) cin>>a[i];
for(int i=0;i<m;++i) cin>>b[i];
c = a += b;
cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
return 0;
}
代码
#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
成员函数。以流输出运算符重载为例,其实现过程必然为如下两种之一:
ostream& operator << (ostream&os,const LinkedList&rhs){
for(int i=0;i<rhs.getSize();++i){
os<<rhs.at(i)<<" ";
}
return os;
}
或者
ostream& operator << (ostream&os,const LinkedList&rhs){
for(int i=0;i<rhs.getSize();++i){
os<<rhs[i]<<" ";
}
return os;
}
但很遗憾,这两种实现方式有着同样的问题——效率问题。仔细考查 at
函数即可知道,调用 at(i)
函数就会循环 i 次。假设链表一共包含 n 个数据,那么流输出运算符循环的次数为:
1+2+...+n=21n(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 的内容如下:
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
#include <iostream>
using namespace std;
class LinkedList{
public:
//这是单链表节点的结构体
struct Node{
int data;
Node *next;
Node(int a=0,Node *b=nullptr):data(a),next(b){}
};
private:
Node *head;//链表的头结点
int size; //保存数据的数量,这是一个冗余数据
public:
//默认构造函数,构造一个逻辑为空的链表
LinkedList();
//拷贝构造函数,构造一个逻辑上与参数内容相同的链表
LinkedList(const LinkedList&rhs);
//原生数组构造函数,构造一个内容与给定数组相同的链表
LinkedList(int const a[],int n);
//填充构造函数,构造一个内容为n个value的链表
LinkedList(int n,int value);
//析构函数,一定要自行实现,否则有内存泄漏
~LinkedList();
//无话可说
int getSize()const{return size;}
//增删查改
void insert(int pos,int value);
void remove(int pos);
int at(int pos)const;
void modify(int pos,int newValue);
void disp()const;
private:
//辅助函数,返回指定位置的节点的指针
Node *advance(int pos)const;
public:
//赋值运算符重载
LinkedList& operator = (const LinkedList&rhs);
LinkedList& operator += (const LinkedList&rhs);
//方括号运算符重载
int& operator [] (int pos);
const int& operator [] (int pos)const;
//友元函数声明
friend const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
friend bool operator == (const LinkedList&lhs,const LinkedList&rhs);
friend bool operator < (const LinkedList&lhs,const LinkedList&rhs);
friend ostream& operator << (ostream&os,const LinkedList&rhs);
};
#endif // _LINKEDLIST_H_
LinkedListOp.h 的内容如下:
#ifndef _LINKEDLISTOP_H_
#define _LINKEDLISTOP_H_
#include "LinkedList.h"
#include <iostream>
//加号运算符重载,加法实现连接功能
const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
//关系运算符重载,按照字典序比较顺序表
bool operator == (const LinkedList&lhs,const LinkedList&rhs);
bool operator != (const LinkedList&lhs,const LinkedList&rhs);
bool operator < (const LinkedList&lhs,const LinkedList&rhs);
bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
bool operator > (const LinkedList&lhs,const LinkedList&rhs);
bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
//流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
using std::ostream;
ostream& operator << (ostream&os,const LinkedList&rhs);
#endif // _LINKEDLISTOP_H_
main.cpp 的内容如下:
#include <iostream>
#include "LinkedList.h"
#include <stdio.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
LinkedList a(n,0),b(m,0),c;
for(int i=0;i<n;++i) cin>>a[i];
for(int i=0;i<m;++i) cin>>b[i];
c = a += b;
cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
return 0;
}
代码
#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
类中曾经演示过。 要实现关系运算符重载,首先实现一个成员函数:
int compareTo(const LinkedList&rhs);
该函数比较 2 个链表,如果 ∗this<rhs
则返回负数,相等则返回 0,再则返回正数。然后利用该函数实现关系运算符重载 要实现流输出运算符,则首先实现如下成员函数:
void disp(ostream&os)const;
然后在流输出运算符中调用该函数。
编程要求
根据提示,在右侧编辑器的Begin-End区域内补充代码。
测试说明
本关一共 5 个文件。其中,LinkedList.h 是头文件,包含了 LinkedList
类的定义,其中包括以成员函数形式重载的运算符(简单赋值运算符,加号赋值运算符,方括号运算符)。LinkedListOp.h 是头文件,包含了以非成员函数形式重载的与 LinkedList
类有关的运算符(加号运算符,关系运算符,流输出运算符)。LinkedListOp.cpp 是非成员函数形式的运算符重载,已经给出了实现。 用户还需实现 LinkedList.cpp 中的内容。 main.cpp 是运行文件。
LinkedList.h 的内容如下:
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
#include <iostream>
using namespace std;
class LinkedList{
public:
//这是单链表节点的结构体
struct Node{
int data;
Node *next;
Node(int a=0,Node *b=nullptr):data(a),next(b){}
};
private:
Node *head;//链表的头结点
int size; //保存数据的数量,这是一个冗余数据
public:
//默认构造函数,构造一个逻辑为空的链表
LinkedList();
//拷贝构造函数,构造一个逻辑上与参数内容相同的链表
LinkedList(const LinkedList&rhs);
//原生数组构造函数,构造一个内容与给定数组相同的链表
LinkedList(int const a[],int n);
//填充构造函数,构造一个内容为n个value的链表
LinkedList(int n,int value);
//析构函数,一定要自行实现,否则有内存泄漏
~LinkedList();
//无话可说
int getSize()const{return size;}
//增删查改
void insert(int pos,int value);
void remove(int pos);
int at(int pos)const;
void modify(int pos,int newValue);
void disp()const;
private:
//辅助函数,返回指定位置的节点的指针
Node *advance(int pos)const;
public:
//赋值运算符重载
LinkedList& operator = (const LinkedList&rhs);
LinkedList& operator += (const LinkedList&rhs);
//方括号运算符重载
int& operator [] (int pos);
const int& operator [] (int pos)const;
int compareTo(const LinkedList&rhs)const;
void disp(ostream&os)const;
};
#endif // _LINKEDLIST_H_
LinkedListOp.h 的内容如下:
#ifndef _LINKEDLISTOP_H_
#define _LINKEDLISTOP_H_
#include "LinkedList.h"
#include <iostream>
//加号运算符重载,加法实现连接功能
const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs);
//关系运算符重载,按照字典序比较顺序表
bool operator == (const LinkedList&lhs,const LinkedList&rhs);
bool operator != (const LinkedList&lhs,const LinkedList&rhs);
bool operator < (const LinkedList&lhs,const LinkedList&rhs);
bool operator <= (const LinkedList&lhs,const LinkedList&rhs);
bool operator > (const LinkedList&lhs,const LinkedList&rhs);
bool operator >= (const LinkedList&lhs,const LinkedList&rhs);
//流输出运算符重载,所有内容输出一行,每个数据后面接一个空格
using std::ostream;
ostream& operator << (ostream&os,const LinkedList&rhs);
#endif // _LINKEDLISTOP_H_
LinkedListOp.cpp 的内容如下:
#include "LinkedList.h"
//使用成员函数operator+=来实现加号运算符重载
const LinkedList operator + (const LinkedList&lhs,const LinkedList&rhs){
LinkedList ans(lhs);
return ans += rhs;
}
//使用成员函数compareTo来实现等于号运算符重载
bool operator == (const LinkedList&lhs,const LinkedList&rhs){
return 0 == lhs.compareTo(rhs);
}
//其他关系运算符重载还是使用等于号与小于号组合得到
bool operator != (const LinkedList&lhs,const LinkedList&rhs){
return ! ( lhs == rhs );
}
//使用成员函数compareTo来实现小于号运算符重载
bool operator < (const LinkedList&lhs,const LinkedList&rhs){
return lhs.compareTo(rhs) < 0;
}
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 );
}
//使用成员函数disp来实现流输出运算符重载
ostream& operator << (ostream&os,const LinkedList&rhs){
rhs.disp(os);
return os;
}
main.cpp 的内容如下:
#include <iostream>
#include "LinkedList.h"
#include <stdio.h>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
LinkedList a(n,0),b(m,0),c;
for(int i=0;i<n;++i) cin>>a[i];
for(int i=0;i<m;++i) cin>>b[i];
c = a += b;
cout<<(a==b)<<" "<<(a!=b)<<" "<<(a<b)<<" "<<(a<=b)<<" "<<(a>b)<<" "<<(a>=b)<<endl;
cout<<(a==c)<<" "<<(a!=c)<<" "<<(a<c)<<" "<<(a<=c)<<" "<<(a>c)<<" "<<(a>=c)<<endl;
cout<<(b==c)<<" "<<(b!=c)<<" "<<(b<c)<<" "<<(b<=c)<<" "<<(b>c)<<" "<<(b>=c)<<endl;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
return 0;
}
代码
#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;
}
}