[轉]廣義表

(C版)node

#include <stdio.h>
#include <malloc.h>
#define OK 1
#define ERROR -1
#define status int
typedef struct gnode
{
 int tag;
 union
 {
  char atom;
  struct gnode *sublist;
 } val;
 struct gnode *link;
} *Gnode;
Gnode creatglist(char *s)
{//建立廣義表
 Gnode h;
 char ch;
 ch=*s;
 s++;
 if(ch!='\0')          //串未結束判斷
 {
  h=(Gnode)malloc(sizeof(Gnode));
  if(!h) printf("存儲空間分配失敗\n");
  if(ch=='(')
  {
   h->tag=1;
   h->val.sublist=creatglist(s);   //遞歸建立廣義表
  }
  else if(ch==')')  h=NULL;
  else
  {
   h->tag=0;
   h->val.atom=ch;
  }
 }
 else h=NULL;
 ch=*s;
 s++;
 if(h!=NULL)
 {
  if(ch==',')
   h->link=creatglist(s);
  else
   h->link=NULL;
 }
 return h;
}
void output(Gnode h)
{
 if(h!=NULL)
 {
  if(h->tag==1)
  {
   printf("(");
   if(h->val.sublist==NULL)
    printf(" ");
   else
    output(h->val.sublist);
  }
  else
   printf("%c",h->val.atom);
  if(h->tag==1)
   printf(")");
  if(h->link!=NULL)
  {
   printf(",");
   output(h->link);
  }
 }
}
void empty(Gnode h)
{
 if(h->val.sublist==NULL)
  printf("廣義表爲空\n");
 else
  printf("廣義表非空\n");
}
int length(Gnode h)
{
 Gnode p=h;
 int len=0;
 if(p==NULL)
  return len;
 else
  return length(h->link)+1;
}
Gnode copy(Gnode h)
{
 Gnode b;
 if(h==NULL) return NULL;
 b=(Gnode)malloc(sizeof(Gnode));
 b->tag=h->tag;
 if(h->tag==1)
  b->val.sublist=copy(h->val.sublist);
 else
  b->val.atom=h->val.atom;
 b->link=copy(h->link);
 return b;
}
void insert(Gnode &h,char e)
{//把元素e插入廣義表h,爲其第一個元素
 Gnode p;
 p=(Gnode)malloc(sizeof(Gnode));
 p->tag=0;
 p->val.atom=e;
 p->link=h->val.sublist;
 h->val.sublist=p;
}
int depth(Gnode h)
{//求廣義表的深度
 int max=0,dep;
 while(h!=NULL)
 {
  if(h->tag==1)
  {
   dep=depth(h->val.sublist);
   if(dep>max)
    max=dep;
  }
  h=h->link;
 }
 return max+1;
}
void delfirstnode(Gnode &h)
{//刪除第一元素並輸出其值
 Gnode p,q;
 p=(Gnode)malloc(sizeof(Gnode));
 p=copy(h);
 p->val.sublist->link=NULL;
 printf("廣義表的第一元素爲:   ");
 output(p->val.sublist);printf("\n");
 q=h->val.sublist;
 h->val.sublist=q->link;
 printf("刪除第一元素後,廣義表h爲:\n");
 output(h);
}
void main()
{
 int len,dep;
 char s[50],elem;
 Gnode h,b;
 scanf("%s",s);ios

 h=creatglist(s);git

 empty(h);算法

 printf("廣義表h爲\n");
 output(h);printf("\n");
 
 printf("廣義表的長度爲:  ");
 len=length(h->val.sublist);
 printf("%d\n",len);express

 b=copy(h);
 printf("廣義表b爲:  ");
 output(b);printf("\n");
 insert(b,'e');
 printf("廣義表b爲:  ");
 output(b);printf("\n");安全

 printf("廣義表h的深度爲:\n");
 dep=depth(h->val.sublist);
 printf("%d\n",dep);數據結構

 delfirstnode(b);
}ide

 

 

 

(C之二)函數

#include <stdio.h>
#include <string.h>
#include <stdlib.h>性能

#define AtomType char
#define MAXSIZE  1024
#define ElemTag int
#define OK       1
#define ERROR    0


typedef struct GLNode
{
 ElemTag tag;
 union
 {
  AtomType  atom;
  struct GLNode *hp;
 }atom_hp;
    struct GLNode *tp;
}GLNode,*GList;


//功能:分離出廣義表中表頭部分
//返回:分離後剩下的字符串,不包括逗號
void Disastr(char *s,char *hstr)
{
 int i,j,k,r;
 char rstr[MAXSIZE];
 
 i=j=k=0;
 while(s[i] && (s[i] != ',' || k))
 {
  if (s[i] == '(')  {  k++ ; }        // k 做爲括號計數器        
  else if (s[i] == ')') {k--;}
  if (s[i] != ',' || s[i] == ',' && k)
  {
   hstr[j] = s[i];
   i++;
   j++;
  }
 }

 hstr[j] = '/0';
 if (s[i] == ',') {i++;}

 r=0;
 while(s[i])                 // 處理剩餘的表尾部分
 {
  rstr[r] = s[i];
  r++;
  i++;
 }
 rstr[r] = '/0';
 strcpy(s,rstr);
}

