廣義表

廣義表是非線性結構,其定義是遞歸的。

以下給出幾種簡單的廣義表模型:

wKioL1cU06LDp3cZAAAGadRgppI798.png

wKiom1cU0uWjiRe8AAAM3dKYxa8731.png

wKioL1cU06PCYs3lAAAm-7A2avQ633.png

由上圖我們可以看到,廣義表的節點類型無非head、value、sub三種,這裏設置枚舉類型,利用枚舉變量來記錄每個節點的類型:

enum  Type
{
	HEAD,   //頭節點
	VALUE,  //值節點
	SUB,    //子表節點
};

每個節點都有自己的類型以及next指針,除此之外,如果該節點是VALUE類型還要分配空間存儲該節點的有效值;但是若該節點是SUB類型,就需定義一個指針指向子表的頭。

這裏我們可以用聯合來解決這個問題。

(聯合(或共同體)是一種不同數據類型成員之間共享存儲空間的方法,並且聯合體對象在同一時間只能存儲一個成員值)

構造節點

struct GeneralizedNode
{
	Type _type;       //  1.類型
	GeneralizedNode* _next;  //2.指向同層的下一個節點
	union
	{
		char _value;    //  3.有效值
		GeneralizedNode* _subLink;     // 3.指向子表的指針
	};
	
	GeneralizedNode(Type type = HEAD, char value = '0')
	:_value(value)
	,_type(type)
	, _next(NULL)
	{
		if (_type == SUB)
		{
			_subLink = NULL;
		}
	}
};

廣義表的定義及基本操作

class Generalized
{
public:
	//無參的構造函數,建立空的廣義表
	Generalized();
	//建造廣義表,有參數的構造函數
	Generalized(const char* str);
	//打印廣義表
	void Print();
	//獲取值節點的個數
	size_t Amount();
	//獲取廣義表的深度
	size_t Depth();
	//拷貝構造
	Generalized(const Generalized& g);
	////賦值運算符的重載
	Generalized& operator=(const Generalized& g);
	////析構函數
	~Generalized();

protected:
	void _Print(GeneralizedNode* head);
	GeneralizedNode* _CreatList(const char*& str);
	size_t _Amount(GeneralizedNode* head);
	GeneralizedNode* _Copy(GeneralizedNode* head);
	void _Destory(GeneralizedNode* head);
protected:
	GeneralizedNode* _head;   //記錄廣義表頭指針
};

初始化建立廣義表進行循環遞歸。遍歷字符串時遇到字符就建立值節點,遇到'('就進行遞歸併建立子表;遇到')'就結束當前子表的建立,並返回當前子表的頭指針。

GeneralizedNode* _CreatList(const char*& str)
	{
		assert(*str == '(');
		GeneralizedNode* head = new GeneralizedNode(HEAD,'0');
		GeneralizedNode* cur = head;
		str++;
		while (str != '\0')
		{
			if ((*str >= '0'&&*str <= '9') || (*str >= 'a'&&*str <= 'z') || (*str >= 'A'&&*str <= 'Z'))
			{
				cur->_next = new GeneralizedNode(VALUE, *str);
				cur = cur->_next;
			}
			else if (*str == '(')
			{
				cur->_next = new GeneralizedNode(SUB);
				cur = cur->_next;
				cur->_subLink = _CreatList(str);
			}
			else if (*str == ')')
			{
				return head;
			}
			str++;
		}
		return head;
	}

打印廣義表:當節點的類型爲SUB時進行遞歸,最後不要忘了每打印完一層要打印一個後括號。

void _Print(GeneralizedNode* head)
	{
		if (head == NULL)
		{
			cout << "Generalized table is NULL" << endl;
			return;
		}
		GeneralizedNode* cur = head;
		while (cur)
		{
			if (cur->_type == HEAD)
			{
				cout << '(';
			}
			else if (cur->_type == VALUE)
			{
				cout << cur->_value;
				if (cur->_next)
				{
					cout << ',';
				}
			}
			else if (cur->_type == SUB)
			{
				_Print(cur->_subLink);
				if (cur->_next)
				{
					cout << ',';
				}				
			}
			cur = cur->_next;
		}
		cout << ')';
	}

獲取值節點的個數:設置count變量,遇到值節點就加1,遇到SUB節點進行遞歸併將返回值加給count

size_t _Amount(GeneralizedNode* head)
	{
		GeneralizedNode* begin = head;
		size_t count = 0;
		while (begin)
		{
			if (begin->_type == VALUE)
			{
				count++;
			}
			if (begin->_type == SUB)
			{
				count += _Amount(begin->_subLink);
			}
			begin = begin->_next;
		}
		return count;
	}

廣義表的深度:設置變量dp和max分別用來記錄當前子表即當前SUB節點指向的子表深度,以及本層所有的SUB節點中深度最大的子表的深度。

size_t _Depth(GeneralizedNode* head)
	{
		if (_head == NULL)
		{
			return 0;
		}
		size_t dp=0;
		GeneralizedNode* cur = head;
		size_t max = 0;
		while (cur)
		{
			if (cur->_type == SUB)
			{
				dp=_Depth(cur->_subLink);
				if (max < dp)
				{
					max = dp;
				}
			}
			cur = cur->_next;
		}
		return max+1;
	}

銷燬廣義表:依次遍歷節點,遇到子表遞歸,將子表的節點delete完成後,再回到當前層繼續遍歷。

void _Destory(GeneralizedNode* head)
	{
		if (head == NULL)
		{
			return;
		}
		while (head)
		{
			GeneralizedNode* begin = head->_next;
			if (head->_type == SUB)
			{
				_Destory(head->_subLink);
			}
			delete head;
			head = begin;
		}
	}

廣義表的拷貝構造及賦值運算符重載與構造函數的遞歸方式類似,這裏就不再闡述冗餘信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章