題目描述:
Create in C ++, a parametric class MyCircularList <T>. The objects of MyCircularList <T> are sets of objects of type (class) Node <T>, each node pointing to the next one and to the previous one. In a circular list the next node at the last node is the first node (reference node) and the node before the first node is the last node.
1. The class Nœud<T> must have a member « data » of type T and two pointers of type Node<T>*. It must also have a private constructor with signature:
Node(T v)
which creates a node with data = v and pointers set to nullptr. The Node <T> class must declare the MyCircularList <T> and MyCircularIterator <T> classes as friends.
2. The MyCircularList <T> class must be public, with a private field: the "_head" field for the head of the list (the reference node). The MyCircularList <T> class must declare the MyCircularIterator <T> class as friend. The MyCircularList <T> class must have 3 public constructors with signatures:
MyCirculaireList() // empty list (_head = nullptr)
MyCirculaireList(T v) // list of a single node whose field « data » is v.
MyCirculaireList(T v []) // list whose nodes correspond to the elements of the array v
It must also have the dynamical methods:
public Vector<T> toVector() // returns the vector of objects of type T
//corresponding to the MyCirculaireList.
public MyCirculaireList<T> copy() // returns a copy (clone) of MyCirculaireList.
public T head() // returns the value of « data » of the node pointed by _head (nœud de référence)
public void append (T e) // creates a node with « data »=e at the "end" of the MyCirculaireList.
public void concat (MyCirculaireList<T> lc) // concatenates a copy of lc at the "end" of the MyCirculaireList.
public MyCirculaireListIterator<T> iterator() // method to initialise the iterator
//MyCirculaireListIterator for the object
//current MyCirculaireList
3. The MyCircularListIterator <T> class must have two private fields (pointers), for example:
Node<T>* current; // current node
MyCircularList<T>* ch; // Instance of MyCircularList on which we iterate.
The MyCircularListIterator <T> class must declare the MyCircularList <T> class as a friend. The MyCircularListIterator <T> class must also have a constructor with signature:
public MyCircularListIterator(MyCircularList<T> a)
(If the instance of MyCircularList on which we iterate is not empty, the current pointer will indicate the node which precedes the reference node, _head, of ch, otherwise current is nullptr.)
and the dynamic methods:
public bool isEmpty() // checks if the instance of MyCircularList on which we
// iterate is empty vide
public T next() // moves the pointer current to the next node and returns its
// value
public T previous() // returns the value of the node pointed by current and moves the
// pointer current to the preceding node
public bool isAtBegin() // check if current points to the node that precedes
// the reference node (_head)
public void goToBegin() // moves the pointer current to its initial position.
public void set (T v ) // assign v as the value of « data » of the node pointed by
// current.
4. The classes MyCircularList <T> and MyCircularListIterator <T> must use an exception class MCLInvalidAccessException, extension of exception class, which must receive a numeric parameter to identify (at least) the six exception cases:
case 1 : msg= "Invalid head() call: empty list";
case 11 : msg= "Invalid next() call: empty list";
case 12: msg = "Invalid previous() call: empty list";
case 13: msg = "Invalid isAtBegin() call: empty list";
case 14: msg = "Invalid goToBegin() call: empty list";
case 15: msg = "Invalid set(T v) call: empty list";
Attention : You should also write a C ++ "main" program to check if your classes are working well (informal test).
代碼實現:
#include <iostream>
#include <vector>
#include <exception>
using namespace std;
//喬卿
//2020-06-21
template<class T>
class Node {
public:
T val;
Node *next;
Node *pre;
Node(T v) {
val = v;
next = NULL;
pre = NULL;
}
};
class MCLInvalidAccessException: public exception {
public:
const char * what (int id) const throw () {
switch(id) {
case 1:
return "Invalid head() call: empty list";
break;
case 11:
return "Invalid next() call: empty list";
break;
case 12:
return "Invalid previous() call: empty list";
break;
case 13:
return "Invalid isAtBegin() call: empty list";
break;
case 14:
return "Invalid goToBegin() call: empty list";
break;
case 15:
return "Invalid set(T v) call: empty list";
break;
}
}
};
template <typename T> class MyCirculaireListIterator;
template <typename T> class MyCircularList {
private:
Node<T>* _head;
friend class MyCirculaireListIterator<T>;
public:
MyCircularList<T>() {
_head=NULL;
}
MyCircularList(T v) {
_head=new Node<T>(v);
}
MyCircularList(T v []) {
_head=new Node<T>(v[0]);
int len=(sizeof(v) / sizeof(v[0]));
for(int i=1; i<len; i++) {
append(v[i]);
}
}
vector<T> toVector() {
vector<T> rs;
Node<T>* now=_head;
if(_head==NULL) {
return rs;
}
rs.push_back(_head->val);
now=_head->next;
while(now!=_head) {
rs.push_back(now->val);
now=now->next;
}
return rs;
}
MyCircularList<T> copy() {
MyCircularList<T> copy;
if(_head==NULL) {
return copy;
}
copy.append(_head->val);
Node<T> * curr=_head->next;
while(curr!=_head) {
copy.append(curr->val);
curr=curr->next;
}
return copy;
}
void append(T e) {
if(_head==NULL) {
_head=new Node<T>(e);
_head->next= _head;
_head->pre= _head;
} else {
Node<T>* tail=new Node<T>(e);
tail->next=_head;
Node<T>* curr=_head;
while(curr->next!=_head) {
curr=curr->next;
}
curr->next=tail;
}
}
void concat (MyCircularList<T> lc) {
Node<T>* curr=_head;
while(curr->next!=_head) {
curr=curr->next;
}
curr->next=lc._head;
Node<T>* curr2=lc._head;
while(curr->next!=lc._head) {
curr=curr->next;
}
curr->next=_head;
}
};
template <typename T> class MyCirculaireListIterator {
private:
Node<T>* current=NULL;
MyCircularList<T>* ch=NULL;
friend class MyCircularList<T>;
public:
MyCirculaireListIterator() {
}
MyCircularListIterator(MyCircularList<T> a) {
ch=&a;
current=a._head;
}
bool isEmpty() {
return (current==NULL) || (ch==NULL);
}
T head() {
try {
if(ch==NULL)
throw MCLInvalidAccessException();
return ch->_head;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(1);
}
}
T next() {
try {
if(current==NULL)
throw MCLInvalidAccessException();
current=current->next;
return current->val;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(11);
}
}
T previous() {
try {
if(current==NULL)
throw MCLInvalidAccessException();
current=current->pre;
return current->val;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(12);
}
}
bool isAtBegin() {
try {
if(current==NULL || ch==NULL)
throw MCLInvalidAccessException();
return current==ch->_head;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(13);
}
}
void goToBegin() {
try {
if(ch==NULL)
throw MCLInvalidAccessException();
current=ch->_head;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(14);
}
}
void set(T v) {
try {
if(current==NULL)
throw MCLInvalidAccessException();
current->val=v;
} catch (MCLInvalidAccessException& e) {
cout<<e.what(15);
}
}
void setCh(MyCircularList<T> a) {
ch=&a;
current=a._head;
}
};
int main() {
//喬卿
//2020-06-21
//create my list
MyCircularList<int> list;
//append
list.append(1);
list.append(2);
list.append(3);
//show
vector<int> v0=list.toVector();
for(int i = 0; i < v0.size(); i++) {
cout<<v0[i];
}
cout<<endl;
//append
list.append(4);
//show
vector<int> v1=list.toVector();
for(int i = 0; i < v1.size(); i++) {
cout<<v1[i];
}
cout<<endl;
//create my iterator
MyCirculaireListIterator<int> itor;
itor.setCh(list);
itor.goToBegin();
itor.set(9);
vector<int> v2=list.toVector();
for(int i = 0; i < v2.size(); i++) {
cout<<v2[i];
}
cout<<endl;
return 0;
}