Day Day Up

  • 广义表
  • 引入
  • 定义
  • 元素组成
  • 重要的特性
  • 表名
  • 广义表字符串表示转图形表示
  • 储存结构
  • 空表的结构
  • 两种方法理解递归性
  • 广义表运算
  • 求表长度
  • 求表深度(我感觉这个挺难懂的)
  • 广义表字符串转链式储存(重点)


广义表

引入


广义表是线性表的推广,将线性的表推广到平面。

定义


广义表:是(n≥0)的元素组成的 有限 的序列,当 n=0 时,称为空表。
空表的表示: (#)

元素组成


GL = {a1,a2,a3,a4,a5,a6};
原子:当a1是一个元素时,称为原子,深度为0
子表:当a1是一个广义表时,称为子表,深度为1

重要的特性


  1. 广义表的数据元素既可以原子 也可以是 子表
  2. 广义表的元素是有序的,数据元素是有限的(深度可以是无限的
  3. 广义表的 长度 :最外一层所包含的元素个数
  4. 广义表的 深度 :括号的重数(数一下左括号个数)
  5. 广义表是可以共享的
  6. 广义表可以是递归的,自己可以是自己的子表,此时深度是无限的,长度是有限的
  7. 广义表的拆分:可以分为表头,和表尾,其中表尾是用( )括起来的,所以 表尾一定是一个广义表

表名


名为A的空表:A(#)
无名的空表:· (#) 注意前面的点,表示匿名

广义表字符串表示转图形表示


例:D( A(#) , B(e) , C(a,(b,c,d) ))

  1. D是一个广义表,元素 为表A,表B,表C
  2. 表A为空表,表B的元素为e,表C的元素为a,匿名表
  3. 该匿名表中元素为 b c d

储存结构

lua空表会被处理为nil吗 空表是指_结点

  1. tag:标记结点的类型
  2. union联合域:根据tag做不同的处理
  3. link:指向兄弟结点,或者置NULL

空表的结构

lua空表会被处理为nil吗 空表是指_lua空表会被处理为nil吗_02


空表 不是 ghead == NULL而是 ghead->sublist == NULL

两种方法理解递归性

解决1:对 广义表 的操作是一致的,子表也是一个独立的广义表

void func1(Node * g){
	// param g :  广义表的头结点
	Node * g1 = g->sublist; //指向该表的第一个元素
	while(g1 != NULL){ //判断是否遍历完了这个广义表
		if(g1->tag == 1) func(g1); //处理子表元素,传入的g1为子表的表头
		else {
			//处理原子操作
		}
		g1 = g1->link; // 指向兄弟结点
	}
}

解决2:对 广义表的结点 操作是一致的

void func2(Node * g){
	//param g : 广义表结点
	if(g == NULL) // 递归结束条件
		return;
	if(g->tag == 1)//该结点为子表
		func2(g->sublist); //处理子表的第一个元素结点
	else
		func2(g->link); //处理兄弟结点
}

广义表运算

求表长度


思路:不用深入,横向扫到NULL

int getLength(){
	int ans = 0;
	Node * g1 = ghead->sublist; //获取第一个元素的地址,ghead为广义表的表头结点
	while(g1!=NULL){
		ans++;
		g1 = g1 -> link; //跳转到兄弟结点
	}
	return ans;
}

求表深度(我感觉这个挺难懂的)


注意点:

  1. 空表的深度是 1
  2. 原子的深度是 0
  3. 子表是深度是 1
int getDepth(){
	return getDepth(ghead); //传入的是表头结点
}
// 用于递归调用
int getDepth1(Node * g){
	int max = 0,dep;
	if(g->tag == 0) return 0; //判断头结点为原子
	Node g1 = g->sublist; //已经确定是子表,则指向首元素
	if(g1->link ==NULL) return 1;//子表为空表
	while(g1 != NULL){ // 遍历该非空子表
		if(g1->tag == 1){
			dep = getDepth1(g1); //递归调用子表元素
			if(dep > max) max = dep;//更新最大值
		}
		g1 = g1 -> link; //指向兄弟结点
	}
	return max + 1; // 返回表的深度 + 自身的深度1
}

广义表字符串转链式储存(重点)

从左到右扫字符串

  1. 遇到 #:说明前面的广义表是空表
  2. 遇到 (:说明是一个广义表
  3. 遇到) :最近的一个广义表结束了
  4. 遇到,:添加一个兄弟结点
Node* create1(char* &s){
	Node * g;
	char chr =  * s++; //获取后自增 s++,是指针的自增
	if(chr != '\0'){
		g = new Node;
		if (ch == '('){
			//左括号说明遇到了一个子表
			g -> tag =1;
			g -> sublist = create1(s);
		}
		else if(ch == '#' ) delete g ; g = NULL; //空表
		else{
			// 是一个原子
			g->tag = 0;
			g->data = ch;
		}
	}else  delete g ; g = NULL;//结束遍历
	//以下为处理兄弟的部分
	ch = * s++;//取下一个字符
	if(g!=NULL){
		if(ch == ','){
			g->link = create1(s);
		}else{
			g->link = NULL;
		}
	}
	return g;
}