抽象数据类型(ADT)

来源:互联网 发布:ubuntu快捷键 编辑:程序博客网 时间:2024/06/05 01:58

抽象数据类型(ADT)

理论基础

定义新的类型

什么是类型?类型特指两类信息:属性和操作。
假设要定义一个新的数据类型:

  • 首先,必须提供存储数据的方法,例如设计一个结构。
  • 其次,必须提供操控数据的方法。

计算机科学领域已开发了一种定义新类型的好方法,用3个步骤完成抽象到具体的过程。

  1. 提供类型属性和相关操作的抽象描述。这些描述既不能依赖特定的实现,也不能依赖特定的编程语言。这种正式的抽象描述被称为抽象数据类型(ADT)
  2. 开发一个实现ADT的编程接口。也就是说,指明如何储存数据和执行所需操作的函数。例如在C中,可以提供结构定义和操控该结构的函数原型。这些作用于用户定义类型的函数相当于作用于C基本类型的内置运算符。需要使用该新类型的程序员可以使用这个接口进行编程。
  3. 编写代码实现接口。这一步至关重要,但是使用该新类型的程序员无需了解具体的实现细节。

实现过程

建立抽象

以简单电影项目为例,所需的是一个链表数据类型,每一项包含电影名和评级。所需的操作是把新项添加到链表的末尾和显示链表中的内容。

链表的属性:

  • 能储存一系列的项,并按照一定方式排列;
  • 链表类型应该提供一些有用的操作。

链表一些有用的操作:

  • 初始化一个空链表;
  • 在链表末尾添加一个新项;
  • 确定链表是否为空;
  • 确定链表是否已满;
  • 确定链表的项数;
  • 访问链表的每一项执行某些操作,如显示该项。

对于该电影项目而言,暂时不需要其他操作。但是一般的链表还应包含以下操作:

  • 在链表的任意位置插入一个项;
  • 移除链表中的一个项;
  • 在链表中检索一个项(不改变链表);
  • 用另一个项替换链表中的一个项。

最后该类型总结如下:
简单链表

建立接口

list.h接口头文件:

/* list.h -- header file for a simple list type */#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;  //List是指向Node类型的指针/* 函数原型 */void InitializeList(List * plist); //plist是指向List类型的指针bool ListIsEmpty(const List *plist);bool ListIsFull(const List *plist);unsigned int ListItemCount(const List *plist);bool AddItem(Item item, List * plist);void Traverse (const List *plist, void (* pfun)(Item item) );//pfun是指向无返回值、参数为Item类型的函数的指针void EmptyTheList(List * plist);#endif  

使用接口

使用这个接口编写程序,但是不必知道具体细节。
伪代码方案:

创建一个List类型的变量。创建一个Item类型的变量。初始化链表为空。当链表未满且有输入时:    把输入读取到Item类型的变量中。    在链表末尾添加项。访问链表中的每个项并显示他们。  

films.c使用ADT风格的链表

#include<stdio.h>#include<stdlib.h>  //提供exit()的原型#include"list.h"    //定义Item、Listvoid showmovies(Item item);char * s_gets(char *st, int n);int main(void){    List movies;    int count;    Item temp;    /* 初始化 */    InitializeList(&movies);    if (ListIsFull(&movies))    {        fprintf(stderr, "No memory available!\n");        exit(1);    }    /* 获取用户输入并储存 */    puts("Enter first moive title");    while (s_gets(temp.title, TSIZE) != NULL && temp.title[0] != '\0')    {        puts("Enter your rating <1-10>:");        scanf("%d", &temp.rating);        while (getchar() != '\n')            continue;        if (AddItem(temp,&movies) == false)        {            fprintf(stderr,"Problem allocating memory.\n");            break;        }        if (ListIsFull(&movies))        {            fprintf(stderr, "The list is now full.\n");            break;        }        puts("Enter the next title:");      }    /* 显示 */    if (ListIsEmpty(&movies))        printf("No data entered.\n");    else    {        printf("Here is the moive list:\n");        Traverse(&movies, showmovies);    }    printf("You entered %d moives.\n", ListItemCount(&movies));    /* 清理 */    EmptyTheList(&movies);    puts("88");    return 0;}void showmovies(Item item){    printf("Moive: %s Rating: %d\n",item.title, item.rating);}char * s_gets(char *st, int n){    char *ret_val;    char *find;    ret_val = fgets(st, n, stdin);    if (ret_val)    {        find = strchr(st,'\n');        if (find)        *find = '\0';        else            while (getchar() != '\n')                continue;    }    return ret_val;}      

实现接口

list.c实现文件

//支持链表操作的函数#include<stdio.h>#include<stdlib.h>#include"list.h"//局部函数原型static void CopyToNode(Item item, Node * pnode);//内部链接,只在文件内生效//接口函数//把链表设置为空void InitializeList(List * plist)//plist是指向List的指针,*plist是指向Node的指针{    *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 = 0;    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->next = NULL;    if (scan == NULL)        *plist = pnew;    else    {        while(scan->next != NULL)            scan = scan->next;        scan->next = pnew;    }    return true;}//访问每个节点并执行pfun指向的函数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; }