數據結構之線性表

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章