• 广义表的学习


    一、广义表的定义

    • 先举例说明:中国举办的国际足球邀请赛,参赛队名单表示如下:
    • (阿根廷,巴西,德国,法国,(),西班牙,意大利,英国,(国家队,山东鲁能,广州恒大))这个表中,叙利亚队应排在法国队后面,但未能参加,成为空表。国家队,山东鲁能,广州恒大均作为东道主的参赛队参加,构成一个小的线性表,成为原线性表的一个数据元素。这种扩宽了的线性表就是广义表。
    • 广义表(又称列表Lists)是n>=0个元素a0,a1,....an-1的有限序列,其中每一个aj或者是原子,或者是一个广义表。 
    • 广义表通常记作:LS=(a1,a2,...an)其中:LS为表名,n为表的长度,每一个ai为表的元素。
    • 习惯上,一般用大写字母表示广义表,小写字母表示原子。
    • 表头:若LS非空(n>=1)则其第一个元素a1就是表头。记作head(LS)=a1。注:表头可以是原子,也可以是子表。
    • 表尾:除了表头之外的其它元素组成的表。记作tail(LS)=(a2,....an)。注:表尾不是最后一个元素,而是一个子表
    1. 例:
    2. 1)A=( ) 空表,长度为0
    3. 2)B=(( )) 有一个元素(该元素为空表),所以长度为1。表头,表尾均为()
    4. 3)C=(a,(b,c)) 长度为2,由原子a和子表(b,c)构成。表头为a,表尾为((b,c))
    5. 注意:(b,c)加括号((b,c))表示的是表尾是一个广义表,广义表里有一个元素是(b,c)
    6. 如果不加括号,(b,c)表示的是表尾是一个广义表,广义表里面有b,c两个元素
    7. 4)D=(x,y,z) 长度为3,每一项都是原子。表头是x,表尾为(y,z)
    8. 5)E=(C,D) 长度为2,每一项都是子表。表头为C,表尾为(D)
    9. 6)F=(a,F) 长度为2,每一项为原子,第二项为它本身。表头为a,表尾为(F)。
    10. 实际上,F=(a,(a,(a,..)))

    二、广义表的性质

    1. 广义表中的数据元素由相对次序;一个直接前驱和一个直接后继。
    2. 广义表的长度定义为最外层所包含元素的个数;如,C=(a,(b,c))是长度为2的广义表。
    3.  广义表的深度定义为该广义表展开后所含括号的重数;
      例如:A=(b,c)的深度为1----只有1层括号
      B=(A,d)的深度为2----因为B=((b,c),d),有2层括号
      C=(f,B,h)的深度为3----因为C=(f,((b,c),d),h),有3层括号
      注意:“原子”的深度为0,“空表的深度为1”
    4. 广义表可以为其他广义表共享;如:广义表B就共享表A。在B中不必列出A的值,而是通过名称来引用,B=(A)
    5. 广义表可以是一个递归的表。如:F=(a,F=(a,(a,(a,..))))注意:递归的深度是无穷值,长度是有限值。
    6. 广义表是多层次结构,广义表的元素可以是单元素,也可以是子表,而子表的元素还可以是子表,..。例如:D=(E,F) 其中:E=(a,(b,c)),F=(d,(e)) 
    7. 广义表和线性表的区别:
      广义表可以看成是线性表的推广,线性表是广义表的特例。

    三、广义表的2种常见的存储结构 

    • 广义表中的数据元素可以具有不同的结构(原子或广义表),难以用顺序存储结构表示,通常采用链式存储,将广义表分解为表头和表尾,对表头和表尾再次分解,直到分解到空的广义表或是一个具体的原子,分解结束。 

     头尾表示法:

    • 分解后的表头和表尾各用一个结点表示,显然表头可能为原子或列表(表尾肯定是列表),所以需要两种结构的节点:一种是表结点,一种是原子结点。其中变量tag用来区分表结点和原子结点。
    • 表结点:包括标志域(tag),指向表头的指针域(hp),指向表尾的指针域(tp)
    • 原子结点:包括标志域(tag),值域(atom)  

     

     存储结构类型:

    1. typedef int AtomType;
    2. typedef enum
    3. {
    4. ATOM,LIST
    5. }ELemTag;//ATOM=0原子结点,LIST=1子表
    6. typedef struct GLNode
    7. {
    8. AtomType tag;//区分原子结点和表结点的类型参数
    9. union
    10. {
    11. AtomType atom;//原子结点的值域
    12. struct
    13. {
    14. struct GLNode* hp,* tp;
    15. }htp;
    16. }atom_htp;//atom_ptr是原子结点的值域atom,表结点的表头指针hp,表尾指针tp的联合体域
    17. }GLNode,*GList;

     

    1. bool Init(GList &L)//初始化,建立一个空的广义表
    2. {
    3. L = NULL;
    4. return true;
    5. }
    6. bool CreatGList(GList &L,SString S,char*a)//建立广义表
    7. {
    8. L = (GList)malloc(sizeof(GList));//建立表结点
    9. if (StrLen(S) == 1)
    10. {
    11. L->tag = ATOM;
    12. (L->atom_htp).atom = a[1];//S为单原子,创建单原子广义表
    13. }
    14. else
    15. {
    16. SString sub
    17. L->tag = LIST;
    18. GLNode* p = L;
    19. SubString(S, sub, 2, StrLen(S)-2);//
    20. }
    21. }
    22. GList Head(GList L)//求广义表的表头
    23. {
    24. if (L == NULL)//空表无表头
    25. {
    26. return NULL;
    27. }
    28. if (L->tag == ATOM)//如果是原子结点则不是表
    29. {
    30. exit(0);
    31. }
    32. else
    33. {
    34. return L->atom_htp.htp.hp;
    35. }
    36. }
    37. GList Tail(GList L)//求广义表的表尾
    38. {
    39. if (L == NULL)
    40. {
    41. return NULL;
    42. }
    43. if (L->tag == ATOM)
    44. {
    45. exit(0);
    46. }
    47. else
    48. {
    49. return L->atom_htp.htp.tp;
    50. }
    51. }
    52. int Length(GList L)//求广义表的长度
    53. {
    54. if (L == NULL)
    55. {
    56. return 0;
    57. }
    58. if (L->tag == ATOM)
    59. {
    60. exit(0);
    61. }
    62. GList p = L;
    63. int count = 0;
    64. while (p != NULL)
    65. {
    66. count++;
    67. p = p->atom_htp.htp.hp;//寻找下一个表结点
    68. }
    69. }
    70. int Depth(GList L)//求广义表的深度
    71. {
    72. if (L == NULL)
    73. {
    74. return 1;//空表深度为1
    75. }
    76. if (L->tag == ATOM)
    77. {
    78. return 0;//原子结点的深度为0
    79. }
    80. GLNode* p = L;
    81. int d, max;
    82. while (p != NULL)
    83. {
    84. p = p->atom_htp.htp.hp;//进入下一个表结点
    85. d = Depth(p);//寻找下一个表结点的深度
    86. if (d > max)
    87. {
    88. max = d;
    89. }
    90. p = p->atom_htp.htp.hp;//继续寻找下下一个表节点
    91. }
    92. return max + 1;
    93. }
    94. int CountAtom(GList L)//统计广义表中原子结点的数目
    95. {
    96. int n1 = 0, n2 = 0;//分别计算表头,表尾中原子数目个数
    97. if (L == NULL)
    98. {
    99. return 0;
    100. }
    101. if (L->tag == ATOM)
    102. {
    103. return 1;
    104. }
    105. n1 = CountAtom(L->atom_htp.htp.hp);
    106. n2 = CountAtom(L->atom_htp.htp.tp);
    107. return (n1 + n2);
    108. }

    四、关于广义表的取“表头”“表尾”

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. typedef struct {
    8. char* ch; // 先存放非空串的首地址,不分配内存
    9. int Length; // 存放串的当前长度
    10. }SString;
    11. bool StrInit(SString& S);//初始化
    12. bool StrAssign(SString& S, char* chars);//一个字符串常量赋值给顺序串S
    13. bool StrCopy(SString& S, SString T);//将T串拷贝给S串
    14. bool SubString(SString S, SString& T, int pos, int len);//取子串,此处pos代表元素下标
    15. int StrLen(SString S);//求串长
    16. bool Print(SString S);//打印
    17. bool sever(SString &sub, SString& head);//从串T中分离出头串head
    18. //将非空串T分割成两部分:head为第一个','之前的子串,T为之后的子串
    19. bool StrInit(SString& S)//初始化
    20. {
    21. S.ch = NULL;
    22. S.Length = 0;
    23. return true;
    24. }
    25. bool StrAssign(SString& S, char* chars)//一个字符串常量赋值给顺序串S
    26. {
    27. int i, j;
    28. char* c;
    29. for (i = 0, c = chars; *c; i++, c++);//计算一个字符串常量的长度
    30. if (i == 0)//说明字符串常量是0,就不用给SString开辟空间
    31. return false;
    32. else
    33. {
    34. S.ch = (char*)malloc(i * sizeof(char));//申请空间
    35. if (S.ch == NULL)
    36. {
    37. exit(0);
    38. }
    39. for (j = 0; j < i; j++)
    40. {
    41. S.ch[j] = chars[j];
    42. S.Length = i;
    43. }
    44. }
    45. return true;
    46. }
    47. bool StrCopy(SString& S, SString T)//将T串拷贝给S串
    48. {
    49. if (S.ch != NULL)//先释放掉原来的空间
    50. {
    51. S.ch = NULL;
    52. free(S.ch);//注意此处虽然free函数进行了动态内存的释放和回收,但实际中未完全释放,S.ch依然会指向
    53. //动态开辟的空间,而非指向NULL。当第一次使用完空间,如果未退出继续运行代码,再次赋值就会发生错误,
    54. //只需在free函数前把S.ch进行赋值NULL操作即可
    55. }
    56. if (S.Length != 0)
    57. {
    58. StrInit(S);
    59. }
    60. for (int i = 0; i < T.Length; i++)
    61. {
    62. S.ch = (char*)malloc(T.Length * sizeof(char));
    63. if (S.ch == NULL)
    64. return false;
    65. S.ch[i] = T.ch[i];
    66. S.Length = T.Length;
    67. }
    68. return true;
    69. }
    70. bool SubString(SString S, SString& T, int pos, int len)//取子串,此处pos代表元素下标
    71. {
    72. if (pos<0 || pos>S.Length - 1 || len<0 || len>S.Length - pos)
    73. return false;
    74. else
    75. {
    76. if (T.ch != NULL)
    77. {
    78. T.ch = NULL;
    79. free(T.ch);
    80. }
    81. if (T.Length != 0)
    82. StrInit(T);
    83. int i;
    84. T.ch = (char*)malloc(len * sizeof(char));
    85. if (T.ch == NULL)
    86. return false;
    87. for (i = 0; i < len; i++)
    88. {
    89. T.ch[i] = S.ch[pos + i];
    90. T.Length = len;
    91. }
    92. return true;
    93. }
    94. return true;
    95. }
    96. int StrLen(SString S)//求串长
    97. {
    98. return S.Length;
    99. }
    100. bool Print(SString S)//打印
    101. {
    102. for (int i = 0; i < S.Length; i++)
    103. {
    104. cout << S.ch[i];
    105. }
    106. cout << endl;
    107. return true;
    108. }
    109. bool sever(SString &sub, SString& head)//从T串中分离出头串head
    110. //注意sever处理的是已经除去最外层括号的串
    111. {
    112. int n = StrLen(sub);
    113. int i = 0, k=0 ;//k记尚未配对的左括号个数
    114. for(i=0;i
    115. {
    116. char ch = sub.ch[i];
    117. if (ch == '(')
    118. {
    119. k++;
    120. }
    121. else if (ch == ')')
    122. {
    123. k--;
    124. }
    125. if(ch==','&&k==0)
    126. {
    127. break;
    128. }
    129. } //找到第一个','之前的子串的的条件的出现1个左括号
    130. //和第一个','
    131. if (i < n)
    132. {
    133. SubString(sub, head, 0, i);
    134. SubString(sub, sub, i + 1, n - (i+1));
    135. }
    136. else//串中只有一个字符(单原子)的时候
    137. {
    138. StrCopy(head, sub);
    139. free(sub.ch);
    140. StrInit(sub);
    141. sub.ch = (char*)malloc(50 * sizeof(char));
    142. }
    143. return true;
    144. }
    145. int main()
    146. {
    147. SString S1;
    148. StrInit(S1);
    149. S1.ch = (char*)malloc(50 * sizeof(char));
    150. char a[] = "(a,(b,d,e,f))";
    151. StrAssign(S1, a);//一个字符串常量赋值给顺序串S1
    152. cout << StrLen(S1) << endl;
    153. SString head;//用于保留分割后的表头
    154. StrInit(head);
    155. head.ch = (char*)malloc(100 * sizeof(char));
    156. SubString(S1, S1, 1, StrLen(S1) - 2);//除去串的最外层括号
    157. sever(S1, head);
    158. cout << "第一个逗号之前的元素(除了第一个左括号)" << endl;;
    159. Print(head);
    160. cout << "第一个逗号之后的元素(除了最后一个右括号)" << endl;
    161. Print(S1);
    162. return 0;
    163. }

     

     

  • 相关阅读:
    Spring Boot中Jack相关问题(精度丢失/日期格式化/忽略null值)
    网络安全(黑客)自学
    Waves 14混音特效插件合集mac/win
    redis常识
    变分(Calculus of variations)的概念及运算规则(二)
    小白终于解决了在学习Go中不知道Makefile是什么的难题
    SystemVerilog Assertions应用指南 Chapter1.34 :SVA中的多时钟定义
    (转)富文本编辑器——Vue2Editor
    KylinV10系统如何查找JDK路径和安装JDK
    8.3:加强堆的应用
  • 原文地址:https://blog.csdn.net/m0_63783532/article/details/127737791