抽象數據類型(ADT)

抽象數據類型(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、List

void 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;
 } 
發佈了27 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章