抽象数据类型(ADT)

   类型是由什么组成?一个类型(type)指定两类信息:一个属性集和一个操作集。

所以您想定义一个新的数据类型。首先,您需要提供存储数据的方式,可能是通过设计一个结构。第二个,需要提供操作数据的方式。

计算机科学已经研究出一种定义新类型的成功方法。这种方法使用3个步骤来完成从抽象到具体的过程:

  1. 为类型的属性和可对类型执行的操作提供一个抽象的描述。这个描述不应受任何特定实现的约束,甚至不应受到任何特定编程语言的约束。这样一种正式的抽象描述被称为抽象数据类型(ADT)
  2. 开发一个实现该ADT的编程接口(即函数集合)。即说明如何存储数据并描述用于执行所需操作的函数集合。比如,在C中,您可能同时提供一个结构的定义和用来操作该结构 的函数的原型。
  3. 编写代码来实现这个接口。这一步至关重要,但是使用这种新类型的程序员无须了解实现的细节。

以抽象数据类型——列表为例进行说明

类型名称: 列表
类型属性: 可保存一个项目序列
类型操作: 把列表初始化为空列表
  确定列表是否为空
  确定列表是否已满
  确定列表中项目的个数
  向列表末尾添加项目
  遍历列表,处理列表中每个项目
  清空列表
  在列表中的任何位置插入一个项目
  从列表中删除一个项目
  取出列表中的一个项目(不改变列表)
  替换列表中的一个项目
  在列表中搜索一个项目

非正式但抽象的列表定义时:它是一个能够保存项目序列并且可以对其应用任何前面的操作的数据对象。这个定义没有说明什么样的项目才能存储在列表中。它并未指定是否应该使用数组或链接的结构集或其他数据形式来保存这些项目。它并未指定使用何种方法来实现诸如获取列表中的元素个数之类的操作。这些都是留给实现的细节。

构造C语言接口

简单列表的接口有两个部分:①描述数据如何表示,②描述实现ADT操作的函数。接口的设计应和ADT的描述尽可能密切地保持一致。因此,应该使用某种通用的Item类型来进行表达,而不是用诸如int或struct film之类的专用类型。这样做的方法之一是使用C的typedef工具将Item定义为所需类型。如:

#define TSIZE 45  /* 存放片名的数组大小 */
struct film {
char title[TSIZE];
int rating;
};
typedef struct film Item;

在链表的实现中,每一个链接被称为一个节点(node)。每一个节点包含形成列表内容的信息和指向下一节点的指针。例如:

typedef struct node {
Item item;
struct node * next; // 指向下一节点的指针
} Node;
typedef Node * List;

↓ 等价于

struct node {
Item item;
struct node * next;
};
typedef struct node Node;
typedef Node * List; // 为了管理链表,需要一个指向其开始处的指针

还可以加入一个变量来保存列表中项目的数量:

typedef struct list {
Node * head; // 指向列表头的指针
int size; // 列表中项目的数量
} List;

考虑如下声明:

List movies;

movies是在建立一个列表,而不是在建立一个指向节点的指针或是建立一个结构。movies的确切数据表示是应该在接口层上不可见的实现细节上。

启动后,程序应该把头指针初始化为NULL。任何使用List类型的人都应无须担心细节,而应能够使用下面的代码:

InitializeList(movies);

程序员只需要知道他们应该使用InitializeList()函数来初始化列表,不需要知道List变量的确切的数据实现。这是数据隐藏的一个例子。数据隐藏是一种对跟高级编程隐藏数据表示细节的艺术。InitializeList()的函数原型为:

/* 操作: 初始化一个列表  */
/* 操作前:plist指向一个列表 */
/* 操作后:该列表被初始化为空列表 */
void InitializeList(List * plist);

C语言把所有的类型和函数信息集成到一个包中的方法是:将类型定义和函数原型(包括“操作前”和“操作后”注释)放入一个头文件中。这个文件将提供程序员使用该类型所需的全部信息。

单链表的实现与分析(以C Primer Plus(第5版) 第17章 高级数据表示——程序清单17.4为例)

抽象数据类型的头文件(list.h):定义数据结构并为用户接口提供原型

