面向对象几种类模板整理
1.Node类(节点类)
数据成员:
T data; //存放节点数据
Node<T> *next; //指向下一个类
注意:
需要在Node类里声明LinkList为友元类
friend class LinkList<T>;
template <typename T> class Node // 结点类模板 { public: Node() : next(NULL) {}//构造函数 Node(const T &t) : data(t), next(NULL) {}//构造函数 Node(const Node<T> &node) : data(node.data), next(NULL) {}//拷贝构造函数 Node<T> & operator=(const Node<T> &node) { data = node.data; return *this; } friend class LinkList<T>;//设置成一个友元类 private: T data; Node<T> *next; };
2.LinkList类(链表类)
数据成员:
Node<T> *head; //头节点
int num; //节点个数
注意:
构造函数需要按照节点个数申请一个个的空间放置节点,插在head上
拷贝构造函数可以利用赋值函数调用*thiis=t;
析构函数需要一个个把节点释放掉,从头释放,要保证不会丢失头节点所以释放时要先把首节点指向下一节点,释放指向首节点的p
链表要注意添加顺序!赋值时不能从头上添加节点,append函数是从尾部添加节点,要用
while(p->next!=NULL)
p = p->next;
每次都指向链表的尾部,然后为下一空指针申请空间,把下下指针指向NULL;
重载<<函数,不能设计为成员函数,函数头如下
ostream & operator<<(ostream &out, const LinkList<T> &t)
{
out<<.......
return out;
}
template <typename T> class LinkList // 单向链表类模板 { public: LinkList(int n=0, const T *x=NULL); // ① 构造函数 LinkList(const LinkList<T> &link); // ② 拷贝构造函数 virtual ~LinkList(); // ③ 析构函数 LinkList<T> & operator=(const LinkList<T> &link); // ④ 赋值运算符函数 void FreeList(); // ⑤ 释放所有结点 void Append(const T &t); // ⑥ 追加新的尾结点 virtual void ShowList(ostream &out)const; // ⑦ 输出 protected: Node<T> *head; }; // ⑧ 重载operator<< 运算符 template <typename T> LinkList<T>::LinkList(int n, const T *x):head(NULL) //构造函数 { Node<T> *p; for(int i=0;i<=n;i++) { p=new Node<T>; if(x!=NULL) p->data=x[i]; p->next=head;
head=p; } } template <typename T> LinkList<T>::LinkList(const LinkList<T> &link):head(NULL) { *this=link; } template<typename T> LinkList::~LinkList() { FreeList(); } template <typename T> LinkList<T> & LinkList<T>::operator=(const LinkList<T> &link) { if(&link==this) { return *this; } FreeList(); for(Node<T> *p=link.head;p!=NULL;p=p->next) ( Append(p->data); ) return *this; } template <typename T> // ④ 赋值运算符函数 void LinkList<T>::FreeList() // ⑤ 释放所有结点 { Node<T> *p; while(head!=NULL) { p=head; head=head->next; delete p; } } template <typename T> void LinkList<T>::Append(const T &t)// ⑥ 追加新的尾结点 { if(head==NULL) { head=new Node<T>(t); head->next=NULL; return; } Node<T> *p; p=head; while(p->next!=NULL) {p=p->next;} p->next=new Node<T>(t); p->next->next=NULL; } template <typename T> void LinkList<T>::ShowList(ostream &out)const// ⑦ 输出 { out<<"head "; for(Node<T> *p=head;p!=NULL;p=p->next) { out<<"->"<<p->data; } out<<"->NULL"; template <typename T> ostream & operator<<(ostream &out,const LinkList<T> &link) { link.ShowList(out); return out; }
3.Vector类(向量类)
数据成员:
int n; //向量维度
double *x; //存向量数据
注意:(大多数最后一题都这么搞,重点看赋值函数,拷贝构造函数,重载运算符函数)
构造函数,存向量数据的double型指针x申请的空间需要根据维度n来确定
在存入向量数据时要验证所得接收指针是否为NULL
函数头:Vector::Vector(int dim=0, const double *x=NULL) : n(dim), p(NULL)
析构函数,判断指针是否为空然后delete删除,需要把维度置0
函数头:Vector::virtual ~Vector()
赋值函数,首先判断两指针指向(而非指针所指内容)是否相等,相同返回this指针所指内容(本对象)不同则依照【先删除原有空间】->【通过维度新值申请新的空间】->【循环语句一个个拷贝】
函数头:Vector&Vector::operator=(const Vector & t)
拷贝构造函数,指针不可以更改指向,this常指针,所以更改指针所指内容,利用赋值函数
函数头:Vector::Vector(const Vector & t):n(0),p(NULL)
其他成员函数,需要类有较好的容错性能,就要在成员函数设计时时刻检验x是否为空指针以及维度
n是否小于等于0,例如:average函数若维度n为0(构造函数的设计使得n不可能小于0,且n为0,p为空)就直接返回NULL(NULL与整型0区别在于能表示地址,本身也可以作为整型0使用);max,min,range函数也是在n==0时直接返回0
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 5 class Vector 6 { 7 public: 8 Vector(int dim=0, const double *x=NULL) : n(dim), p(NULL) 9 { 10 if(n<=0) 11 { 12 n = 0; return; 13 } 14 p = new double[n]; 15 for(int i=0; i<n; i++) 16 p[i] = (x==NULL)? 0 : x[i]; 17 } 18 Vector(const Vector &v) : n(0), p(NULL) 19 { 20 *this = v; 21 } 22 23 virtual ~Vector() 24 { 25 if(p!=NULL) delete [] p; 26 n = 0; 27 p = NULL; 28 } 29 Vector & operator=(const Vector &v) 30 { 31 if(this == &v) 32 return *this; 33 if(p!=NULL) delete [] p; 34 p = NULL; 35 n = 0; 36 if(v.n<=0) 37 return *this; 38 p = new double[n]; 39 for(int i=0; i<n; i++) 40 p[i] = v.p[i]; 41 return *this; 42 } 43 double average() const 44 { 45 double y=0; 46 for(int i=0; i<n; i++) 47 y += p[i]; 48 if(n>0) 49 y /= n;; 50 return y; 51 } 52 double max() const 53 { 54 if(n==0) return 0; 55 double max = p[0]; 56 for(int i=1; i<n; i++) 57 if(p[i]>max) max = p[i]; 58 return max; 59 } 60 double min() const 61 { 62 if(n==0) return 0; 63 double min = p[0]; 64 for(int i=1; i<n; i++) 65 if(p[i]<min) min = p[i]; 66 return min; 67 } 68 double range() const // 极差(range): 最大值-最小值 69 { 70 if(n==0) return 0; 71 double min, max; 72 min = max = p[0]; 73 for(int i=1; i<n; i++) 74 { 75 if(p[i]<min) min = p[i]; 76 if(p[i]>max) max = p[i]; 77 } 78 return max-min; 79 } 80 private: 81 int n; 82 double *p; 83 }; 84 85 int main() 86 { 87 double array[] = {85, 73, 60, 98, 86, 76, 85, 90, 93, 80}; 88 int n = sizeof(array)/sizeof(*array); 89 Vector v(n, array); 90 cout << "范围: [" << v.min() << ", " << v.max() 91 << "],\t极差: " << v.range() 92 << ",\t平均值: " << v.average() << endl; 93 return 0; 94 }
4.Matrix类
数据成员:
int row,col;
double *x; //存放矩阵数据
注意:
给矩阵里存数据遍历用以下循环
for(int i=row*col-1;i>=0;i--)
5.Stack类
数据成员:
T *x; //栈的首地址
int top,max; //栈顶位置,表示下标用于指针间指(-1表示栈为空),栈的最大容量(创建对象时一旦确定不可更改)
注意:做栈的pop和push操作都是针对栈顶(栈只有一个出入口)
push函数返回bool型值,需要验证当前是否已经满栈
pop函数需要验证栈是否为空
template <typename T> class Stack { public: Stack(int Max=5): x(NULL),top(-1),max(0) // 构造函数 { if(Max<=0) return; x = new T[max=Max]; } Stack(const Stack &s): x(NULL),top(-1),max(0) { *this = s; } ~Stack() { if(x!=NULL) delete [] x; top = -1; max = 0; } Stack & operator=(const Stack &s) { if(this==&s) return *this; if(x!=NULL) delete [] x; top = s.top; max = s.max; if(s.x!=NULL) { x = new T[max]; for(int i=0; i<=top; i++) // 栈顶以上的无须复制 x[i] = s.x[i]; } else x = NULL; } int Size() const; // 获取栈中当前拥有的元素个数 bool Empty() const; // 当栈为空时返回true,否则返回false bool Top(T &t) const; bool Push(const T &t); bool Pop(T &t); private: T *x; int top, max; }; template <typename T> int Stack<T>::Size() const { return top + 1; } template <typename T> bool Stack<T>::Empty() const { return top == -1; } template <typename T> bool Stack<T>::Top(T &t) const { if(top >= 0) { t = x[top]; return true; } return false; } template <typename T> bool Stack<T>::Push(const T &t) { if(top < max-1) { x[++top] = t; return true; } return false; } template <typename T> bool Stack<T>::Pop(T &t) { if(top >= 0) { t = x[top--]; return true; } return false; }
6.AutoLink类
7.Complex类(复数类)
数据成员:
double re, im;
注意:数学函数double atan2(double y, double x);当x≠0时返回y/x的反正切值,当x=0时返回π/2
或-π/2(正负号与y同号)
复数加法是x1*x1-y1*y1,减法x1y2+x2y1
(a+bi)(c+di)=(ac-bd)+(bc+ad)i
Complex.h #include <iostream> #include <cmath> using namespace std; class Complex { public: Complex(double real=0, double imag=0):re(real),im(imag){} double & Real(){ return re; } double & Imag(){ return im; } double Angle() const { return atan2(im, re); } double Abs() const { return sqrt(re*re + im*im); } friend Complex operator+(const Complex &c1, const Complex &c2) { Complex result(c1); result.re += c2.re; result.im += c2.im; return result; } friend Complex operator*(const Complex &c1, const Complex &c2) { Complex result; result.re = c1.re*c2.re - c1.im*c2.im; result.im = c1.re*c2.im + c1.im*c2.re; return result; } Complex & operator*=(const Complex &c) { double x = re*c.re - im*c.im; im = re*c.im + im*c.re; re = x; return *this; } friend ostream & operator<<(ostream &out, const Complex &c) { out << '(' << c.re << ", " << c.im << ')'; return out; } protected: double re, im; };