8.数据结构之广义表
2015-12-18 12:50
543 查看
数据结构之广义表
广义表定义
广义表从结构上来说是对链表的一种扩展,也就是说其中的某个节点可能又指向了另外一个链表(这样的节点叫做子表节点),那么对于广义表这种数据类型的设定一定会大量的涉及递归的算法,因为不管是广义表还是二叉树类型,它们从结构上都具有不断递归的过程。如下图所示是广义表的常见结构:
从应用的角度来看,广义表被广泛的应用于人工智能等领域的表处理语言LISP中,在LISP语言中,广义表化i一种最基本的数据结构。下面让我么不展示LISP的程序:
[code] //LISP语言 (defun search-start (open closed) (let ((q (first open)) (seq (rest open))) (cond ((null open) nil) ((find q finish-status :test 'equal) (list seq (cons q closed))) (t (search-start (funcall update-open-lst seq (expand-vertex q rules-set expand-func (cons q closed)) ) (cons q closed))))))
可以看到lisp的代码里充斥着“()”,这些就是广义表中的子表元素,针对一个广义表,我们需要了解其组织结构、元素数量、广义表深度等信息。下节我们将会设计一个广义表,如果有兴趣的同学可以学习下LISP的使用,据说掌握LISP的程序员都是天才。
广义表实现
为了简化问题的规模,我们对于广义表内数据类型设定为以下几种:整型(INT)、字符型(CHARACTER)、头结点(HEAD)和子表类型(LIST)。在枚举类型中对它们进行了定义:[code]//广义表节点类型 typedef enum { HEAD = 0, //子表类型(头结点) INT, //整型类型 CHARACTER, //子符类型 LIST //子表地址 }Node_type;
广义表中的节点内容需要有以下几个:
1.节点类型
2.实际存储的值(不同的类型值不同,可以采用共用体)
3.指向下一个广义表节点的指针
[code]//广义表的节点结构 typedef struct Gen_node{ //1.标志(类型) int char list head Node_type n_type; //2.实际存储的值 int char (Gen_node *) 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;
下面我们就广义表的常见接口进行介绍:
[code]//广义表接口 Gen_list init_genlist(char *input_str) ; //广义表的创建 void destroy_genlist(Gen_list *gen_list) ; //广义表的销毁 int get_genlist_count(Gen_list gen_list); //得到广义表的元素个数 int get_genlist_depth(Gen_list gen_list); //得到广义表的深度 Gen_list copy_genlist(Gen_list gen_list) ; //广义表的拷贝 void show_genlist(Gen_list gen_list) ; //显示广义表信息
上述介绍了广义表的基本操作,下面我们来实现广义表的接口:
[code]//gen_list.c #include "gen_list.h" #include "tools.h" #include <ctype.h> #include <strings.h> #include <stdio.h> static Boolean is_input_empty(const char *string); static Boolean is_braket_match1(const char *string); //括号匹配 static Boolean is_braket_match(const char *string); //括号匹配 static Gen_list create_genlist(char *string); //创建广义表节点 static Gen_node *create_node(void); static Gen_node *create_head_node(int head_flag); static Gen_node *create_int_node(int int_value); static Gen_node *create_char_node(char character); static Gen_node *create_list_node(Gen_node *p_list); //删除空格 static char *delete_blank(char *string); //去掉最外层括号 static void delete_braket(const char *src_str, char *des_str, int src_len); static void get_item(char *sub_str, char *item_str); static void show_genlist_value(Gen_list gen_list); //显示广义表信息 static void get_item(char *sub_str, char *item_str) { //15,'c',(20,'d',(30,'f','i')),(12,32),60 // // ((), 'a', 12) // (12, 'd', 34), 'a', 12 // // 12 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); } } static void delete_braket(const char *src_str, char *des_str, int src_len) { // (asdfasd) // asdfasd\0 strncpy(des_str, src_str + 1, src_len - 2); des_str[src_len - 2] = '\0'; } static char *delete_blank(char *string) { // adsfad a dsd\0 // adsfadadsd\0 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; } static 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; } static 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; } static Gen_node *create_char_node(char character) { Gen_node *node = create_node(); node->n_type = CHARACTER; node->value.char_value = character; return node; } static 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; } static Gen_node *create_node(void) { Gen_node *result = (Gen_node *)Malloc(sizeof(Gen_node)); bzero(result, sizeof(Gen_node)); return result; } static 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; } //(15, 'c', (20, 'd', (30, 'f', 'i')),(12, 32), 60) //15, 'c', (20, 'd', (30, 'f', 'i')),(12, 32), 60 // // ((12, 'c', 'd')) // 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); // printf("%s\n", sub_str); while(strlen(sub_str)){ //2.通过逗号分隔广义表元素 get_item(sub_str, item_str); 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; } //3.根据元素类型构造节点(如果遇到子表要递归调用) // strncpy free(sub_str); free(item_str); return start; } static Boolean is_input_empty(const char *string) { // "()" return strlen(string) == ZERO || strcmp(string, "()") == 0; } static Boolean is_braket_match(const 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; } static Boolean is_braket_match1(const char *string) { int flag = MATCH; int length = strlen(string); int i = 1; if(string[0] != '(' || string[length - 1] != ')'){ return NOT_MATCH; } while(i < length - 1){ if(string[i] == '('){ flag++; }else if(string[i] == ')'){ flag--; } if(flag < MATCH){ return NOT_MATCH; } i++; } return flag == MATCH ? MATCH : NOT_MATCH; } 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); } 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; } } int get_genlist_count(Gen_list gen_list) //得到广义表的元素个数 { int count = 0; Gen_node *p_node = NULL; if(gen_list == NULL){ return 0; } for(p_node = gen_list->next; p_node; p_node = p_node->next){ count++; } return count; } int get_genlist_depth(Gen_list gen_list) //得到广义表的深度 { int max = 0; //记录最高子表的高度 int child_depth = 0; Gen_node *p_node = NULL; if(gen_list == NULL || gen_list->next == NULL){ return max; } //找到当前广义表中子表内深度最深的(max),当前广义表深度等于: max + 1 p_node = gen_list->next; while(p_node != NULL){ if(p_node->n_type == LIST){ //子表类型 child_depth = get_genlist_depth(p_node->value.head); if(max < child_depth){ //当前子表深度大于之前的子表 max = child_depth; } } p_node = p_node->next; } return max + 1; } Gen_list copy_genlist(Gen_list gen_list) //广义表的拷贝 { Gen_list result = NULL; Gen_node *p_node = NULL; Gen_node *q_node = NULL; if(gen_list == NULL || gen_list->next == NULL){ return result; } result = create_head_node(1); p_node = gen_list->next; q_node = result; 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(copy_genlist(p_node->value.head)); } p_node = p_node->next; q_node = q_node->next; } return result; } static void show_genlist_value(Gen_list gen_list) //显示广义表信息 { Gen_node *p_node = NULL; if(gen_list == NULL){ 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(")"); } void show_genlist(Gen_list gen_list) //显示广义表信息 { show_genlist_value(gen_list); printf("\n"); }
在实现了广义表的基本操作后我们需要进行测试:
[code]//main.c测试文件 #include <stdio.h> #include <stdlib.h> #include "gen_list.h" int main(int argc, char **argv) { Gen_list list = NULL; Gen_list list2 = NULL; char str[] = "(15, 'c', (20, 'd', (30, 'f')), ('g', 'i'), 60)"; list = init_genlist(str); show_genlist(list); //显示广义表信息 printf("the count of list:%d\n", get_genlist_count(list)); printf("the depth of list:%d\n", get_genlist_depth(list)); list2 = copy_genlist(list); //广义表的拷贝 show_genlist(list2); //显示广义表信息 destroy_genlist(&list); //广义表的销毁 destroy_genlist(&list2); return 0; } //(15, 'c', (20, 'd', (30, 'f')), ('g', 'i'), 60)
在广义表的实现中需要借助工具类操作,所以和往常一样,我们需要介绍tool.c和tool.h文件。
[code]//tools.h #ifndef _TOOLS_H_ #define _TOOLS_H_ #include <stdio.h> #include <stdlib.h> #include <string.h> #define TRUE (1) #define FALSE (0) #define ZERO (0) typedef unsigned char Boolean; //工具类接口 void *Malloc(size_t size); void swap(void *a, void *b, int length); #endif
[code]//tools.c #include "tools.h" void *Malloc(size_t size) { void *result = malloc(size); if(result == NULL){ fprintf(stderr, "the memory is full!\n"); exit(1); } return result; } void swap(void *a, void *b, int length) { void *temp = Malloc(length); memcpy(temp, a, length); memcpy(a, b, length); memcpy(b, temp, length); free(temp); }
小结:
关于广义表的操作介绍到这里,借助广义表我们了解了递归的过程,为以后学习二叉树打好了基础,另外值的一提的是,LISP真的是一个不错的语言,大家可以尝试尝试。^_^相关文章推荐
- 数据结构实验 第四单元 串操作
- 数据结构实验 第四单元 串操作
- 数据结构实验 第三单元 二进制转换
- 数据结构实验 第三单元 队列操作
- 数据结构实验 第三单元 队列操作
- 数据结构实验 第三单元 二进制转换
- 数据结构实验 第二单元 构造计算器
- 数据结构实验 第二单元 构造计算器
- 数据结构实验 第二单元 汉诺塔(非递归,用栈模拟递归)
- 数据结构实验 第二单元 汉诺塔(非递归,用栈模拟递归)
- 数据结构实验 第二单元 括号匹配
- 数据结构实验 第二单元 括号匹配
- 数据结构实验 第二单元 栈操作
- 数据结构实验 第二单元 栈操作
- 数据结构之插入排序
- <LeetCode OJ> 8. String to Integer (atoi)
- 数据结构实验之查找六:顺序查找
- <LeetCode OJ> 148. Sort List
- 学期末数据结构教程总结
- 数据结构总结