第17章:高级数据表示
@(学C笔记)[2023-10-30am, C语言]
本章重点:
■ 函数:进一步学习malloc()
■ 使用C表示不同类型的数据
■ 新的算法,从概念上增强开发程序的能力
■ 抽象数据类型(ADT)
简言之,设计一种数据类型:如何储存该数据类型,及一系列管理该数据的函数。
算法:操控数据的方法;
抽象数据类型(ADT):面向问题
而不是面向语言。
1. 研究数据表示
■ 对于不是一种但又密切相关的一组数据,用结构来表示每一项合适。
■ 用动态内存分配来表示数据比较好。
2. 从数组到链表
建立首尾相连的结构:链表。(每个结构中包含指向next结构的指针)。
#define TSIZE 45 /* 储存片名的数组大小 */
struct film {
char title[TSIZE];
int rating;
struct film * next;
};
虽然结构不能含有与本身类型相同的结构,但是可以含有执行同类型结构的指针。这种定义是定义链表
的基础,链表中的每一项都包换着在何处能找到下一项的信息。
3. 抽象数据类型(ADT)
在编程时,应该根据编程问题匹配合适的数据类型,若不是C中与之匹配的基本类型,可设计一种符合程序要求的新数据类型。
什么是类型?类型特指两类信息:属性和操作。好比int类型属性是整数值,对它的操作有加减乘除等。
假设要定义一个新的数据类型:首先,必须提供储存数据的方法。其次,必须提供操控数据的方法。
计算机科学领域已开发了一种定义新类型的好方法,用3个步骤完成从抽象到具体的过程。
- 提供类型属性和相关操作的抽象描述。这些描述既不能依赖特定的实现,也不能依赖特定的编程语言。这种正式的抽象描述被称为抽象数据类型(ADT)。
- 开发一个实现ADT的编程接口。也就是说,指明如何储存数据和执行所需操作的函数。例如在C中,可以提供结构定义和操控该结构的函数原型。这些作用于用户定义类型的函数相当于作用于C基本类型的内置运算符。需要使用该新类型的程序员可以使用这个接口进行编程。
- 编写代码实现接口。这一步至关重要,但是使用该新类型的程序员无需了解具体的实现细节。
3.1 建立抽象
以电影项目为例:抽象类型叫链表
(非正式但抽象的链表定义是:链表是一个能储存一系列项且可以对其进行所需操作的数据对象)。
简化链表的抽象数据类型(ADT):
类型名: 简单链表
类型属性: 可以储存一系列项
类型操作:
初始化链表为空
确定链表为空
确定链表已满
确定链表中的项数
在链表末尾添加项
遍历链表,处理链表中的项
清空链表
3.2 建立接口
程序清单 17.3 list.h接口头文件
/* list.h -- 简单链表类型的头文件 */
#ifndef LIST_H
#define LIST_H
#include <stdbool.h> /* C99特性 */
/* 特定程序的声明 */
#define TSIZE 45 /* 储存电影名的数组大小 */
struct film
{
char title[TSIZE];
int rating;
};
/* 一般类型定义 */
typedef struct film Item;
typedef struct node
{
Item item;
struct node * next;
} Node;
typedef Node * List;
/* 函数原型 */
/* 操作: 初始化一个链表 */
/* 前提条件: plist指向一个链 */
/* 后置条件: 链表初始化为空 */
void InitializeList(List * plist);
/* 操作: 确定链表是否文空定义,plist指向一个已初始化的链表 */
/* 后置条件: 如果链表为空,该函数返回图热,否则返回false */
bool ListIsEmpty(const List *plist);
#endif
3.3 使用接口
目标:使用这个接口编写程序,但是不必知道具体的实现细节。
例程伪代码方案:
创建一个list类型的变量。
创建一个Item类型的变量。
初始化链表为空。
当链表未满且有输入时:把输入读取到Item类型变量中。
在链表末尾添加项。
访问链表中的每个项并显示它们。
程序清单17.4 films3.C程序
/* films3.c -- 使用抽象数据类型(ADT)风格的链表 */
/* 与list.c一起编译 */
#include <stdio.h>
#include <stdlib.h> /* 提供exit()的原型 */
#include "list.h" /* 定义List、Item */
void showmovies(Item item);
char * s_gets(char * st, int n);
int main(void
{
List movies;
Item temp;
/* 初始化 */
InitializeList(&movies);
if (ListIsFull(&movies))
{
fprintf(stderr, "No memory available! Bye!\n");
exit(1);
}
/* 获取用户输入并储存 */
puts("Enter first movie title:");
while (s_gets(temp.title, TSIZE) != NULL && temp.title[0] != '\0')
{
puts("Enter your rating <0-10>:";
scanf("%d", &temp.rating);
while (getchar() != '\n')
continue;
if (AddItem(temp, &movies) == false)
{
fprintf(stderr, "Problem allocating memory\n");
break;
}
if (ListIsFull(&movies))
{
puts("The list is now full.");
break;
}
puts("Enter next movie title (empty line to stop):");
}
/* 显示 */
if (ListIsEmpty(&movies))
printf("No data enterend.");
else
{
printf("Here is the movie list:\n");
Traverse(&movies, showmovies);
}
printf("You entered %d movies.\n", ListItemCount(&movies));
/* 清理 */
EmptyTheList(&movies);
printf("Bye!\n");
return 0;
}