1. 程式人生 > >廣義表3——廣義表的擴充套件線性連結串列表示

廣義表3——廣義表的擴充套件線性連結串列表示


【結點結構】
用擴充套件線性連結串列表示時,廣義表也可以包含兩種結點:表結點和原子結點,這兩種結點都包含三個域。其中,表結點由標誌域tag、表頭指標域hp、表尾指標域tp構成:原子結點由指標域、原子的值域和表尾指標域構成。


標誌域tag用來區分當前結點是表結點還是原子結點,當tag=0時為原子結點,tag=1時為表結點;hp和tp分別指向廣義表的表頭和表尾;atom用來儲存原子結點的值。擴充套件線性連結串列的結點

如圖所示。


例如,A=(),B=(a),C=(a,(b,c)),D=(A,B,C),E=(a,E)

則廣義表A、B、C、D、E的擴充套件線性連結串列儲存結構如圖所示

【儲存結構】

typedef enum{ATOM,LIST}ElemTag; /*ATOM=0,表示原子,LIST=1,表示子表*/
typedef struct
{
    ElemTag tag;                 /*標誌位tag用於區分元素是原子還是子表*/
    union
    {
        AtomType atom;         /*AtomType是原子結點的值域,使用者自己定義型別*/
        struct
        {
            struct GLNode *hp,*tp;        /*hp指向表頭,tp指向表尾*/
        }ptr;
    };
}*GList,GLNode;

【問題】
編寫演算法,利用擴充套件線性連結串列表示法建立廣義表,要求在輸入廣義表的同時實現建立,設廣義表按形式:(a,b,(a,(a,b,c),d),e)輸入,並求廣義表的深度和長度。

【分析】

該題是北京工業大學考研試題。廣義表中的元素有原子和子表,在讀入輸入的字串時,遇到左括號"("時,就遞迴構造子表;若是原子,就建立原子結點;若讀入逗號“,”就遞迴構造後續子表;若n為0,則構造含空格字元的空表,直到遇見結束符“\n”為止。

main.cpp

#include<stdio.h>
#include<stdlib.h>
#include<iostream>

using namespace std;
typedef char AtomType;//元素型別為字元型
typedef enum { ATOM, LIST }ElemTag; /*ATOM=0,表示原子,LIST=1,表示子表*/
									//廣義表的儲存結構
struct GNode
{
	ElemTag tag;	//標誌域
	union
	{
		AtomType atom;	//值域
		struct GNode *hp;//子表的表頭指標
	};
	struct GNode *tp;	//後繼結點的指標
};
int LengthGList(struct GNode *GL);	//求廣義表的長度
int DepthGList(struct GNode *GL);	//求廣義表的深度
void CreateGList(struct GNode **GL);//建立廣義表的儲存結構
void PrintGList(struct GNode *GL);	//列印輸出廣義表
int SearchGList(struct GNode *GL, AtomType e);//查詢等於給定字元的單元素結點,查詢成功則返回1,否則返回0

void main()
{
	int flag;
	AtomType e;
	struct GNode *GL;
	cout << "輸入一個廣義表(以回車結束)." << endl;
	CreateGList(&GL);
	cout << "輸出廣義表:" << endl;
	PrintGList(GL);
	cout << endl;
	cout << "廣義表的長度:";
	cout << LengthGList(GL->hp) << endl;
	cout << "廣義表的深度:";
	cout << DepthGList(GL->hp) << endl;
	cout << "請輸入要查詢的原子元素:" << endl;
	cin >> e;
	flag = SearchGList(GL, e);
	if (flag)
		cout << "廣義表中存在查詢的元素。" << endl;
	else
		cout << "要查詢的元素不存在。" << endl;


	system("pause");
}
int LengthGList(struct GNode *GL)
//求廣義表的長度
{
	if (GL != NULL)
		return(1 + LengthGList(GL->tp));
	else
		return(0);
}
int DepthGList(struct GNode *GL)
//求廣義表的深度
{
	int max = 0;//給max賦初值
	int dep;
	//遍歷表中每一個結點,求出所有子表的最大深度
	while (GL != NULL)
	{
		if (GL->tag == LIST)
		{
			dep = DepthGList(GL->hp);//遞迴呼叫求出一個子表的深度
			if (dep > max)
				max = dep;//讓max始終為同一層所求過的子表中深度的最大值
		}
		GL = GL->tp;//使GL指向同一層的下一個結點
	}
	return max + 1;//返回表的深度
}
void CreateGList(struct GNode **GL)
//建立廣義表的儲存結構
{
	char ch;
	scanf("%c", &ch);//讀入一個字元,此處只可能讀入空格#、左括號或英文字母
	if (ch == '#')//若輸入為空格,則置表頭指標為空
		*GL = NULL;
	else if (ch == '(')//若輸入為左括號則建立由*GL所指向的子表結點並遞迴構造子表
	{
		*GL = (struct GNode*)malloc(sizeof(struct GNode));
		(*GL)->tag = LIST;
		CreateGList(&((*GL)->hp));
	}
	else {	//若輸入為字元則建立由*GL所指向的單元素結點
		*GL = (struct GNode*)malloc(sizeof(struct GNode));
		(*GL)->tag = ATOM;
		(*GL)->atom = ch;
	}
	scanf("%c", &ch);//此處讀入的字元必為逗號、右括號或分號
	if (*GL == NULL)//若*GL為空,則什麼都不做
		;
	else if (ch == ',')//若輸入逗號則遞迴構造後繼表
		CreateGList(&((*GL)->tp));
	else if ((ch == ')') || (ch == '\n'))//若輸入為右括號或分號則置*GL的後繼指標域為空
		(*GL)->tp = NULL;
}
void PrintGList(struct GNode *GL)
//列印輸出廣義表
{
	if (GL->tag == LIST)	//對於子表,
	{
		printf("(");//則輸出左括號,作為開始符號
		if (GL->hp == NULL)//若子表為空則輸出‘#’字元
			printf("#");
		else//若子表非空,則遞迴輸出子表
			PrintGList(GL->hp);
		printf(")");//當一個子表輸出結束後,應輸出一個右括號終止符
	}
	else//對於原子元素結點,則輸出該結點的值
		printf("%c", GL->atom);
	if (GL->tp != NULL)//輸出結點的後繼子表
	{
		printf(",");//先輸出逗號分隔符
		PrintGList(GL->tp);//再遞迴輸出後繼子表
	}
}
int SearchGList(struct GNode *GL, AtomType e)
//查詢等於原子元素結點,查詢成功則返回1,否則返回0
{
	while (GL != NULL)
	{
		if (GL->tag == LIST)//存在子表,則遞迴搜尋本層該子表
		{
			if (SearchGList(GL->hp, e))
				return 1;
		}
		else//存在原子元素結點,則查詢是否存在值e ,若存在則返回1
		{
			if (GL->atom == e)
				return 1;
		}
		GL = GL->tp;//使GL指向同一層的下一個結點
	}
	return 0;//搜尋不到值e ,則返回0
}

結果: