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

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)
.....................以此类推


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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值