//功能:根據輸入的字符串,創建廣義表
//返回:成功則返回創建的廣義表的表頭,不然,返回NULL
GLNode * GLCreate(char *s)
{
 GLNode *p,*q,*r,*head;
    char substr[MAXSIZE],hstr[MAXSIZE];//rstr[MAXSIZE];
    int len;

 len = strlen(s);
    if ( !strcmp(s,"()") || !len)  { head = NULL;}     // (1) 空表狀況
 else if (len == 1)                                      // (2) 原子狀況
 {
  head = (GLNode *)malloc(sizeof(GLNode));       // 創建一個新結點
  if (!head)  return NULL;     
  head->tag = 0;                                 // 構造原子結點
  head->atom_hp.atom = *s;
  head->tp = NULL;
 }
    else                                                // (3) 子表狀況
 {
  head = (GLNode *)malloc(sizeof(GLNode));
  if (!head) return NULL;
  head->tag = 1;
  p = head;
  s++;
  strncpy(substr,s,len-2);                         // 剝去外層的()
  substr[len-2] = '/0';
  do 
  {
   Disastr(substr,hstr);                        // 分離出表頭
   r = GLCreate(hstr);
   p->atom_hp.hp = r;                           // 尾插法建表
   q=p;
   len = strlen(substr);
   if (len > 0)
   {
    p = (GLNode*)malloc(sizeof(GLNode));
    if (!p) return NULL;
    p->tag = 1;
    q->tp=p;
   }
  } while (len > 0);
  q->tp=NULL;
 }
 return head;
}

void DisplayList(GList head)
{
 GLNode *p,*q;
    
 if (!head)  return;
 if (head->tag==0)
 {
  printf("%c",head->atom_hp.atom);
  return;
 }
 printf("(");
 if (head)
 {
  do 
  {
   p = head->atom_hp.hp;
   q = head->tp;
   while (q && p && p->tag == 0)                //  同一層的原子結點
   {
    printf("%c,",p->atom_hp.atom);
    p = q->atom_hp.hp;
    q = q->tp;
   }
   if (p && !p->tag)                           // 最後一個原子結點
   {
    printf("%c",p->atom_hp.atom);
    break;
   }
   else                                        // 子表狀況
   {
    if (!p) printf("()");
    else DisplayList(p);
    if (q)  printf(",");
    head = q;
   }
  } while (head);
  printf(")");
 }
}

//功能:取出廣義表的表頭部分
//返回:成功則返回廣義表的表頭,不然,返回空或退出
GList GetHead(GList L)
{
 if (!L)  return (NULL);                    // 空表無表頭
 if (L->tag == 0)  exit(0);                 // 原子結點不是表
 else return (L->atom_hp.hp);
}

//功能:取出廣義表的表尾部分
//返回:成功返回廣義表的表尾部分,不然,返回空或者退出
GList GetTail(GList L)
{
 if (!L) return (NULL);
 if (L->tag == 0) exit(0);
 else return (L->tp);
}

//功能:求出廣義表的長度
//返回值:廣義表的長度
int Length(GList L)
{
 int k=0;
 GLNode *s;

 if (!L) return 0;                    // 空表的長度爲零
 if (L->tag == 0) exit(0);            // 原子不是表
 s=L;
 while(s)                             // 統計表的最上層的長度
 {
  k++;
  s=s->tp;
 }

 return k;
}


//功能:求得廣義表的深度
//輸入:需求深度的廣義表的指針
int Depth(GList L)
{
 int d,max;
 GLNode *s;

 if (!L)  return (1);            // 空表的深度爲 1
 if (L->tag==0)  return 0;       // 原子的深度爲 0
 s=L;
 max=0;
 while (s)                        // 遞歸求每一個子表深度的最大值
 {
  d = Depth(s->atom_hp.hp);
  if (d > max) max = d;
  s = s->tp;
 }
 return (max+1);                  // 表的深度爲子表深度加一
}


//功能:統計原子結點的個數
//輸入:需統計的廣義表指針
int CountAtom(GList L)
{
 int n1,n2;

 if (!L) return 0;                   // 空表無原子結點
 if (L->tag==0) return 1;            // 原子結點
 n1 = CountAtom(L->atom_hp.hp);      
 n2 = CountAtom(L->tp);
 return (n1+n2);
}

//功能:完成廣義表的複製,將res複製到dest中
//返回:成功返回1,不然,返回0
bool CopyList(GList *dest,GList res)
{
 if (!res) {*dest = NULL;return (OK);}

 *dest = (GLNode *)malloc(sizeof(GLNode));
 if (!*dest)  return (ERROR);

 (*dest)->tag = res->tag;
 if (res->tag==0)  (*dest)->atom_hp.atom = res->atom_hp.atom;
    else
    {
  CopyList(&(*dest)->atom_hp.hp,res->atom_hp.hp);
  CopyList(&(*dest)->tp,res->tp);
 }
 return (OK);
}

//功能:合併廣義表,若是p爲空,則申請空間,將q複製到p中
//例如:((a,b),c) 和(a,b)合併以後爲:((a,b),c,a,b)
//算法描述:先找到第一個廣義表的最後一個結點,將其鏈到第二個廣義表的首元素便可
void Merge(GList *p,GLNode *q)
{
 GLNode *r;

 if (!q) return;       //  若是複製的是個空表,返回
 if (!p)               // p爲空,申請空間
 {
  *p = (GLNode*)malloc(sizeof(GLNode));
  if (!(*p)) return ;
  (*p)->tag = 1;
 }
 else
 {
  if ((*p)->tag)         
  {
   r=*p;
   while(r->tp) r=r->tp;             // 找到最後一個子表的表尾指針
   if (q->tag) r->tp = q;        // 修改表尾指針
  }
 }
}

//功能:相似二叉樹的先序遍歷遍歷廣義表L
//eg:例如(a,(b,(c),d))結果爲:a,b,c,d
//算法描述:
//L若爲原子結點,顯示該數據,遞歸調用遍歷後續元素,也即:write(L->atom_hp.atom);PreOrder(L->tp);
//L是子表結點,遞歸調用遍歷該子表,遍歷後續元素,也即:PreOrder(L->atom_hp.tp);PreOrder(L->tp);
void PreOrder(GList L)
{
 if (L)
 {
  if (L->tag==0) printf("%c ",L->atom_hp.atom);   // 打印原子結點
  else  PreOrder(L->atom_hp.hp);                  // 往下遍歷,相似二叉樹中的左子樹

  if (L->tp) PreOrder(L->tp);                     // 往右遍歷,相似二叉樹中的右子樹
 }
}

// 判斷兩個廣義表是否相等,相等,返回1,不然,返回0
// 相等的定義:兩個廣義表具備相同的存儲結構,對應的原子結點的數據域也相等
//算法描述:
// 形式:條件
//Equal(p,q) = Equal(p->tp,q->tp) ; p->tag = 0 && q->tag = 0 && p->atom_hp.atom = q->atom_hp.atom
//Equal(p,q) = Equal(p->atom_hp.hp,q->atom_hp.hp) && Equal(p->tp,q->tp) ; p->tag = 1 && q->tag = 1
//Equal(p,q) = false     ; p->tag = 0 && q->tag = 0 p->atom_hp.atom != q->atom_hp.atom 或者 p->tag *p->tag + q->tag*q->tag =1
//Equal(p,q) = false      ; p q 其中之一爲NULL
bool Equal(GList p,GList q)
{
 bool flags = true;

 if (!p && q) flags = false;
 if (p && !q) flags = false;
    if (p && q)
 {
  if (p->tag == 0 && q->tag == 0 )
  {
   if (p->atom_hp.atom != q->atom_hp.atom) 
    flags = false;
  }
  else if (p->tag == 1 && q->tag == 1)
  {
   flags = Equal(p->atom_hp.hp,q->atom_hp.hp);
  }
  else flags = false;
  if (flags) flags = Equal(p->tp,q->tp);
 }
 return flags;
}

int main()
{
 char s[MAXSIZE],a[MAXSIZE];
 GList head;
    GList L;

 printf("please input a string:");
 scanf("%s",s);
 head = GLCreate(s);
 DisplayList(head);
 printf("/n");

 printf("The Head is:");
    DisplayList(GetHead(head));
    printf("/n");

 printf("The Tail is: ");
 DisplayList(GetTail(head));
 printf("/n");

 printf("The Length is %d/n",Length(head));
 printf("The Depth is %d/n",Depth(head));
 printf("The Atom number is %d/n",CountAtom(head));

 printf("Copy the List:/n");
    CopyList(&L,head);
 DisplayList(L);
 printf("/n");

 printf("Merge the List/n");
 Merge(&L,head);
 DisplayList(L);
 printf("/n");

 printf("PreOrder:");
 PreOrder(head);
 printf("/n");

 printf("input a string:");
 scanf("%s",a);
 L = GLCreate(a);
 DisplayList(L);
 printf(" Eqaul ");
 DisplayList(head);
 printf(":");
 if (Equal(L,head)) printf("yes!/n");
 else printf("no!/n");
 return 0;
}

 

 

 

 

 

(C++)

//---------------------------------------------------------------

