和arden一起学算法--第三天

第三天    抽象数据类型ADT

先给定义:抽象数据类型abstract data type是一种只通过接口访问的数据类型(值的集合以及作用于其上的运算组合)。

A set of data values and associated operations that are precisely specified independent of any particular implementation.

主要在于这个词abstract。它使得此data type只能通过接口来访问数据。数据的表示法及实现的运算都存在在实现中,用户不能通过接口看到实现。想想,有点OO的意思吧, 它和class这样的东西有这样的共同点(封装怎么也算是OO三个重要特点之一),按照我的理解来说,class便是一种ADT,或者它在语法层面更高级一点。

真正的ADT比较苛刻,我们的串不算一个。为什么?我们都可以直接提领它和它的地址,没有接口在中间。我们可以string str=”this is a string”printf(“%c”, str[1]);不需要写一个函数来代替这个运算符:printf(“%c”,str.getchar(1));当然我们可以定做一个完全ADTstring

下面给一个熟悉的例子:下堆栈STACK

其实就是我们说的LIFOlast in first out)的堆栈,和它对应的那个我们常叫它队列FIFOfirst in first out)。

我们假设这个抽象数据类型有这样几种操作:初始化、压栈、出栈、清空。

stack.h中我们定义下面的函数:此代码写在stack.h

void stack_init( int );

Int stack_empty();

void stack_push(item);

Item stack_pop();

下面在选择实现方式的时候,我们可以有很多种方法:自己完全定义或者拿来现成的。数组可以吧,链表也可以,

给一个数组的实现:

#include <stdlib.h>

#include "Item.h"

#include "STACK.h"

static Item *s;

static int N;

void STACKinit(int maxN)

  { s = malloc(maxN*sizeof(Item)); N = 0; }

int STACKempty()

  { return N == 0; }

void STACKpush(Item item)

  { s[N++] = item; }

Item STACKpop()

  { return s[--N]; }


  
  
   
    
  
  

我使用其它的好不好?比如串?不好,串太狭隘了,字符已经局限了它的作为,此处非它擅长(并不是不行,只是在效率和实现复杂度上不可取)。

看起来一个ADT并不复杂,定义好数据和接口便可以付诸使用。现实是,这个栈的逻辑关系并不复杂,对于很有经验的熟悉的东西作ADT可能容易。面对一个新问题,我们如何周全的设计它是关键。

先看看怎么用这个stack

逆波兰这个名次在数据结构中一定听说过。正是使用栈的好时候。看看这个后缀表达式:5 9 8 + 4 6 * * 7 + *

我们需要人化一下:我们容易看懂的表达式是这样的:5*((9+8)*(4*6)+7)

这个转换过程我们需要借助堆栈帮我们完成,读取一个逆波兰式,如果是数字压入栈,如果是运算符,将前面两个入栈的pop出来和读到的运算符计算,再将结果压入栈。就是这样一个过程,我们看看代码如何实现:

#include <stdio.h>

#include <string.h>

#include "Item.h"

#include "STACK.h"

main(int argc, char *argv[])

  { char *a = argv[1]; int i, N = strlen(a);

    STACKinit(N);

    for (i = 0; i < N; i++)

      {

        if (a[i] == '+')

          STACKpush(STACKpop()+STACKpop());

        if (a[i] == '*')

          STACKpush(STACKpop()*STACKpop());

        if ((a[i] >= '0') && (a[i] <= '9'))

          STACKpush(0);

        while ((a[i] >= '0') && (a[i] <= '9'))

          STACKpush(10*STACKpop() + (a[i++]-'0'));

      }

    printf("%d /n", STACKpop());

  }  

Ok,看出来了为了简便没有给出减法和除法的运算,因为这两个运算没有交换率,写出代码可能复杂些,不利于我们理解栈的使用。

会使用现成的ADT还没有变成英雄,我们还需要自己来规划并实现自己想得到的ADT。参考上面已经实现的ADT,我们可以照猫画虎,画多了就会得心应手。既然这样我们来画一个FIFO

比较麻烦的是,堆栈其实就在操作一个内存地址,进去出来都是这里,哈,这是一个只有一个门的房间。FIFO队列有前门和后门,前门出后门进。在实现其数据操作时需要两个内存位置,稍微复杂了一些。先自己想想怎么做,然后看下面的代码好了。

void QUEUEinit(int);

 int QUEUEempty();

void QUEUEput(Item);

Item QUEUEget();

-----

#include <stdlib.h>

#include "Item.h"

#include "QUEUE.h"

typedef struct QUEUEnode* link;

struct QUEUEnode { Item item; link next; };

static link head, tail;

link NEW(Item item, link next)     

  { link x = malloc(sizeof *x);

    x->item = item; x->next = next;    

    return x;                        

  }                                  

void QUEUEinit(int maxN)

  { head = NULL; }

int QUEUEempty()

  { return head == NULL; }

QUEUEput(Item item)

  {

    if (head == NULL)

      { head = (tail = NEW(item, head)); return; }

    tail->next = NEW(item, tail->next);

    tail = tail->next;

  }

Item QUEUEget()

  { Item item = head->item;

    link t = head->next;

    free(head); head = t;

    return item;

  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值