广义表的类定义及其操作的实现

来源:互联网 发布:java编写手机游戏 编辑:程序博客网 时间:2024/05/24 00:39

1.头文件

# include <iostream>using namespace std;struct GenListNode{        //广义表结点int utype;         //结点类型:=0附加头结点;=1原子结点;=2子表结点GenListNode *tlink; //尾指针union {  //联合体:utype=0,该结点存引用计数ref;=1该结点存值value;=2该结点存子表的头指针int ref;int value;GenListNode *hlink;} info;GenListNode():utype(0),tlink(NULL){ //结点构造函数info.ref=0;}GenListNode(GenListNode& RL){ //复制构造函数utype=RL.utype;tlink=RL.tlink;switch(utype){    //根据utype的值进行赋值操作case'0':info.ref=RL.info.ref; break;case'1':info.value=RL.info.value; break;case'2':info.hlink=RL.info.hlink; break;}}};struct Items{  //该数据类型用于取表头,表尾函数,不包含tlink,与单链表比较即可理解。int utype;union{int ref;int value;GenListNode *hlink;}info;Items():utype(0){     //构造函数info.ref=0;}Items(Items& RL){  //复制构造函数utype=RL.utype;switch(utype){case'0':info.ref=RL.info.ref; break;case'1':info.value=RL.info.value; break;case'2':info.hlink=RL.info.hlink; break;}}};class GenList{    //广义表类private:GenListNode *first;   //头指针GenListNode* Copy(GenListNode *ls); //复制ls指的广义表并返回该表的头指针int Length(GenListNode *ls);//求ls指示的广义表的长度int Depth(GenListNode *ls); //求ls所指的广义表的深度bool Equal(GenListNode *s,GenListNode *t); //判断两个广义表是否相同void Remove(GenListNode *ls); //释放ls所指的广义表void Createlist(istream& istr,GenListNode *&ls); //根据输入流建立广义表void delvalue(GenListNode *ls,int x); //删除广义表中原子结点值为x的结点public:GenList(); //构造函数~GenList(); //析构函数bool Head(Items& x);  //取表头bool Tail(GenList& lt);  //取表尾GenListNode* First(); //求第一个元素的地址GenListNode* Next(GenListNode *elem); //求elem所指的下一个元素的地址void Copy(const GenList& R);  //复制广义表R给调用该函数的广义表int Length();  //求调用该函数的广义表的长度int Depth();  //求广义表深度friend istream& operator>>(istream& istr,GenList& L);  //根据输入流建立广义表};
2.操作的实现