/*注:由清華大學出版社出版出版,殷人昆等人編著的《數據結構 C++描述》

 * 一書中,對廣義表的定義是比較詳細的。可是,該書對廣義表的進行的抽象分析

 * 以及實現有點差強人意,通過分析,該書對廣義表的C++實現有下面幾個缺點:

 *

 * 1:整個類型的定義很是鬆散,徹底沒有把數據封裝以及對數據的隱藏當一回事

 *

 * 2:對於GenListNode 幾個公開的接口的定義讓人根本不能分清楚它們究竟是不是成員函數

 *

 * 3: 廣義表GenList的一部分public成員函數返回的是 GenListNode* 類型,

 * 而這個函數返回的是函數內部經過申請堆內存得到的指針,這很容易引發memory leak

 * 這種做法根本不能在公用接口中出現,看到這樣的作法讓我半天無語中……

 *

 * 4:對於鏈表這類指針元素比較多的類型結構,若是不想提供拷貝構造和賦值函數,

 * 最好把它們聲明爲私有的……,這會省去不少麻煩

 *

 * 5:貌似還有一些無傷大雅的錯誤……………… 原書setNext() 和 setTail() 兩個函數必定有問題

 *

 * 6:撇開上面的第3點不談,書上提供的GenList的ADT以及實現對廣義表結構以及算法的理解

 * 仍是有用的,可是這樣作彷佛對不起「用C++描述」這幾個字。若是這樣,我還不如去買

 * 一本比較好的《數據結構,精闢地用C描述》一本書來看

 *

 *

 * 實現該類的目的不是爲了完美的解釋一個廣義表結構,相反,利用數據隱藏等潛規則

 * GenList的實現會稍微複雜一些,若是想了解廣義表的Data structure,最好去看

 * 下用C實現的GenList,那樣會更容易理解

 *

 * OK,試試能不能本身實現一個徹底用C++實現的的GenList

 *

 * Author: Jacky Wu

 * 2006-5-8

 */

 

 /*

 * **************************************************************

 *  Copyright (c) 2006

 *  Jacky Wu

 * You can use these source code for any purpose.

 * And It is provided "as is" without express or implied warranty.

 *

 * 你能夠任意使用該代碼,可是本人不對代碼的安全性作任何擔保!!!

 *

 * 因爲大部分代碼是出於學習目的實現的,只是讓它「可使用",

 * 並無通過安全性,高負荷運行強度等測試,我必須對這些代碼作一個聲明:

 * !!!!

 * 免責聲明:

 * 對於使用在本blog上提供的任意「形式」(包括測試,類的實現,

 * 系統的分析  等等只要是代碼片段)的代碼形成系統不穩定或者

 * 因爲此形成的經濟、聲譽上的損失,或者是人身傷害等任何損失,本人不負任何法律責任

 * **************************************************************

 */

 

////////////////////////////////////////////////////

//文件 GenList.h

///////////////////////////////////////////////////

#ifndef GENLIST_H_

#define GENLIST_H_

 

#include <string>

#include <iostream>

 

///////////////////////////////////////////////////////////

//廣義表 General List

//

//廣義表結點中元素類型仍是根據書上定義的幾種類型

//0:HEAD 1:INT 2:CH 3:LIST

 

enum EleCate { HEAD=0, INT, CH, LIST };     //ElementCategory 元素類型種類 

 

 

class GenList;

class GenListNode;

 

/*********************************************************

 * class NodeElement

 *節點中元素的類型,是用union來保存的,這裏提供了一系列SET,GET操做函數

 *這樣能夠減小程序中因誤取union類型出現錯誤

**********************************************************/

class NodeElement {

public:         //針對不一樣聯合存儲類型進行構造

   NodeElement();

   NodeElement( int iinfo);

   NodeElement( char chinfo);

   NodeElement( GenListNode* link);

  

public:     //提供一些可以正確存取節點中 m_unValue 元素的接口

         //每次只能正確的使用一個接口獲取信息

 

   EleCate GetTypeID() const;           //得到元素類型信息

  

   void SetRef(int rf);

   int GetRef() const;

  

   void SetIntInfo(int iinfo);

   int GetIntInfo() const;

  

   void SetCharInfo(char chinfo);

   char GetCharInfo() const;

  

   void SetList(GenListNode* link);

   GenListNode* GetList() const;

 

   void SetElement( const NodeElement& node);     //根據node值設定

public:

   NodeElement& operator=( const NodeElement& ne);

   bool operator==(const NodeElement& ne);

protected:

   void SetTypeID(EleCate ID);       //設定元素ID,只能提供protected訪問

 

private:

   union EleValue

   {

      int ref;           //m_iType == HEAD,存放表頭的引用計數

      int intinfo;       //m_iType == INT, 存放整數值

      char charinfo;        //m_iType == CH, 存放字符

      GenListNode* hlink;      //m_iType == LIST, 存放下層子表的頭的指針

   };

     

private:

   EleCate m_iType;         //標記存放的元素種類

   EleValue m_unValue;         //元素值

};

 

 

/************************************************************************

 * class GenListNode

 *因爲結點保存的數據類型比較複雜,在這裏必須將結點類單獨定義

 *這種定義方式是以破壞廣義表的結構封裝性爲代價的,

 *可是得到了良好的代碼複雜度,綜合考慮是可使用的

*************************************************************************/

