广义表的述说

广义表

说到广义表,就必须知道它是个什么东西!!!!    今天就让我来详详细细的向大家来说说这个广义表。。。

广义表   是一种    数据结构    ,,  ,这种表的结构是     链式存储的  ,,,,,是线性表的一种扩展。。。。
是 由  n个元素组成的有限序列。。。。


广义表   的定义可以说是递归的一种体现 ,,, , 因为在广义表 中不仅可以存在存数据,,,还可以存一个子表(广 义表 ),,,所以我们在这块只能使用递归来建立了。。。。。


下面是四种广义表
<1> A = ()
<2> B = (a,b)
<3> C = (a,b,(c,d))
<4> D = (a,b,(c,d),(e,(f),h))
<5> E = (((),()))

广义表的结构   我们制定的结构是这样的

这是上面的C广义表的结构 

通过这个这个结构我们可以进而推断出来广义表的每个   节点的  内容   
1、节点类型(判断这个节点有什么作用)
2、指针域(用来指向下一个节点的指针)
3、数据值(如果是值节点,要有这个值的数据)
4、链接指针(如果这个节点是子表节点,,,,需要有个指针指向字表的头)

这些内容  中   
节点类型  包括三种  头节点  、、 值节点、、、 子表节点    这些类型我们可以 用 一个枚举量来表示(每个节点都有)

//定义一种枚举常量 ,, 用来表示节点类型
enum Type
{
	HEAD,//表示节点类型为 头节点
	VALUE,//表示节点类型为 值节点
	SUB,//表示节点类型为 子表节点
};
指针域     是一个节点指针  指向一个 下个节点的指针(每个节点都有)

数据值    表示的值节点所表示的数据(只有值节点才有)

链接指针   指向一个子表节点的头 (只有子表节点才有)


因为 数据值  ,,,  与  链接指针      都只有  值节点   与  子表节点    才有  
如果     我们为每一个节点都开辟一个一段空间,,,,要是节点的量过大的话  ,,,, 那么造成的浪费就严重了
所以     我们想到一个变量      union(共用体)                我们都知道这中 变量内部的成员共用的是同一段空间,
这样     我们可以根据节点类型的不同使用不同的变量  ,,, , ,既不会产生错误 ,,, ,也不会浪费空间。。


节点的定义代码

struct GeneralListNode//广义表节点
{
	GeneralListNode* _next;//指针域
	Type _type;//节点类型
	union//匿名的共用体
	{	
		GeneralListNode* _subLink;//链接指针
		char _value;//数据值
	};
	GeneralListNode(Type type = HEAD,char value  = ' ')//构造函数
		:_next(NULL)
		,_type(type)
	{
		if(_type == VALUE)//如果节点类型为值节点
		{
			_value = value;//将节点的数据给数据值
		}
		else//否则
		{
			_subLink= NULL;//节点的链接为NULL
		}
	}	
};

针对一个广义表我们必须要实现的操作有
构造函数 
拷贝构造
赋值运算符的重载
析构函数
求节点个数
求广义表的深度

为什么我把   构造函数   、、、 拷贝构造 、、、、赋值运算符重载、、、、析构函数    也说出来呢?????

因为  这里的这些函数我们都要自己实现 ,,,,为什么要自己实现呢???

因为  这里的节点存在子表节点 ,,,, ,如果直接实现的话 ,,,, 解药用到大量的循环  ,,,不仅很难实现
而且难理解  ,,,,并且还容易错     所以在这里我们对于这这些函数的实现要用到递归实现

