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