class GenListNode {

   friend class GenList;

public:

   GenListNode();

   GenListNode( int iinfo);

   GenListNode( char chinfo);

   GenListNode( GenListNode* link);

  

public:     //提供操做該節點的接口

   const NodeElement& GetInfo() const;         //得到該結點的信息

   void SetInfo(const NodeElement& node);      //設置結點內容,這裏能夠發生隱式類型轉換

 

private:

   NodeElement m_NodeEle;      //節點中的元素

   GenListNode* m_pLink;    //指向同層下一個結點的指針

  

}; //GenListNode over

 

 

 

class GenList {

public:

   GenList();

   GenList( const GenListNode* glnode);        //用glnode節點做爲第一個節點索引的表生成新表

   ~GenList();

                                       

   //若是考慮到類的完整性,最好爲下面幾個函數同時提供 () const函數,

   //實現代碼是類似的,只是函數聲明不一樣,這裏就簡略了

  

   NodeElement& Head();                    //返回廣義表表頭元素的引用(非節點)

   GenList Tail();                         //返回該廣義表的尾表

   NodeElement& First();                   //返回廣義表第一個元素的引用

   NodeElement& Next(const GenListNode* node);    //返回node節點直接後繼元素的引用(不推薦進行這樣的操做)              //

  

   GenList& Push( const NodeElement& x);       //將x值做爲第一個節點的元素值插入到廣義表中

   GenList& SetHead( const NodeElement& x);    //將第一個元素值設置爲x

   GenList& SetNext( const GenListNode* node, const NodeElement& x);   //將node節點後一個節點的元素值設置爲x

   GenList& SetTail( GenList& list);           //將list做爲新表的表尾,list 被刪除

   GenList& SetTail( const GenList& list);        //將list元素複製爲表尾,list不發生變化

 

   GenList& Copy( const GenList& list);        //複製一個廣義表

   int Depth() const ;                         //計算一個廣義表深度

   bool operator==(const GenList& list) const;       //判斷兩個表是否相等

   GenList& Delete(const NodeElement& x);            //刪除表中含全部值爲X的原子節點

  

   GenList& CreateList(const std::string& exp);         //由exp描述的表達式來生成一個表

   void CreatList();                       //由輸入流新建一個表格

 

   friend std::ostream& operator<<(std::ostream& out, const GenList& list);

private:

   GenListNode* copy(const GenListNode* nd);      //全模式遞歸複製廣義表(包括對遞歸,共享表的識別複製)

                                        //遞歸複製子表,這個函數返回堆上指針,

   int depth(const GenListNode* list) const;            //遞歸計算表的深度                                //注意,此函數只能做爲該類私有使用,不得剝離做爲它用

   GenListNode* scopy(const GenListNode* nd);     //單一模式廣義表的拷貝   ,表中無遞歸或者共享結構                       

   void remove(GenListNode* nd);               //刪除nd節點後全部的表節點

   bool IsEqual(const GenListNode* p, const GenListNode* q) const;

   void delvalue(GenListNode* list, const NodeElement& x);    //刪除表中含全部值爲X的原子節點的遞歸函數

  

   GenListNode* creatlist(std::istream& in);

 

   void output(std::ostream& out, const GenListNode* node) const;//用於輸出流的廣義表遞歸提取函數

 

private:

   GenListNode* m_phead;       //表頭指針

};

 

#endif /*GENLIST_H_*/

 

 

 

////////////////////////////////////////////////////

//文件 GenList.cpp

///////////////////////////////////////////////////

 

#include "GenList.h"

 

#include <cassert>

#include <stdexcept>

#include <iostream>

using namespace std;

 

//NodeElement constructs

NodeElement::NodeElement() : m_iType(HEAD)     //default is a head node

{

   m_unValue.ref = 1;

}

 

NodeElement::NodeElement( int iinfo) : m_iType(INT)

{

   m_unValue.intinfo = iinfo;

}

           

NodeElement::NodeElement( char chinfo) : m_iType(CH)

{

   m_unValue.charinfo = chinfo;

}

 

NodeElement::NodeElement( GenListNode* link) : m_iType(LIST)

{

   m_unValue.hlink = link;

}

 

//*********************************************************

void NodeElement::SetTypeID(EleCate ID)     //this is protected function

{

   m_iType = ID;  

}

 

EleCate NodeElement::GetTypeID() const

{

   return m_iType;

}

 

void NodeElement::SetRef(int rf)

{

   SetTypeID(HEAD);

   m_unValue.ref = rf;

}

 

int NodeElement::GetRef() const

{

   assert( m_iType == HEAD);

   return m_unValue.ref;

}

 

void NodeElement::SetIntInfo(int iinfo)

{

   SetTypeID(INT);

   m_unValue.intinfo = iinfo; 

}

 

