广义表的实现(c++实现)

本文要点:

1.广义表的存储结构

2.广义表的简单实现,包括:构造、拷贝构造、赋值运算符重载、广义表的大小Size、深度Depth以及输出函数


广义表是非线性的结构,是一种线性表的推广,它由n个元素组成有限序列。广义表的定义是递归的。

一、广义表的存储结构

由于广义表中的数据元素可以有不同结构,采用顺序表的结构是很难实现的,因此通常采用链式存储结构,每个元素可用一个节点表示,一个结点有可能是头结点_head,有可能是值结点_value,也有可能是子表项_sub(递归)。如广义表A、B、C、D、E是这样定义:

A = ()

B = (a,b)

C = (a,b,(c,d))

D = (a,b,(c,d),(e,(f),h))

来看看这个表的存储结构:


从上图我们也可以很清晰的看到,一个结点的内容有三种,并且只要遇到 “(” 就有子表项,遇到 “)” 该子表项结束。因此要用链表的方式实现广义表,我们首先要定义出结点内容:

enum TYPE
{
	HEAD_TYPE,	//表头
	VALUE_TYPE,	//值
	SUB_TYPE,	//子表
};

struct GeneralizedNode
{
	GeneralizedNode(TYPE type,const char& value=0)
		:_type(type)
		,_next(NULL)
		,_sublink(NULL)
	{
		_value = value;
	}

	TYPE _type;		//类型
	GeneralizedNode* _next;	//指向下一个表项
	union
	{
		char _value;
		GeneralizedNode* _sublink;	//指向子表头
	};
	//除头结点外,剩下的节点中每个结点有可能是value也可能是sub,因此用联合
};


二、接下来就是广义表的实现部分了:

class GeneralizedList
{
	typedef GeneralizedNode Node;
public:
	GeneralizedList()
		:_head(NULL)
	{}

	GeneralizedList(const char* str)
		:_head(NULL)
	{
		_head = _CreatList(str);
	}
	
	GeneralizedList(const GeneralizedList& g)	//拷贝构造
	{
		_head = _copy(g._head);
	}

	~GeneralizedList()
	{
		Destory(_head);
	}

	GeneralizedList& operator=(const GeneralizedList& g)
	{
		//_head = _assignment(g);
		if (this != &g)
		{
			GeneralizedList tmp(g);
			std::swap(_head,tmp._head);
		}
		return *this;
	}