下面是代码的实现
class GeneralList
{
	typedef GeneralListNode  Node;
public:
	//构造函数
	GeneralList(const char *s)//s表示是一个字符串 
	{
		_head = CreatList(s);	//调用自己实现的构造函数
	}
	GeneralList(const GeneralList& g)
	{
		_head = _Copy(g._head);
	}
	GeneralList& operator=(const GeneralList& g)
	{
		if(this != &g)
		{
			GeneralList tem(g);
			std::swap(_head,tem._head);
		}
		return  *this;
	}
	~GeneralList()
	{
		Distroy();
	}
public:
	void Distroy()
	{
		_Distroy(_head);
		_head = NULL;
	}
	void Print()
	{
		_Print(_head);
		cout<<endl;
	}
	//求节点的个数
	size_t Size()
	{
		return _Size(_head);
	}
	//求广义表的深度
	size_t Depth()
	{
		return  _Depth(_head);
	}
protected:
	//判断字符串中每个字符 来决定,,,,是不是需要值节点
	bool CheckValue(const char& s)
	{
		if((s >= '0'&&s <='9')
			||(s >= 'a'&&s<='z')
			||(s >= 'A'&&s<='Z'))
			return true;
		return false;
	}
	//自己实现的构造函数
	Node * CreatList(const char* & s)
	{
		assert(*s =='(');//进来判断一下是不是需要建立广义表
		Node * newhead = new Node(HEAD);//如果需要必须要先建立一个头节点
		Node * tail   = newhead;//定义tail节点指针 表示广义表最后一个节点
		++s;
		while(*s)
		{
			if(CheckValue(*s))//如果是值节点
			{
				tail->_next =new Node(VALUE ,*s);//最后一个节点  指针域  指向  一个新建立的值节点
				tail = tail->_next;//最后一个节点后移
				++s;//字符串向后
			}
			else if(*s == '(')//需要建立一个子表节点
			{
				tail ->_next = new Node(SUB);
				tail =tail->_next; 
				tail->_subLink =  CreatList(s);	//子表的链接指针为一个新的广义表		
			}
			else if(*s ==')')//表示广义表结束
			{
				++s;
				return newhead;
			}
			else
			{
				++s;
			}
		}
		return newhead;	
	}
	void _Distroy(Node * head)//节点的销毁
	{
		Node * cur = head;
		assert(cur->_type==HEAD);//判断是不是头节点
		while(cur)
		{
			if(cur->_type ==SUB)//如果是子表节点
			{
				_Distroy(cur->_subLink);// 递归  将子表的链接指针销毁
				Node *del  = cur;
				cur= cur->_next;
				delete del;
			}
			else
			{
				Node *del  = cur;
				cur= cur->_next;
				delete del;
			}
		}
	}
	size_t _Size(Node* head)//广义表节点的个数可以看成是  值节点的个数加上  子表节点的个数
	{
		Node * cur =head;
		assert(cur->_type == HEAD);
		size_t count =  0;
		while(cur)
		{
			if(cur->_type ==VALUE)//如果是值节点  +1
			{
				++count;
				cur =cur->_next; 
			}
			else if(cur->_type ==HEAD)//头节点  跳过
			{
				cur = cur->_next;
			}
			else if(cur->_type ==SUB)//子表节点   递归
			{
				count += _Size(cur->_subLink); 
				cur= cur->_next;
			}
			else
			{
				assert(false);
			}
		}
		return count;
	}
	size_t _Depth(Node *head)//深度为 1+上最大的子表深度
	{
		Node * cur = head;
		assert(cur->_type == HEAD);
		size_t maxdepth = 1;//1  为当前的深度
		while(cur)
		{
			if(cur->_type== SUB)
			{
				size_t depth =  1+_Depth(cur->_subLink);
				if(depth >maxdepth)
				{
					maxdepth = depth;//  广义表的深度就是当前的深度+上最大的子表的深度
				}
			}
			cur = cur->_next;
		}
		return  maxdepth;//如果当前的层   没有子表   ,深度为1
	}
	Node*  _Copy(Node * head)//拷贝构造
	{
		Node *cur = head;
		assert(cur->_type == HEAD);//判断是头节点的话    ,可进入
		Node* newhead = new Node();//建立一个头节点
		Node* tail = newhead;
		cur = cur->_next;
		while(cur)
		{
			if(cur->_type == VALUE)//如果是值节点
			{
				tail->_next  =new Node(VALUE,cur->_value);//用值节点的数据来创建一个新的节点
				tail = tail->_next;
				cur = cur->_next;
			}
			else if(cur->_type ==SUB)
			{
				tail->_next = new Node(SUB);//如果遇到子表节点,,,,创建一个子表节点
				tail = tail->_next;
				tail->_subLink = _Copy(cur->_subLink);//递归复制建立一个广义表链接到子表节点的链接指针
				cur = cur->_next;
			}
			else
			{
				cur = cur->_next;
			}
		}
		return newhead;
	}
	void _Print(Node * head)
	{
		Node * cur = head;
		assert(cur->_type ==HEAD);
		while(cur)
		{
			if(cur->_type==VALUE)
			{
				cout<<cur->_value;
				if(cur->_next)
				{
					cout<<',';
				}
			}
			else if(cur->_type== HEAD)
			{
				cout<<'(';
			}
			else if(cur->_type== SUB)
			{
				_Print(cur->_subLink);
				if(cur->_next)
				{
					cout<<',';
				}
			}
			else
			{
				assert(false);
			}
			cur = cur->_next;
		}
		cout<<')';
	}

protected:
	Node * _head;
};


void TestGeneralList()
{
	GeneralList  g1("()");
	g1.Print();
	cout<<"g1.size = "<<g1.Size()<<endl;
	cout<<"g1.Depth = "<<g1.Depth()<<endl;
	GeneralList  g2("(a,b)");
	g2.Print();
	cout<<"g2.size = "<<g2.Size()<<endl;
	cout<<"g2.Depth = "<<g2.Depth()<<endl;
	GeneralList  g3("(a,b,(c,d))");
	g3.Print();
	cout<<"g3.size = "<<g3.Size()<<endl;
	cout<<"g3.Depth = "<<g3.Depth()<<endl;
	GeneralList  g4("(a,b,(c,d),(e,(f),h))");
	g4.Print();
	cout<<"g4.size = "<<g4.Size()<<endl;
	cout<<"g4.Depth = "<<g4.Depth()<<endl;
	GeneralList  g5("(((),()))");
	g5.Print();
	cout<<"g5.size = "<<g5.Size()<<endl;
	cout<<"g5.Depth = "<<g5.Depth()<<endl;
	GeneralList g6(g3);
	g6.Print();
	g5 =  g4;
	g5.Print();


}


大家要是看了还有什么不懂的地方 ,,,,或者写了有什么错误都可私聊我
 

 











评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值