int NodeElement::GetIntInfo() const

{

   assert( m_iType == INT);

   return m_unValue.intinfo;  

}

 

void NodeElement::SetCharInfo(char chinfo)

{

   SetTypeID(CH);

   m_unValue.charinfo = chinfo;

}

 

char NodeElement::GetCharInfo() const

{

   assert( m_iType == CH);

   return m_unValue.charinfo; 

}

 

void NodeElement::SetList(GenListNode* link)

{

   SetTypeID(LIST);

   m_unValue.hlink = link;

}

 

GenListNode* NodeElement::GetList() const

{

   assert( m_iType == LIST);

   return m_unValue.hlink; 

}

 

void  NodeElement::SetElement( const NodeElement& node)

{

   switch(node.m_iType)

   {

      case HEAD :

         this->SetRef(node.m_unValue.ref);

         break;

      case INT :

         this->SetIntInfo(node.m_unValue.intinfo);

         break;

      case CH :

         this->SetCharInfo(node.m_unValue.charinfo);

         break;

      case LIST :

         this->SetList(node.m_unValue.hlink);

         break;

   }

}

 

NodeElement& NodeElement::operator=( const NodeElement& ne)

{

   m_iType = ne.m_iType;

   m_unValue = ne.m_unValue;

   return *this;

}

 

bool  NodeElement::operator==(const NodeElement& ne)

{

   //針對不一樣的數據類型進行比較

   switch(ne.m_iType)

   {

      case HEAD :

         if(m_iType == HEAD && m_unValue.ref == ne.GetRef())

         {

            return true;

         }

         else return false;

         break;

        

      case INT :

         if(m_iType == INT && m_unValue.intinfo == ne.GetIntInfo())

         {

            return true;

         }

         else return false;

         break;

        

      case CH :

         if(m_iType == CH && m_unValue.charinfo == ne.GetCharInfo())

         {

            return true;

         }

         else return false;

         break;

        

      case LIST :

         if(m_iType == LIST && m_unValue.hlink == ne.GetList())

         {

            return true;

         }

         else return false;

         break;

      default:

         return false;

         break;

   }

}

 

//*********************************************************

//

 

//*********************************************************

//GenListNode:

//

 

//constructors!!

GenListNode::GenListNode() : m_pLink(0) {}     //默認構造定義了一個表頭節點

 

GenListNode::GenListNode( int iinfo) : m_NodeEle(iinfo), m_pLink(0) {}

 

GenListNode::GenListNode( char chinfo) : m_NodeEle(chinfo), m_pLink(0) {}

 

GenListNode::GenListNode( GenListNode* link) : m_NodeEle(link), m_pLink(0) {}

 

const NodeElement& GenListNode::GetInfo() const

{

   return this->m_NodeEle;

}

 

void GenListNode::SetInfo(const NodeElement& node)

{

   m_NodeEle.SetElement(node);

}

 

//*********************************************************

//

 

 

//*********************************************************

//GenList

//

 

GenList::GenList()

{

   m_phead  = new GenListNode;     //定義了一個表頭節點

   assert( m_phead );

}

 

GenList::~GenList()

{

   remove(m_phead);

}

 

 

NodeElement& GenList::Head()      //表頭元素的引用,能夠修改元素內部值

{

   return m_phead->m_NodeEle; 

}

 

 

/*這裏返回的是一個表尾的拷貝

因爲廣儀表結構的特殊性(包含指針域),必須爲這樣的函數提供

GenList(const GenList&) 和 operator=(const GenList& )

這兩個很是重要的函數,此類沒有具體定義,可是隻要在這兩個函數中調用

GenList& GenList::Copy(const GenList& list) 就能夠很容易實現

*/

 

GenList GenList::Tail()

{

  

   GenList glist;

   if(m_phead->m_pLink)

   {

      glist.m_phead->m_pLink = this->copy(m_phead->m_pLink->m_pLink);  //拷貝尾表中全部的節點

   }

  

   return glist;      //此句將引起兩個過程

                   //1:對於外部過程,可能會調用 GenList(const GenList&) 或者operator=(const GenList& )

                   //2:對於內部過程,必定會調用 glist.~GenList(); 

                   //這樣作不會引發memory leak,且有良好的封裝可是

                   //性能就值得擔心了,若是因爲這個函數引發系統性能低下,

                   //能夠考慮是否是要捨棄類的數據隱藏。

}

 

NodeElement& GenList::First()     //表中第一個元素的引用,能夠修改元素內部值

{

   if(!m_phead->m_pLink)

   {

      throw out_of_range("FirstElementNotExist");

   }

   return m_phead->m_pLink->m_NodeEle; 

}

 

 

NodeElement& GenList::Next(const GenListNode* node)

{

   if(!node->m_pLink)

   {

      throw out_of_range("NextElementNotExist");

   }

   return node->m_pLink->m_NodeEle;

  

}

 

GenList& GenList::Push( const NodeElement& x)