	size_t Size()
	{
		return _size(_head);
	}
	size_t Depth()
	{
		return _depth(_head);
	}
	void Print()
	{
		_print(_head);
	}
protected:
	bool Judge(const char& value)
	{
		if ((value >= '0' && value <= '9') ||
			(value >= 'a' && value <= 'z') ||
			(value >= 'A' && value <= 'Z') )	
			return true;
		else
			return false;
	}
	Node* _CreatList(const char*& str)
	{
		assert(*str == '(');
		Node* head = new Node(HEAD_TYPE,*str);
		Node* prev = head;
		head->_type = HEAD_TYPE;
		++str;
		while (*str)
		{
			if (Judge(*str))		//有效值项
			{
				Node* node = new Node(VALUE_TYPE,*str);
				prev->_next = node;
				prev = prev->_next;

				++str;
			}
			else if (*str == '(')		//有子表项
			{
				Node* node = new Node(SUB_TYPE,*str);
				prev->_next = node;
				prev = prev->_next;
				prev->_sublink = _CreatList(str);
				++str;
			}
			else if (*str == ')')
			{
				prev->_next = NULL;

				++str;
				return head;
			}
			else
				++str;
		}
		return head;
	}
	Node* _copy(Node* copyhead)
	{
		assert(copyhead);
		Node* newhead = new Node(HEAD_TYPE,copyhead->_value);	//新表的头
		Node* prev = newhead;
		Node* cur = copyhead->_next;
		while (cur)
		{
			if (cur->_type == VALUE_TYPE)	//拷贝值结点
			{
				Node* tmp = new Node(VALUE_TYPE,cur->_value);
				prev->_next = tmp;
				prev = prev->_next;
				cur = cur->_next;
			}
			else if (cur->_type == SUB_TYPE)		//拷贝子表
			{
				Node* tmp = new Node(SUB_TYPE);
				prev->_next = tmp;
				prev = prev->_next;
				tmp->_sublink = _copy(cur->_sublink);
				cur = cur->_next;
			}
			else
				cur = cur->_next;
		}
		return newhead;
	}
	void Destory(Node* head)
	{
		Node* cur = head;
		while (cur)
		{
			Node* del = cur;
			if (cur->_type == SUB_TYPE)
			{
				Destory(cur->_sublink);
			}
			cur = cur->_next;
			delete[] del;
		}
	}
	Node* _assignment(const GeneralizedList& g)
	{
		assert(g._head);
		if (this != &g)
		{
			Node* newhead = new Node(HEAD_TYPE,g._head->_value);
			Destory(_head);
			_head = newhead;
		}
		return _head;
	}
	size_t _size(Node* head)	//表内有效值的个数
	{
		Node* cur = head;
		size_t count = 0;
		while (cur)
		{
			if (cur->_type == VALUE_TYPE)
			{
				count++;
			}
			else if (cur->_type == SUB_TYPE)
			{
				count += _size(cur->_sublink);
			}
			cur = cur->_next;
		}
		return count;
	}
	size_t _depth(Node* head)	//表的最大深度
	{
		Node* cur = head;
		size_t maxdepth = 1;
		while(cur)
		{
			size_t depth = 1;
			if (cur->_type == SUB_TYPE)
			{
				depth += _depth(cur->_sublink);
				if (depth > maxdepth)
				{
					maxdepth = depth;
				}
			}
			cur = cur->_next;
		}
		return maxdepth;
	}
	void _print(Node* head)
	{
		assert(head);
		Node* cur = head;
		while (cur)
		{
			if (cur->_type == VALUE_TYPE)
			{
				cout<<cur->_value;
				if (cur->_next != NULL)
				{
					cout<<",";
				}
				cur = cur->_next;
			}
			else if (cur->_type == SUB_TYPE)
			{
				_print(cur->_sublink);
				if (cur->_next != NULL)
				{
					cout<<",";
				}
				cur = cur->_next;
			}
			else
			{
				cout<<"(";
				cur = cur->_next;
			}
		}
		cout<<")";
	}
protected:
	Node* _head;
};












  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
广义表是一种线性结构,它可以包含原子和子表。下面是一个简单的C++实现: ```c++ #include<iostream> using namespace std; //定义广义表结点 template<typename T> class GLNode{ public: bool tag;//标记,1表示结点是原子,0表示结点是子表 union{ T atom; GLNode<T> *hp;//指向广义表的表头 }; GLNode<T> *tp;//指向广义表的表尾 GLNode(bool t, T a = 0, GLNode<T> *h = nullptr, GLNode<T> *t2 = nullptr) :tag(t), atom(a), hp(h), tp(t2){} }; //定义广义表类 template<typename T> class GList{ public: GList(string str);//字符串构造广义表 void PrintList();//打印广义表 private: GLNode<T> *head;//广义表头结点 }; //构造函数 template<typename T> GList<T>::GList(string str){ int len = str.length(); head = nullptr; GLNode<T> *p = nullptr, *q = nullptr; int k = 0;//记录当前扫描到的位置 while (k < len){ char ch = str[k]; if (ch == '('){//遇到左括号,创建新的子表 q = new GLNode<T>(0, 0, nullptr, nullptr); if (!head) head = q; else p->tp = q; p = q; k++; } else if (ch == ')'){//遇到右括号,回溯到上一层子表 p = p->hp;//回到上一层子表 k++; } else if (ch == ',') k++; else{//读入原子 string str_atom; while (k < len && str[k] != '(' && str[k] != ')' && str[k] != ','){ str_atom += str[k]; k++; } q = new GLNode<T>(1, str_atom, nullptr, nullptr); if (!head) head = q; else p->tp = q; } } } //打印广义表 template<typename T> void GList<T>::PrintList(){ GLNode<T> *p = head; cout << "("; while (p){ if (p->tag) cout << p->atom; else{ GList<T> gl(p->hp); gl.PrintList(); } if (p->tp) cout << ","; p = p->tp; } cout << ")"; } int main(){ string str = "(1,(2,3),4)"; GList<string> gl(str); gl.PrintList(); cout << endl; return 0; } ``` 使用示例: 输入字符串 `(1,(2,3),4)`,输出结果 `(1,(2,3),4)`

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值