广义表之表头表尾表示法
本文最后更新于196 天前,其中的信息可能已经过时,如有错误请发送邮件到1910452164@qq.com

题目要求如下:

记录一下此次学习过程:

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct GNode
{
	int Tag; // 0表示原子,1表示列表
	union
	{
		char atom; // 原子值
		struct // 指针域
		{
			struct GNode* hp, * tp; // hp连接当前表的子表,tp连接下一个子表
		}ptr;
	};
}*General_List, GNode;

void SubString(char sub[], char str[], int start, int len) // 将str中部分内容赋值给sub串
{
	int i = 0;
	for (; i < len; ++i)
		sub[i] = str[start + i - 1];
	sub[i] = '\0'; // 结尾补串结束符
}

void SeperateList(char* head, char* tail) // 将表tail分离成表头和表尾
{
	int i = 0, cnt = 0, len = strlen(tail);
	for (; i < len; ++i)
	{
		if (tail[i] == '(') cnt++;
		if (tail[i] == ')') cnt--;
		if (!cnt && tail[i] == ',') break; // 找到表头和表尾的分界点
	}
	if (i < len) // 存在表尾
	{
		SubString(head, tail, 1, i); // 分离出表头,赋值给head
		SubString(tail, tail, i + 2, len - i - 1); // 将自己更新为表尾
	}
	else // 不存在表尾
	{
		SubString(head, tail, 1, len); // 全部更新为表头
		tail[0] = 0;
	}
}

void Create_General_List(General_List* L, char* str)
{
	if (str == NULL) (*L) = NULL; // 传入了空字符串
	else
	{
		(*L) = (General_List)malloc(sizeof(GNode));
		if (strlen(str) == 1) // 传入字符,只能创建原子节点
		{
			(*L)->Tag = 0;
			(*L)->atom = *str;
		}
		else // 传入字符串,创建list节点
		{
			char head[100] = { '\0' };
			SubString(str, str, 2, strlen(str) - 2); // 去除str最外层括号
			General_List q, p = (*L);
			p->Tag = 1;
			do
			{
				SeperateList(head, str); // head变成表头,str变成表尾
				Create_General_List(&(p->ptr.hp), head); // 递归创建表头
				if ((*str)!=0) // 表尾非空,则下次循环继续将表尾分割成表头和表尾
				{
					q = p;
					p = (General_List)malloc(sizeof(GNode));
					p->Tag = 1;
					q->ptr.tp = p; // 在当前节点后连接子尾表
				}
			} while ((*str) != 0);
			p->ptr.tp = NULL;
		}
	}
}

int Get_List_Deepth(General_List L) // 计算表深度
{
	if (!L) return 1; // 空表深度为1
	if (L->Tag == 0) return 0; // 原子不算入深度
	int max = 0, dep;
	for (General_List t = L; t != NULL; t = t->ptr.tp) // 每次循环让t指针指向下一个尾子表
	{
		dep = Get_List_Deepth(t->ptr.hp); // 递归计算头子表深度
		max = max < dep ? dep : max; // 更新深度
	}
	return max + 1;
}

void Clear_List(General_List* L) // 为了删除表首节点,需传入GNode的二级指针
{
	if (!(*L)) return; // L是空节点
	if (!((*L)->Tag)) // 是原子节点
	{
		free((*L));
		(*L) = NULL;
		return;
	}
	Clear_List(&((*L)->ptr.hp)); // 递归删除头子表
	Clear_List(&((*L)->ptr.tp)); // 递归删除尾子表
	free(*L); // 删除自身
	*L = NULL;
}
int main()
{
	General_List L;
	char buffer[100];
	int num;
	printf("请输入广义表个数:");
	scanf("%d", &num);
	for (int i = 1; i <= num; ++i)
	{
		printf("请输入广义表:");
		scanf("%s", buffer);
		Create_General_List(&L, buffer);
		printf("第%d个广义表的深度为:%d\n", i, Get_List_Deepth(L));
		Clear_List(&L);
		if (!L) printf("该广义表内存已释放\n\n");
		else
		{
			printf("内存释放出错,已退出\n\n");
		}
	}
	return 0;
}
// ((a,b,(c,(d,e),f)),g)
// (a,(b,(c,(d,(e,(f),(g))))))
// (a)
// ((((((a),b),c),d),e),f)

分析:

对于题目所要求的算法Get_List_Deepth来说,首先判断当前广义表是否为空表,若为空表,则记其深度为1;其次判断当前广义表节点是否为原子,原子不计入深度。判断完特殊情况后,开始对传入节点进行循环,在每一轮循环中,首先对其头子表进行递归,计算以其为起点的子表深度,然后更新当前深度的最大值,循环结束后转向当前表的尾子表,开始下一轮循环。此循环结束后就可以得到当前表的子表的深度,最后将其+1并返回即可。

你在干嘛?等待戈多。
戈多是谁?我不知道。
你在干嘛?等待戈多。
戈多是谁?我不知道。

我在干嘛?等待戈多。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