{

   GenListNode* pnode = new GenListNode;

   assert(pnode);

   pnode->SetInfo(x);

   pnode->m_pLink = m_phead->m_pLink;

   m_phead->m_pLink = pnode;  

   return *this;

}

 

 

GenList& GenList::SetHead( const NodeElement& x)

{

   GenListNode* pnode = m_phead->m_pLink;

   if(!pnode)         //無元素表,主動生成第一個元素

   {

      pnode = new GenListNode;

      assert(pnode);

      m_phead->m_pLink = pnode;  

      pnode->m_pLink = 0;

   }

   pnode->SetInfo(x);

   return *this;

}

 

GenList& GenList::SetNext( const GenListNode* node, const NodeElement& x)

{

   if(node && node->m_pLink)

   {

      node->m_pLink->m_NodeEle.SetElement(x);     //設定節點元素值爲x    

   }

   return *this;

}

 

GenList& GenList::SetTail( GenList& list)

{

   GenListNode* tmp;

   tmp = m_phead->m_pLink->m_pLink;

   m_phead->m_pLink->m_pLink = list.m_phead->m_pLink;

   delete list.m_phead;  list.m_phead = 0;  //使list失去對原來表的控制,阻止其進行正常的析構操做

   this->remove(tmp);    //刪除原表的表尾 

   return *this;

}

 

GenList& GenList::SetTail(const GenList& list)

{

   GenListNode* tmp;

   tmp = m_phead->m_pLink->m_pLink;

   m_phead->m_pLink->m_pLink = this->copy(list.m_phead->m_pLink);   //遞歸複製

   this->remove(tmp);    //刪除原表的表尾 

   return *this;  

}

 

GenList& GenList::Copy(const GenList& list)

{

   remove(m_phead->m_pLink);

   m_phead->m_pLink = copy(list.m_phead->m_pLink);  

   return *this;

}

 

 

GenListNode* GenList::copy(const GenListNode* nd)   

{

   GenListNode* pnode = 0;

   if(nd)

   {

      pnode = new GenListNode;

      if(nd->GetInfo().GetTypeID() == LIST)   //節點中存儲的是子表

      {

         pnode->m_NodeEle.SetList( copy(nd->m_NodeEle.GetList()));

      } 

      else

      {

         pnode->m_NodeEle.SetElement(nd->m_NodeEle);

      }

      pnode->m_pLink = copy(nd->m_pLink);

   }

   return pnode;

}

 

//

int GenList::Depth() const

{

   return depth(m_phead);  

}

 

int GenList::depth(const GenListNode* list )  const

{

   if(!list->m_pLink) return 1;   //空表深度爲1

   GenListNode *tmp = list->m_pLink;

   int m = 0;

   while(tmp)

   {

      if(tmp->m_NodeEle.GetTypeID() == LIST)

      {

         int n = depth(tmp->m_NodeEle.GetList());

         if(m<n) m = n;

      }

      tmp = tmp->m_pLink;  

   }

   return m+1;

}

 

//

bool GenList::operator==(const GenList& list) const

{

   return IsEqual(m_phead, list.m_phead); 

}

 

bool GenList::IsEqual(const GenListNode* p, const GenListNode* q) const

{

   if(!p->m_pLink && !q->m_pLink)

   {

      //p,q都索引的是空表

      return true;

   }

  

   bool btest = false;

   if(p->m_pLink != 0 && q->m_pLink !=0

      && p->m_pLink->m_NodeEle.GetTypeID()

      == q->m_pLink->m_NodeEle.GetTypeID())

   {

      if( p->m_pLink->m_NodeEle.GetTypeID() == INT)

      {

         if(p->m_pLink->m_NodeEle.GetIntInfo() == q->m_pLink->m_NodeEle.GetIntInfo())

         {

            btest = true;

         }

         else btest = false;

      }

      else if(p->m_pLink->m_NodeEle.GetTypeID() == CH)

      {

         if(p->m_pLink->m_NodeEle.GetCharInfo() == q->m_pLink->m_NodeEle.GetCharInfo())

         {

            btest = true;

         } 

         else btest = false;  

      }

      //掃描到的是一個表頭索引,進入子表進行索引

      else btest = IsEqual(p->m_pLink->m_NodeEle.GetList(), q->m_pLink->m_NodeEle.GetList());

     

      //節點中的元素是相等的,比較下面一個節點

      if(btest)  return IsEqual(p->m_pLink, q->m_pLink);

   }

   return false;

}

 

//廣義表刪除操做,等同於析構

void GenList::remove(GenListNode* nd) //nd must be a head node

