LinearList.h
注意使用 #pragma once 命令
#pragma once
#include <iostream>
using namespace std;
//陈刚的课件里注释有很多的问题,千万不要引入注释。
template <class T>
class LinearList{
public:
LinearList(){};
~LinearList(){};
virtual bool IsEmpty() const=0;
virtual int Length() const=0;
virtual bool Find(int k,T& x) const=0;
virtual int Search(const T& x) const=0;
virtual bool Insert(int k,const T& x)=0;
virtual bool Delete(int k)=0;
virtual bool Update(int k, const T& x)=0;
virtual void Output(ostream& out)const=0;
int a;
};
//线性表的顺序表实现
template <class T>
class SeqList:public LinearList<T>
{
public:
SeqList(int MaxListSize);
~SeqList() { delete [] elements; };//有意思的地方在这里,如果不指定删除的对象为数组的话,必定会出现内存泄露的问题。
bool IsEmpty() const;
int Length() const;
bool Find(int k,T& x) const;
int Search(const T& x) const;
bool Insert(int k,const T& x);
bool Delete(int k);
bool Update(int k, const T&x);
void Output(ostream& out)const ;
private:
int length;
int MaxLength;
T *elements;
};
template <class T>
SeqList<T>::SeqList(int MaxListSize)
{
MaxLength=MaxListSize;
elements=new T[MaxLength];
length=0;
}
template<class T>
bool SeqList<T>::Find(int k,T& x) const
{
if (k<1 || k>length) {
cout<<"Out of Bounds"<<endl;
return false;
}
x=elements[k-1];
return true;
}
template<class T>
bool SeqList<T>::Insert(int k,const T& x)
{
if(k < 0 || k > length)
{
cout<< "Out of bound" <<endl;
return false;
}
if (length == MaxLength)
{
cout<< "OverFlow" <<endl;
return false;
}
for (int i=length-1;i>=k;i--)
elements[i+1]=elements[i];
elements[k]=x;
length++;
return true;
}
template <class T>
bool SeqList<T>::Delete(int k)
{
if ( !length ) {
cout<<"UnderFlow"<<endl;
return false;
}
if ( k<1 || k>length ) {
cout<<"Out Of Bounds"<<endl;
return false;
}
for (int i=k;i<length;i++)
elements[i-1]=elements[i];
length--;
return true;
}
template <class T>
bool SeqList<T>::IsEmpty() const
{
return length==0;
}
template <class T>
int SeqList<T>::Length() const
{
return length;
}
template <class T>
void SeqList<T>::Output(ostream& out)const
{ for (int i=0; i< length; i++)
out<<elements[i]<<' ';
out<<endl;
}
template<class T>
int SeqList<T>::Search(const T& x) const
{
for (int i=0;i<length;i++)
if (elements[i]==x) return ++i;
return 0;
}
template <class T>
bool SeqList<T>::Update(int k, const T& x)
{
if (k<1|| k>length ) {
cout<<"Out Of Bounds"<<endl;
return false;
}
elements[k-1]=x;
return true;
}
//线性表的单链表实现
template <class T> class SingleList;
template <class T>
class Node
{ private:
T data;
Node<T> *link;
/*这里的友元类很像Java中的内部类,允许单链表类访问自己的私有成员*/
friend class LinearList<T>;
};
template <class T>
class SingleList:public LinearList<T>
{
public:
SingleList()
{ first=NULL; length=0; }
~SingleList();
bool IsEmpty() const;
int Length() const;
bool Find(int k,T& x) const;
int Search(const T& x) const;
bool Insert(int k,const T& x);
bool Delete(int k);
bool Update(int k, const T&x);
void Output(ostream& out)const ;
private:
Node<T>* first;
int length;
};
template <class T>
SingleList<T>::~SingleList()
{ Node<T> *p;
while ( first ) {
p=first->link;
delete first;
first=p;
}
}
template<class T>
bool SingleList<T>::Find(int k,T& x)const
{ if (k<1 || k>length ) {
cout<< "Out Of Bounds";
return false;
}
Node<T> *p=first;
/*注意for循环中止的时候, i == k已经成立了。*/
for (int i=1; i<k; i++) p=p->link;
x=p->data;
return true;
}
template<class T>
bool SingleList<T>::Insert(int k,const T&x)
{ if ( k<0 || k>length ) {
cout<< "Out Of Bounds";
return false;
}
Node<T> *p=first;
for (int i=1; i<k; i++) p=p->link;
Node<T> * q=new Node<T>; q->data=x;
if(k){
q->link=p->link;p->link=q; /*在p之后插入*/
}
else {q->link=first;first=q;/* k=0,在第一个元素之前插入*/
}
length++; return true;
}
template<class T>
bool SingleList<T>::Delete(int k)
{ if ( !length ) {
cout<<"UnderFlow"<<endl; return false;
}
if ( k<1 || k>length ) {
cout<< "Out Of Bounds"<<endl; return false;
}
Node<T> *p=first,*q=first;
for (int i=1; i<k-1; i++) q=q->link; /*循环结束时,q指向谁?指向要删除的结点的前驱。有趣的是,如果要删除头结点,则这个语句不会执行*/
if (k==1) first=first->link; /*删除的是第一个结点的情况*/
else { p=q->link; q->link=p->link; }
delete p;
length--;
return true;
}
//接下来是我自己手写的一个带表头结点的单链表。
template <class T>
class HeaderList:public LinearList<T>
{
public:
HeaderList()
{ first = new ListNode(); length=0;first->link = 0; first -> data = 0; }
~HeaderList();
bool IsEmpty() const;
int Length() const;
bool Find(int k,T& x) const;
int Search(const T& x) const;
bool Insert(int k,const T& x);
bool Delete(int k);
bool Update(int k, const T&x);
void Output(ostream& out)const ;
private:
Node<T>* first;
int length;
};
template <class T>
HeaderList<T>::~HeaderList()
{ Node<T> *p;
while ( first->link ) { /*不能把表头结点删除掉*/
p=first->link;
delete first;
first=p;
}
}
template<class T>
bool HeaderList<T>::Find(int k,T& x)const
{ if (k<1 || k>length ) {
cout<< "Out Of Bounds";
return false;
}
Node<T> *p=first;
/*注意for循环中止的时候, i == k已经成立了。*/
for (int i=1; i<=k; i++) p=p->link;
x=p->data;
return true;
}
template<class T>//为什么注释不能成功呢?
bool HeaderList<T>::Insert(int k,const T&x)
{ if ( k<0 || k>length ) {
cout<< "Out Of Bounds";//越界提示
return false;
}
Node<T> *p=first;
for (int i=1; i<=k; i++) p=p->link;
Node<T> * q=new Node<T>; q->data=x;
if(k){
q->link=p->link;p->link=q; /*在p之后插入*/
}
else {q->link=first;first=q;/* k=0,在第一个元素之前插入*/
}
length++; return true;
}
template<class T>
bool HeaderList<T>::Delete(int k)
{ if ( !length ) {
cout<<"UnderFlow"<<endl; return false;
}
if ( k<1 || k>length ) {
cout<< "Out Of Bounds"<<endl; return false;
}
Node<T> *p=first,*q=first;
for (int i=1; i<k; i++) q=q->link; /*循环结束时,q指向谁?指向要删除的结点的前驱。有趣的是,如果要删除头结点,则这个语句不会执行*/
p = first->link;
first->link= p->link;
delete p;
length--;
return true;
}
Polynominal.h
#pragma once
#include <iostream>
using namespace std;
//一个多项式运算的好例子。值得学习的是关于iostream的重载和理解部分。
class Term
{
public:
Term(int c,int e);
Term(int c,int e,Term* nxt);
Term* InsertAfter(int c,int e);//在this指
//针指示的项后插入新项
//为什么会在多项式结点里存在这样一个插入函数呢?
private:
int coef;
int exp;
Term *link;
friend ostream & operator<<(ostream &, const Term &);//输出项
friend class Polynominal;
};
Term::Term(int c,int e):coef(c),exp(e){
link=0;
}
Term::Term(int c,int e,Term *nxt):coef(c),exp(e){
link=nxt;
}
//这里巧妙地使用了两个构造函数初始化式,调用其他构造函数来初始化。
Term* Term::InsertAfter(int c,int e)
{
link=new Term(c,e,link);
//相当于this->link=new Term(c,e,this->link);
return link;//返回谁的地址?还是本结点的link地址,本结点并没有发生什么变化,只是link指向了一个新结点。
}
//<<果然是一个二元运算符。
ostream &operator <<(ostream & out, const
Term& val)
{
if(val.coef==0) return out;
out<<val.coef;
switch(val.exp){
case 0:break;
case 1:out<<"X"; break;
default:out<<"X^"<<val.exp; break;
}
return out;
}
/*多项式类的成员函数
(1) AddTerms 函数:
通过输入流in,输入多项式的各项构造一个多项式。
(2) Output 函数:
将多项式按降幂方式送输出流。
(3) PolyAdd 函数:
实现将多项式r加到指针this指示的多项式上。*/
class Polynominal
{
public:
Polynominal();
void AddTerms(istream& in);
void Output(ostream& out)const;
void PolyAdd(Polynominal& r);
private:
Term* theList; //指向循环链表的头结点
friend ostream & operator << (ostream &, const Polynominal &);
friend istream& operator >>(istream&, Polynominal &);
friend Polynominal operator +( Polynominal &, Polynominal &);
};
Polynominal::Polynominal()
{
theList=new Term(0,-1); //生成带头结点的空循环链表
theList->link=theList;//注意,要自循环。
}
void Polynominal:: AddTerms(istream & in)
{
Term* q=theList;
int c,e;
for(;;){
cout<<"Input a term(coef,exp):\n"<<endl;
in>>c>>e;
if (e<0) break;
q=q->InsertAfter(c,e);//注意,此时多项式为乱序的。
}
}
//根本就没有办法保证它是降幂输出的,除非一开始输入的时候就是按照降幂输入的。
void Polynominal::Output(ostream& out)const
{
int first=1;
Term *p=theList->link;//p指向谁? 多项式的第一个结点
cout<<"The polynominal is:\n"<<endl;
for ( ; p!=theList; p=p->link){
if (!first && (p->coef>0)) out<<"+";//此处存疑,为什么first下面要置为 0呢?
first=0;//first的含义大概是,是否为头一个结点,在第一个结点以后,就不需要 加上“+”号了。
out<<*p;// 调用Term类上重载的“<<”操作。
}
cout<<"\n"<<endl;
}
/*实现q(x) q(x)+ p(x)即把多项式p(x)和q(x)相加的结果放在q(x) 中
设 p 和 q 分别指向多项式p(x)和q(x)的当前正进行比较的项,初始时分别指向两多项式中最高幂次的项。q1指向q的前驱结点。
(1) p->exp == q->exp
则将q->coef 和p->coef 相加。如果结果不为零,则令q->coef =q->coef + p-> coef,否则从q(x) 中删除q指示的结点
(2) p->exp > q->exp
则复制p所指示的结点,将其插在 q1之后,p指向下一个结点
(3) p->exp < q->exp
则q指示的项应成为结果多项式中的一项,q和q1应向后移动
*/
//这个add是有漏洞的。如果有一条链表不是按降幂排列,则移动就变成没有意义。
void Polynominal::PolyAdd(Polynominal& r) //为什么只有一个参数,因为只有一个链表相加。
{
Term *q,*q1=theList,*q2,*p;
p=r.theList; q=q1->link; p=p->link; //p和q指向两个当前进行比较的项
while (p->exp>=0){ //如果p多项式未结束,则继续
while (p->exp<q->exp){
q1=q;//指向头结点的指针移动到目前最高次幂的结点上 。q1的含义高次幂结点的前驱。
q=q->link;//高次幂结点不断降幂移动。
}
if (p->exp==q->exp){
q->coef=q->coef+p->coef;
if (q->coef==0){
q2=q;q1->link=q->link;//删除q这个目前最高次幂的结点,也就是删除q2
q=q->link;delete(q2);//q继续降幂移动
p=p->link;//p完成任务,也跟着移动
}
else {
q1=q; q=q->link; p=p->link;//把当前的q保存下来成为q1,q和p移动
}
}
//注意,这是一个没有经过if中处理的分支,有点类似finally。
else{ // (p->exp>q->exp)
q1=q1->InsertAfter(p->coef,p->exp); //q1用保存下来的位置作一个媒介,进行插入操作。
p=p->link;//p继续移动
} //end else
} //end while
} //end PolyAdd
ostream& operator <<(ostream &out,const Polynominal &x)
{ x.Output(out); return out;
}
istream& operator >>(istream& in, Polynominal &x)
{ x.AddTerms(in); return in;
}
/*
Polynominal& operator +(Polynominal &a, Polynominal &b)
{ a.PolyAdd(b);
return a;
}*/
Stack.h
#pragma once
#include <assert.h>
const int MaxSize=50;
template <class T>
class Stack
{ public:
Stack(){};
~Stack(){};
virtual void Push(const T &x)=0;
virtual void Pop()=0;
virtual T Top()const=0;
virtual bool IsEmpty() const=0;
virtual bool IsFull() const=0;
};
template<class T>
class SeqStack:public Stack<T>
{
public:
SeqStack(int MaxSize);
~SeqStack();
bool IsEmpty() const {return (top==-1);}/*只有在顺序栈中才可以这样实现吧。*/
void Push(const T &x);
void Pop();
T Top() const;
bool IsFull() const {return (top==MaxTop);}
void SetNull(){ top=-1; }
private:
T *s;
int MaxTop;/*栈的尺寸大小*/
/*总是指向栈顶元素*/
int top;
};
//构造函数
template<class T>
SeqStack<T>::SeqStack(int MaxSize)
{
MaxTop=MaxSize-1;
s=new T[MaxSize];
top=-1;
}
//析构函数
template<class T>
SeqStack<T>::~SeqStack()
{
delete [] s;
}
/* 在函数的实现中使用了一种断言assert,它是C++提供的一种功能,若断言语句的条
件满足,则继续执行后面的语句;否则出错处理,终止程序执行。assert语句包括在assert.h中。*/
template<class T>
void SeqStack<T>::Push(const T &x)
{
assert(!IsFull());
s[++top]=x;
}
template<class T>
void SeqStack<T>::Pop()
{//删除栈顶元素
assert(!IsEmpty());
top--;
}
template<class T>
T SeqStack<T>::Top()const
{
assert(!IsEmpty());
return s[top];
}
Caculator.h
#pragma once
#include <iostream>
#include <math.h>
#include "Stack.h"
class Calculator
{ private:
SeqStack<double> S; /*私有数据成员是一个栈,用于存放操作数*/
void PushOperand(double op); /*操作数进栈*/
bool GetOperands(double &op1, double &op2); /*两个操作数出栈*/
void DoOperator(char optor); /*操作符进行处理(遇到操作符时调用)*/
public:
Calculator(int MaxSize):S(MaxSize) { };/*构造函数*/
void Run();
void Clear();
};
void Calculator::PushOperand(double op)
{/*操作数进栈*/
S.Push(op);
}
bool Calculator::GetOperands(double &op1, double & op2)
{/*两个操作数出栈*/
if (S.IsEmpty())
{ cerr<<"Missing operand!"<<endl; return false;} else /*得到操作数的值,然后出栈*/
{ op1=S.Top(); S.Pop(); }
if (S.IsEmpty()) /*得到操作数的值,然后出栈*/
{ cerr<<"Missing operand!"<<endl; return false; }
else
{ op2= S.Top(); S.Pop(); }
return true;
}
void Calculator::DoOperator(char oper)
{
bool result;
double oper1,oper2;
result=GetOperands(oper1,oper2);
if (result)
switch(oper)/*注意操作数的顺序*/
{ case '+': S.Push(oper2+oper1); break;
case '-': S.Push(oper2-oper1); break;
case '*': S.Push(oper2*oper1); break;
case '/': if (oper1==0.0)
{ cerr<<"Divide by 0!"<<endl; Clear();}
else S.Push(oper2/oper1);
break;
case '^': S.Push(pow(oper2,oper1)); break;
}
else Clear();
}
void Calculator::Run()
{ char c;
double operand;
while (cin>>c,c!='#')
{ switch(c)
{ case '+':
case '-':
case '*':
case '/':
case '^': DoOperator(c); break; /*以上为遇到操作符的情况*/
default: cin.putback(c); /*将字符放回输入流*/
cin>>operand; PushOperand(operand); break;
}
}
if (S.Top()) cout<<S.Top()<<endl;/*输出的是什么?计算结果*/
}
void Calculator::Clear()
{ S.SetNull();}
计算器类的应用程序:
#include “Caculator.h”
const int SIZE=20;
void main()
{ Calculator Cal(SIZE);
Cal.Run();
}
输入:6 4 2 - / 3 2 * + #
结果:9