avatar

数据结构C语言实现8.广义表

引言

数组是一个数据元素的集合,元素之间具有线性关系,但是,元素可以参与多个线性关系(前面讲的都是参与一个);
广义表是一个数据元素的集合,元素之间具有线性关系,但其前驱后继可以是一般元素,也可以是一个表。即广义表中放松对表元素的原子限制,容许它们具有其自身结构。
也可以说广义表(Lists,又称列表)是一种非线性的数据结构,是线性表的一种推广。但如果广义表的每个元素都是原子,它就变成了线性表。

一、广义表的定义

广义表一般记作 LS = (a1, a2, ···, an),

  1. n是广义表的_ 长度 _。ai可以是单个元素(原子),也可以是广义表(子表),
  2. LS是广义表的名字,通常广义表的_ 名字 _ 用大写字母表示。_ 单元素_一般用小写字母表示.
  3. 当广义表非空时,称第一个元素a1为LS的 _ 表头 ,称其余元素组成的表为LS的 表尾 _。注意:表头是元素(可以是原子,也可以是广表),表尾一定是广义表。
    例:
    ((a),a)的表头是(a),表尾是(a),
    ((a))的表头是(a),表尾是( )。
  4. _ 深度 _:简单说就是表的嵌套层次,定义为:
1
2
3
4
5
LS = ( dl , d2 ,... ,dn )
depth ( LS ) =max{depth(dl), depth(d2),... ,depth(dn) } + l
0 di 是单元素
depth ( di ) = {
l di 是空表

5.举例说明:(长度、单元素、子表、表头、深度)
A = ( ) ; A空表,表长为0,深度1;
B = (e) ; B中只有一个元素e,表长为1,表头:e ,表尾 ( ),深度1;
C = (a,(b,c,d)); C的表长为2,两个元素分别为 a 和子表,表头:a, 表尾 ((b,c,d)),深度2;
D = (A,B,C) ; D 的表长为3,它的三个元素 A,B,C 广义表;表头:A 表尾 (B,C),深度3;
depth(D)=max{1,1,2}+1
E=(a, E); E是一个递归的表。
F=(( ),(e),(a,(b,c,d))); F是多层次的广义表,长度为3,深度为3。
广义表图示
广义表图示

二、广义表的数据结构定义

  • gen_list.h
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #ifndef _GEN_LIST_H_
    #define _GEN_LIST_H

    #define MATCH (0)
    #define NOT_MATCH (1)

    #include "tools.h"

    typedef enum
    {
    HEAD = 0, //子表类型(头结点)
    INT, //整型类型
    CHARACTER,//字符类型
    LIST //子表类型
    }Node_type;

    //
    typedef struct Gen_node
    {

    //1.标志(类型) int, char, list, head
    Node_type n_type;
    //2.实际存储的值
    union {
    int int_value;
    char char_value;
    int head_flag;
    struct Gen_node *head;
    }value;
    //3.next指针
    struct Gen_node *next;
    }Gen_node;

    typedef struct Gen_node *Gen_list;

    //接口:
    //1.广义表的创建
    Gen_list init_genlist(char *input_str);
    //2.广义表的销毁
    void destroy_genlist(Gen_list *gen_list);
    //3.广义表元素个数
    int get_genlist_count(Gen_list gen_list);
    //4.广义表深度
    int get_genlist_depth(Gen_list gen_list);
    //5.广义表的拷贝
    Gen_list copy_genlist(Gen_list gen_list);
    //6.显示广义表信息
    void show_genlist(Gen_list gen_list);

    #endif

三、广义表的接口实现

  • gen_list.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
#include <stdio.h>
#include <strings.h>
#include <ctype.h>

#include "gen_list.h"
#include "tools.h"

//非使用者接口操作函数声明

Boolean is_input_empty(char *string); // 1. 判断输入串为空
Boolean is_braket_match(char *string); // 2. 检测括号是否匹配

char *delete_blank(char *string); // 3. 删除字符串中的空格
void delete_braket(char *src_str, char *des_str, int strlen); // 4. 删除字符串两边的括号
void get_item(char *sub_str, char *item_str); // 5. 获取当前条目

Gen_node *create_node(void); // 6. 创建空节点
Gen_node *create_head_node(int head_flag); // 7. 创建头节点
Gen_node *create_int_node(int head_flag); // 8. 创建int型节点
Gen_node *create_char_node(const char character); // 9. 创建字符节点
Gen_node *create_list_node(Gen_node *p_list); //10. 创建子表节点
Gen_list create_genlist(char *string); //11. 通过字符串构造广义表


void show_genlist_value(Gen_list gen_list); //12. 显示广义表

//非使用者接口函数实现

// 1. 判断输入串为空
Boolean is_input_empty(char *string)
{
return strlen(string) == ZERO || strcmp(string, "()") == ZERO;
}

// 2. 检测括号是否匹配
Boolean is_braket_match(char *string)
{
int flag = MATCH;
int i = 1;

if(string[0] != '(')
{
return NOT_MATCH;
}
flag ++;

while(string[i] != '\0')
{
if(string[i] == '(')
{
flag ++;
}
else if(string[i] == ')')
{
flag --;
}
if(flag == MATCH && string[i+1] != '\0')
{
return NOT_MATCH;
}
i ++;
}

return flag == MATCH ? MATCH : NOT_MATCH ;
}

// 3. 删除字符串中的空格
char *delete_blank(char *string)
{
int i = 0;
int j = 0;

if(string == NULL)
{
return string;
}
while(string[j] = string[i])
{
if(isblank(string[i]))
{
i++;
continue;
}
i++;
j++;
}
return string;
}


// 4. 删除字符串两边的括号
void delete_braket(char *src_str, char *des_str, int strlen)
{
strncpy(des_str, src_str + 1, strlen -2 );
des_str[strlen -2 ] = '\0';
}

// 5. 获取当前条目
void get_item(char *sub_str, char *item_str)
{
int i = 0;
int flag = 0;
int sub_len = strlen(sub_str);

while(i < sub_len)
{
if(sub_str[i] == '(')
{
flag++;
}
if(sub_str[i] == ')')
{
flag--;
}
if(flag == 0 && sub_str[i] == ',')
{
break;
}
i ++;
}

if(i == sub_len) //只有一个元素
{
strcpy(item_str, sub_str);
sub_str[0]= '\0';
}
else //把当前元素复制给item_str, 并在原列表删除所复制的元素
{
strncpy(item_str, sub_str, i);
item_str[i] = '\0';
strcpy(sub_str, sub_str + i +1);
}
}


// 6. 创建空节点
Gen_node *create_node(void)
{
Gen_node *result = (Gen_node *)Malloc(sizeof(Gen_node));
bzero(result, sizeof(Gen_node));

return result;
}

// 7. 创建头节点
Gen_node *create_head_node(int head_flag)
{
Gen_node *node = create_node();
node->n_type = HEAD;
node->value.head_flag = head_flag;

return node;
}

// 8. 创建int型节点
Gen_node *create_int_node(int int_value)
{
Gen_node *node = create_node();
node->n_type = INT;
node->value.int_value = int_value;

return node;
}
// 9. 创建字符节点
Gen_node *create_char_node(const char character)
{
Gen_node *node = create_node();
node->n_type = CHARACTER;
node->value.char_value = character;

return node;
}
//10. 创建子表节点
Gen_node *create_list_node(Gen_node *p_list)
{
Gen_node *node = create_node();
node->n_type = LIST;
node->value.head = p_list;

return node;
}

//11. 通过字符串构造广义表
Gen_list create_genlist(char *string)
{
char *sub_str = NULL;
char *item_str = NULL;
int str_len = strlen(string);
Gen_node *p_node = NULL;

if(is_input_empty(string) == TRUE)
{
fprintf(stderr, "input illegal!\n");
return NULL;
}

Gen_list start = create_head_node(1);
p_node = start;

sub_str = (char *)Malloc(sizeof(char) * str_len);
item_str = (char *)Malloc(sizeof(char) * str_len);

//1.去掉外层括号
delete_braket(string, sub_str, str_len);
//2.通过逗号分割广义表元素
while(strlen(sub_str))
{
get_item(sub_str, item_str);
//3.根据元素类型构造节点(遇到子表递归调用)
if(item_str[0] != '(' && item_str[0] != '\'')
{
p_node->next = create_int_node(atoi(item_str));
}
else if(item_str[0] != '(' && item_str[0] == '\'')
{
p_node->next = create_char_node(item_str[1]);
}
else
{
p_node->next = create_list_node(create_genlist(item_str));
}
p_node = p_node->next;
}

free(sub_str);
free(item_str);

return start;
}
//12. 显示广义表
void show_genlist_value(Gen_list gen_list)
{
Gen_node *p_node = NULL;

if(gen_list == NULL)
{
// printf("NULL\n");
return ;
}
printf("(");
p_node = gen_list->next;

while(p_node != NULL)
{
if(p_node->n_type == INT)
{
printf("%d", p_node->value.int_value);
}
else if(p_node->n_type == CHARACTER)
{
printf("'%c'", p_node->value.char_value);
}
else
{
show_genlist_value(p_node->value.head);
}
if(p_node->next != NULL)
{
printf(",");
}
p_node = p_node->next;
}
printf(")");
}

//广义表接口实现:
//1.广义表的创建
Gen_list init_genlist(char *input_str)
{
//判断字符串条件
if(input_str == NULL || is_input_empty(input_str) == TRUE
|| is_braket_match(input_str) == NOT_MATCH)
{
return NULL;
}
//删除空格
delete_blank(input_str);
//
//字符串构建广义表
return create_genlist(input_str);
}

//2.广义表的销毁
void destroy_genlist(Gen_list *gen_list)
{
Gen_node *p_node = NULL;
if(gen_list == NULL || *gen_list == NULL)
{
return ;
}

p_node = *gen_list;
while(p_node != NULL)
{
*gen_list = p_node->next;
if(p_node->n_type == LIST)
{
destroy_genlist(&(p_node->value.head));
}
free(p_node);
p_node = *gen_list;
}
}
//3.广义表元素个数
int get_genlist_count(Gen_list gen_list)
{
int count = 0;
Gen_node *p_node = NULL;

if(gen_list == NULL)
{
return -1;
}
p_node = gen_list->next;

while(p_node != NULL)
{
if(p_node->n_type == INT)
{
count ++;
}
else if(p_node->n_type == CHARACTER)
{
count ++;
}
else
{
count += get_genlist_count(p_node->value.head);
}
p_node = p_node->next;
}
return count;
}
//4.广义表深度
int get_genlist_depth(Gen_list gen_list)
{
int count = 0;
Gen_node *p_node = NULL;

if(gen_list == NULL)
{
return -1;
}
p_node = gen_list->next;

while(p_node != NULL)
{
if(p_node->n_type == LIST)
{
count += get_genlist_depth(p_node->value.head);
}
p_node = p_node->next;
}
count++;
return count;
}
//5.广义表的拷贝
Gen_list copy_genlist(Gen_list gen_list)
{
Gen_node *p_node = NULL;
Gen_node *q_node = NULL;
Gen_list new_list = (Gen_list)Malloc(sizeof(gen_list));
bzero(new_list, sizeof(gen_list));

if(gen_list == NULL)
{
printf("NULL\n");
return NULL;
}
p_node = gen_list->next;
q_node = new_list;

while(p_node != NULL)
{
if(p_node->n_type == INT)
{
q_node->next = create_int_node(p_node->value.int_value);
}
else if(p_node->n_type == CHARACTER)
{
q_node->next = create_char_node(p_node->value.char_value);
}
else
{
q_node->next = create_list_node(p_node->value.head);
}
p_node = p_node->next;
q_node = q_node->next;
}
q_node = NULL;

return new_list;
}
//6.显示广义表信息

void show_genlist(Gen_list gen_list)
{
show_genlist_value(gen_list);
printf("\n");
}

四、代码功能测试

目录结构:

1
2
3
4
5
6
7
8
9
.
├── gen_list
├── gen_list.c
├── gen_list.h
├── main.c
├── tools.c
└── tools.h

0 directories, 7 files

测试代码:

  • main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>
#include "gen_list.h"

int main(int argc, char **argv)
{
Gen_list list = NULL;
Gen_list new_list = NULL;

char str[] = "(15, 'c', (20, 'd', (30, 'f')), ('g', 'i'), 60)";

list = init_genlist(str);

show_genlist(list); //显示广义表信息

printf("%d\n",get_genlist_count(list));
printf("%d\n",get_genlist_depth(list));

new_list = copy_genlist(list);
show_genlist(new_list); //显示广义表信息
destroy_genlist(&list); //广义表的销毁
return 0;
}

//(15, 'c', (20, 'd', (30, 'f')), ('g', 'i'), 60)

测试结果:

1
2
3
4
5
6
7
8
9
10
11
root@aemonair:~# cc.sh *.c
Compiling ...
-e CC gen_list.c main.c tools.c -g -lpthread
-e Completed .
-e Sat Jun 25 00:55:16 CST 2016

root@aemonair:~# ./gen_list
(15,'c',(20,'d',(30,'f')),('g','i'),60)
9
4
(15,'c',(20,'d',(30,'f')),('g','i'),60)

总结

至此,我们学习到了一种叫做广义表的数据结构,并且进行了操作接口的实现。
1.广义表是数据元素的有限序列,可以是单个元素,也可以是广义表。
2.一对表头和表尾可唯一确定广义表。
3.我们采用了链式存储结构,而且我们的节点可以是多种类型,或者是广义表节点。

文章作者: Air
文章链接: http://aemonair.github.io/2016/06/25/Data_Structure_08_General_List/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Aemonair