{

   if(nd) //delete nd if it is using

   {

      assert(nd->m_NodeEle.GetTypeID() == HEAD);

      nd->m_NodeEle.SetRef(nd->m_NodeEle.GetRef()-1);   //detach reference count

      if(!nd->m_NodeEle.GetRef())

      {

         //表頭已經再也不做爲任何子表

         GenListNode* ptmp = nd;

        

         while(ptmp != 0)

         {

            nd = nd->m_pLink;

            if( nd && nd->m_NodeEle.GetTypeID() == LIST )

            {

                //該節點爲子表索引,則遞歸刪除子表

                remove(nd->m_NodeEle.GetList()); 

            }

            delete ptmp;

            ptmp = nd;          

         }       

      }

   }

}

 

 

//刪除廣義表中的全部的指定的元素

GenList& GenList::Delete(const NodeElement& x)

{

   delvalue(m_phead, x);

   return *this;

}

 

//刪除元素的遞歸函數

void GenList::delvalue( GenListNode* list, const NodeElement& x)

{

   //list must be a headnode

   //x必須是原子節點表示的類型

   assert(x.GetTypeID() == INT || x.GetTypeID() == CH);

   if(list->m_pLink != 0)

   {

      GenListNode* ptmp = list->m_pLink;

      GenListNode* q = list;

      while(ptmp)

      {

         if(ptmp->m_NodeEle == x) //直接調用 NodeElement::operator==()

         {

            //若是是原子節點,則進行比較,相等則刪除

            q->m_pLink = ptmp->m_pLink;

            delete ptmp;         

         }

         else if(ptmp->m_NodeEle.GetTypeID()==LIST)

         {

            //發現子表,對子表進行遞歸刪除操做

            delvalue(ptmp->m_NodeEle.GetList(), x);

         }

         q = ptmp;

         ptmp = ptmp->m_pLink;               

      }

   } 

}

 

void GenList::CreatList()

{

  

   cout << " Please Input a List expression/n As this form: /n 21,5,(2,3,(42,p,x,61,n,(x,f,s,6),25,x)),p,x# " << endl;

   //由輸入流來創建一個新表的公用接口

   //必須先刪除原表

   remove(m_phead->m_pLink);

  

  

   //輸入格式爲:

   //21,5,(2,3,(42,p,x,61,n,(x,f,s,6),25,x)),p,x#

   //其中字符能夠相連,數字爲整型數,#爲輸入流終結控制符,

   //最外層表的括號得省

   m_phead->m_pLink = creatlist(cin); //參數是輸入流

}

 

GenListNode* GenList::creatlist(istream& in)

{

   //對輸入流進行處理,生成廣儀表

   char ch;

   while(in.get(ch), ch !='#')

   {

      if(ch != ',')

      {

         if(ch == '(')   //ch爲左括號,動做:生成一個原子節點,生成一個表頭索引,遞歸掃描流

         {

            GenListNode* nd = new GenListNode;

            GenListNode* lhead = new GenListNode;

           

            nd->m_NodeEle.SetList(lhead);  //

            lhead->m_NodeEle.SetRef(1);

            lhead->m_pLink = creatlist(in);   //遞歸生成子表

           

            nd->m_pLink = creatlist(in);   //在生成子表完成後繼續遞歸生成主幹表

           

            return nd;

         }

         else if(ch == ')')

         {

            //ch爲右括號,表遞歸結束,

            return 0;

         }

         else //ch表示字符或者是一個數字

         {

            if(isdigit(ch))    //ch爲數字,則生成一個存儲數字的原子節點

            {

                in.putback(ch);    //ch回推給流

                GenListNode* nd = new GenListNode;

               int x;

                in >> x;        //從流中獲取x值

                nd->m_NodeEle.SetIntInfo(x);

                nd->m_pLink = creatlist(in);   //遞歸流

               

                return nd;

            }

            else

            {

                //ch就表示一個字符

                GenListNode* nd = new GenListNode;

                nd->m_NodeEle.SetCharInfo(ch);

                nd->m_pLink = creatlist(in);   //遞歸流

               

                return nd;           

            }

         }

      }

   } // end while

   //運行到此表示 ch == '#',輸入流結束

   return 0; //終結指針

}

 

void GenList::output(std::ostream& out,const GenListNode* node) const

{

   if(!node)

   {

      return ;

   }

   switch(node->m_NodeEle.GetTypeID())

   {

      case HEAD:  //當前節點爲頭節點

      output(out,node->m_pLink);

      break;

     

      case INT:

      out << node->m_NodeEle.GetIntInfo();

      if(node->m_pLink)

      {

         out << ",";

      }

      output(out, node->m_pLink);

     

     

      break;

      case CH:

      out << node->m_NodeEle.GetCharInfo();

      if(node->m_pLink)

      {

         out << ",";

      }

      output(out, node->m_pLink);   

      break;

     

      case LIST:

      out << "(";

      output(out, node->m_NodeEle.GetList());

      out <<")";

      if(node->m_pLink)

      {

         out << ",";

      }

      output(out, node->m_pLink);

      break;

   }

}

 

std::ostream& operator<<(std::ostream& out, const GenList& list)

{

   out << "The GenList is: /n";

   list.output(out,list.m_phead);

   return out;

}

相關文章
相關標籤/搜索