# include<iostream># include<assert.h># include"GenList.h"using namespace std;GenList::GenList(){  //构造函数,构造一个空表first=new GenListNode;assert(first!=NULL);}bool GenList::Head(Items& x){ //取表头if(first->tlink==NULL) return false;else{x.utype=first->tlink->utype;switch(x.utype){case'1':x.info.value=first->tlink->info.value; break;case'2':x.info.hlink=first->tlink->info.hlink; break;}return true;}};bool GenList::Tail(GenList& lt){  //取表尾if(first->tlink==NULL) return false;else{lt.first->utype=0;  //设置附加头结点lt.first->info.ref=0;lt.first->tlink=Copy(first->tlink->tlink); //调用Copy函数取表尾return true;}}GenListNode* GenList::First(){  //取第一个元素的地址if(first->tlink==NULL) return NULL;else return first->tlink;}GenListNode* GenList::Next(GenListNode *elem){ //取elem下一个结点的地址if(elem->tlink==NULL) return NULL;else return elem->tlink;}void GenList::Copy(const GenList& R){ //把广义表R赋值给调用该函数的广义表first=Copy(R.first);//调用了下面的Copy函数}GenListNode* GenList::Copy(GenListNode *ls){   //赋值ls所指的广义表并返回副本的头指针GenListNode *p=NULL;if(ls!=NULL){p=new GenListNode; p->utype=ls->utype; //复制表头switch(ls->utype){case'0':p->info.ref=ls->info.ref; break;case'1':p->info.value=ls->info.value; break;case'2':p->info.hlink=Copy(ls->info.hlink); break;}p->tlink=Copy(ls->tlink); //复制表尾}return p;  //返回头指针}int GenList::Length(){  //返回广义表的长度return Length(first);}int GenList::Length(GenListNode *ls){ //求广义表长度if(ls==NULL) return 0;else return 1+Length(ls->tlink);//递归求长度}int GenList::Depth(){  //返回广义表的深度return Depth(first);}int GenList::Depth(GenListNode *ls){ //求广义表深度if(ls->tlink==NULL)  //空表深度为一return 1;GenListNode *temp=ls->tlink;int m=0,n;while(temp!=NULL){  //求子表的最大深度if(temp->utype==2){n=Depth(temp->info.hlink);if(m<n) m=n;}temp=temp->tlink;}return m+1; //广义表的深度就是子表的最大深度+1}bool GenList::Equal(GenListNode *s,GenListNode *t){  //判断两个广义表是否相等int x;if(s->tlink==NULL&&t->tlink==NULL) return true;//都为空表,相等else if(s->tlink!=NULL&&t->tlink!=NULL&&s->tlink->utype==t->tlink->utype){  //判断表头是否相等if(s->tlink->utype==1)x=(s->tlink->info.value==t->tlink->info.value)?1:0;else if(s->tlink->utype==2)x=Equal(s->tlink->info.hlink,t->tlink->info.hlink);if(x==1)   //表头相等,接着判断表尾是否相等return Equal(s->tlink,t->tlink);}return false;}void GenList::delvalue(GenListNode *ls,int x){  //删除广义表中所有原子值为x的结点if(ls->tlink==NULL) return;    //ls为空表GenListNode *temp=ls->tlink;while(temp!=NULL){       while(temp->utype==1){ //如果该点为原子结点,用while因为可能连续几个结点都是原子结点         if(temp->info.value==x){ //值为x,删除该结点          ls->tlink=temp->tlink;          delete temp;         }   temp=ls->tlink;        }       if(temp->utype==2){  //该点为子表结点        delvalue(temp->info.hlink,x); //删除子表中所有原子值为x的结点            temp=temp->tlink;   }}return ; //删除完毕,返回到主函数}GenList::~GenList(){  //析构函数Remove(first);}void GenList::Remove(GenListNode *ls){ //释放ls指示的广义表if(ls->tlink==NULL)  //如果ls为空表,删除附加头结点delete ls;GenListNode *temp=ls->tlink;while(temp!=NULL){while(temp!=NULL&&temp->utype==1){ //原子结点         ls->tlink=temp->tlink;         delete temp;         temp=ls->tlink;        }if(temp->utype==2&&temp!=NULL){ //子表结点               Remove(temp->info.hlink); //删除该节点hlink指示的子表   ls->tlink=temp->tlink; //删除该结点   delete temp;               temp=ls->tlink;}}delete ls; //删除附加头结点return ; //返回主函数}

3.阅读建议

(1)由于建立广义表的算法比较复杂,因此本文中并未包括CreateList函数的实现,过几天我再单独写一篇。

(2)本文中基本所有重要函数的实现都用到了递归算法,对对递归不熟悉的小伙伴帮助应该会比较大(包括我)。很多函数只看代码应该不太容易看懂,于是附加一张广义表的结构图,大家可以手动在纸上执行递归的过程:


(3)关于递归过程中创建局部变量的问题,跟大家分享一个百度知道的问题,相信对大家理解递归有帮助:(在此处谢谢答主)

问题:当函数发生递归调用时,同一个局部变量在不同程度上可以同时存在不同的取值,这在底层是如何做到的? 

解答:

你在源代码中看到的一个局部变量,其实在函数递归过程中是存在很多副本的。


比如,你在源代码中看到一个一个局部变量 a
其实在函数递归掉用的时候,每调用一次都会在所调用函数的运行空间里存储一个a的,所以其实存在很多很多的不同的a,他们各自的存储空间是不一样的,当然能存储不同的取值了。



开始调用t(),先为t()分配存储空间,存储空里有一个a
然后t()调用t()(我们称之为t1()),先为t1()分配存储空间,存储空间里有存一个a(与前面的a是不同的)
t1()又调用t()(我们称之为t2()),先为t2分配存储空间,存储空间里存一个a(又是一个不同的a)
.....................以此类推


所以,并不是“同一个局部变量在不同程度上可以同时存在不同的取值” 
而是“不同的局部变量在不同的函数空间里存储了不同的值”



1 0