/* 简单列表类型的头文件 */
#ifndef LIST_H_
#define LIST_H_
#include <stdbool.h>
/* 特定于程序的声明 */
#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; // 指向Node(struct node)类型的指针 /* 函数原型 */
/* 操作:初始化一个列表 */
/* 操作前:plist指向一个列表 */
/* 操作后:该列表被初始化为空列表 */
void InitializeList(List * plist); /* 操作:确定列表是否为空列表 */
/* 操作前:plist指向一个已初始化的列表 */
/* 操作后:如果该列表为空则返回true:否则返回true */
bool ListIsEmpty(const List plist); /* 操作:确定列表是否已满 */
/* 操作前:plist指向一个已初始化的列表 */
/* 操作后:如果该列表已满则返回true:否则返回true */
bool ListIsFull(const List * plist); /* 操作:确定列表中项目的个数 */
/* 操作前:plist指向一个已初始化的列表 */
/* 操作后:返回该列表中项目的个数 */
unsigned int ListItemCount(const List * plist); /* 操作:在列表尾部添加一个项目 */
/* 操作前:item是要被增加到列表的项目 */
/* plist指向一个已初始化的列表 */
/* 操作后:如果可能的话,在列表尾部添加一个新项目, */
/* 函数返回true:否则返回false */
bool AddItem(Item item, List * plist); /* 操作:把一个函数作用于列表中的每个项目 */
/* 操作前:plist指向一个已初始化的列表 */
/* pfun指向一个函数,该函数接受 */
/* 一个Item参数并且无返回值 */
/* 操作后:pfun指向的函数被作用于列表中的每个项目一次 */
void Traverse(const List * plist, void (*pfun)(Item item)); /* 释放以分配的内存(如果有) */
/* 操作前:plist指向一个已初始化的列表 */
/* 操作后:为该列表分配的内存已被释放 */
/* 并且该列表被置为空列表 */
void EmptyTheList(List * plist); #endif // LIST_H_

提供函数代码以实现接口

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
// 把一个项目复制到一个节点中
static void CopyToNode(Item item, Node * pnode); void InitializeList(List * plist)
{
*plist = NULL;
}
bool ListIsEmpty(const List plist)
{
if(plist == NULL)
return true;
else
return false;
}
bool ListIsFull(const List * plist)
{
Node * pt;
bool full; pt = (Node *)malloc(sizeof(Node));
if(pt == NULL)
full = true;
else
full = false;
free(pt);
return full;
}
unsigned int ListItemCount(const List * plist)
{
unsigned int count = ;
Node * pnode = *plist; while(pnode != NULL)
{
++count;
pnode = pnode->next;
}
return count;
}
// 较慢的实现方法
bool AddItem(Item item, List * plist)
{
Node * pnew;
Node * scan = *plist; pnew = (Node *)malloc(sizeof(Node));
if(pnew == NULL)
return false;
CopyToNode(item, pnew); // pnew->item = item;
pnew->next = NULL;
if(scan == NULL)
*plist = pnew;
else
{
while(scan->next != NULL)
scan = scan->next;
scan->next = pnew;
}
return true;
}
void Traverse(const List * plist, void (*pfun)(Item item))
{
Node * pnode = *plist;
while(pnode != NULL)
{
(*pfun)(pnode->item);
pnode = pnode->next;
}
}
void EmptyTheList(List * plist)
{
Node * psave;
while(*plist != NULL)
{
psave = (*plist)->next;
free(*plist);
*plist = psave;
}
}
static void CopyToNode(Item item, Node * pnode)
{
pnode->item = item;
}

将列表接口应用于具体编程问题的源代码文件

#include <stdio.h>
#include <stdlib.h>
#include "list.h" void showmovies(Item item); int main(void)
{
List movies; // 指向链表的指针
Item temp; // 初始化一个列表
InitializeList(&movies);
// 确定列表是否已满
if(ListIsFull(&movies))
{
fprintf(stderr, "No memory available! Bye!\n");
exit();
}
// 收集并存储
puts("Enter first movie title: ");
while(gets(temp.title) != NULL && temp.title[] != '\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 movies title (empty line to stop): ");
}
// 显示
if(ListIsEmpty(movies))
printf("No data entered.");
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 ;
}
void showmovies(Item item)
{
printf("Movie: %s Rating: %d\n", item.title, item.rating);
}

C Primer Plus之高级数据表示的更多相关文章

  1. C语言学习书籍推荐《C Primer Plus(中文版)(第5版)》下载

    普拉塔 (Prata S.) (作者), 云巅工作室 (译者) <C Primer Plus(中文版)(第5版)>共17章,介绍了C语言的基础知识,包括数据类型.格式化输入输出.运算符.表 ...

  2. 《C Primer Plus(第6版)(中文版)》普拉达(作者)epub+mobi+azw3

    内容简介 <C Primer Plus(第6版)中文版>详细讲解了C语言的基本概念和编程技巧. <C Primer Plus(第6版)中文版>共17章.第1.2章介绍了C语言编 ...

  3. 关于C primer plus 的学习计划(暂停)

    最近想学数据结构,但是C的基础不够好,想借着C primer plus补一下基础.怎料第一章看的还挺快,到第二章看了二十多天.现在改改阅读方式:每日在这里添加进度,然后精看例题习题和章总结,其它简略看 ...

  4. C Primer Plus(三)

    重读C Primer Plus ,查漏补缺 重读C Primer Plus,记录遗漏的.未掌握的.不清楚的知识点 文件输入/输出 1.fgets函数在读取文件内容时会将换行符读入,但gets不会,fp ...

  5. C Primer Plus(第五版)12

    第 12 章 存储类, 链接和内存管理 在本章中你将学习下列内容 . 关键字: auto, extern, static, register, const, volatile, restricted. ...

  6. 学长们的求职血泪史(C/C++/JAVA)

    以下分三个方向讲解,每个方向都是一个学长独自撰稿. (一)  C语言篇 C语言求职血泪史 华为(实习):机试.一面.性格测试被鄙视.优招被鄙视.普招被鄙视 锐捷:笔试.面试莫名其妙被鄙视 创新工场:笔 ...

  7. 论文翻译:2018_Artificial Bandwidth Extension with Memory Inclusion using Semi-supervised Stacked Auto-encoders

    论文地址:使用半监督堆栈式自动编码器实现包含记忆的人工带宽扩展 作者:Pramod Bachhav, Massimiliano Todisco and Nicholas Evans 博客作者:凌逆战 ...

  8. C++ Primer(第4版)-学习笔记-第5部分:高级主题

    第17章  用于大型程序的工具 异常处理 不存在数组或函数类型的异常.相反,如果抛出一个数组,被抛出的对象转换为指向数组首元素的指针,类似地,如果抛出一个函数,函数被转换为指向该函数的指针. 不要抛出 ...

  9. [翻译]Primer on Cognitive Computing(认知计算入门)

    Source Kelly J., Primer on Cognitive Computing 20150216. 侵删,联系方式:zhoujiagen\@gmail.com. 按A candidate ...

随机推荐

  1. UILabel常用属性

    [super viewDidLoad]; // 实例化UILabel并指定其边框 UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0 ...

  2. 【NPOI】.NET EXCEL导入导出开发包

    1.导出 //工作簿HSSFWorkbook HSSFWorkbook hssfworkbook = new HSSFWorkbook(); //ISheet页 ISheet sheet1 = hss ...

  3. WP开发笔记——日期时间DateTime.Now函数

    //2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString(& ...

  4. netstat监控大量ESTABLISHED连接与Time_Wait连接问题(转载)

    问题描述: 在不考虑系统负载.CPU.内存等情况下,netstat监控大量ESTABLISHED连接与Time_Wait连接. # netstat -n | awk '/^tcp/ {++y[$NF] ...

  5. Silverlight中嵌套html、swf、pdf

    1.MainPage.xaml <UserControl x:Class="SilverlightClient.MainPage" xmlns="http://sc ...

  6. 读取iis日志到sql server

    using Fasterflect; using System; using System.Collections.Generic; using System.Data.SqlClient; usin ...

  7. 微信小程序视频地址

    微信小程序视频系列教程完整版,课程中用到的源码附在帖子最后. [url=http://bbs.larkapp.com/forum.php?mod=viewthread&tid=5673][b] ...

  8. Stanford parser:入门使用

    一.stanford parser是什么? stanford parser是stanford nlp小组提供的一系列工具之一,能够用来完成语法分析任务.支持英文.中文.德文.法文.阿拉伯文等多种语言. ...

  9. centos 减少tty数量的方法

    在linux中,包括本文介绍的centos系统中,tty系统默认是给出7个,前六个是terminal,一个用于X. 在centos5.x中减少tty数量,通过修改/etc/inittab来实现. [r ...

  10. @RenderSection与@RenderBody

    _LayoutMain: <html> <head> @RenderSection("head") </head> <body> @ ...