一、ADT

  在介绍抽象数据类型的时候,先看看什么是数据类型,在Java中可能首先会想到像 int,double这样的词,这是Java中的基本数据类型,一个数据类型会涉及到两件事:

  ①、拥有特定特征的数据项

  ②、在数据上允许的操作

  比如Java中的int数据类型,它表示整数,取值范围为:-2147483648~2147483647,还能使用各种操作符,+、-、*、/ 等对其操作。数据类型允许的操作是它本身不可分离的部分,理解类型包括理解什么样的操作可以应用在该类型上。

  那么当年设计计算机语言的人,为什么会考虑到数据类型?

  我们先看这样一个例子,比如,大家都需要住房子,也都希望房子越大越好。但显然,没有钱,考虑房子没有意义。于是就出现了各种各样的商品房,有别墅的、复式的、错层的、单间的……甚至只有两平米的胶囊房间。这样做的意义是满足不同人的需要。

  同样,在计算机中,也存在相同的问题。计算1+1这样的表达式不需要开辟很大的存储空间,不需要适合小数甚至字符运算的内存空间。于是计算机的研究者们就考虑,要对数据进行分类,分出来多种数据类型。比如int,比如float。

  虽然不同的计算机有不同的硬件系统,但实际上高级语言编写者才不管程序运行在什么计算机上,他们的目的就是为了实现整形数字的运算,比如a+b等。他们才不关心整数在计算机内部是如何表示的,也不管CPU是如何计算的。于是我们就考虑,无论什么计算机、什么语言都会面临类似的整数运算,我们可以考虑将其抽象出来。抽象是抽取出事物具有的普遍性本质,是对事物的一个概括,是一种思考问题的方式。

  抽象数据类型(ADT)是指一个数学模型及定义在该模型上的一组操作。它仅取决于其逻辑特征,而与计算机内部如何表示和实现无关。比如刚才说得整型,各个计算机,不管大型机、小型机、PC、平板电脑甚至智能手机,都有“整型”类型,也需要整形运算,那么整型其实就是一个抽象数据类型。  

  更广泛一点的,比如栈和队列这两种数据结构,分别使用了数组和链表来实现,比如栈,对于使用者只需要知道pop()和push()方法或其它方法的存在以及如何使用即可,使用者不需要知道我们是使用的数组或是链表来实现的。

  ADT的思想可以作为我们设计工具的理念,比如我们需要存储数据,那么就从考虑需要在数据上实现的操作开始,需要存取最后一个数据项吗?还是第一个?还是特定值的项?还是特定位置的项?回答这些问题会引出ADT的定义,只有完整的定义了ADT后,才应该考虑实现的细节。

  这在我们Java语言中的接口设计理念是想通的。

二、栈概述

  数组、链表、树等数据结构适用于存储数据库应用中的数据记录,它们常常用于记录那些现实世界的对象和活动的数据,便与数据的访问:插入、删除和查找特定数据项

  而栈和队列更多的是作为程序员的工具来使用。他们主要作为构思算法的辅助工具,而不是完全的数据存储工具。这些数据结构的生命周期比那些数据库类型的结构要短很多。在程序操作执行期间它们才被创建,通常它们去执行某项特殊的任务,当任务完成后就被销毁

  栈和队列的访问是受限制的,即在特定时刻只有一个数据项可以被读取或删除

  栈和队列是比数组和其他数据结构更加抽象的结构,是站在更高的层面对数据进行组织和维护

  栈的主要机制可用数组来实现,也可以用链表来实现。优先级队列的内部实现可以用数组或者一种特别的树——堆来实现。

  先来了解栈的概念和实例,然后分别深入理解队列和优先级队列

  栈只允许访问一个数据项:即最后插入的数据。移除这个数据项后才能访问倒数第二个插入的数据项。它是一种“后进先出”的数据结构。

  栈最基本的操作是出栈(Pop)、入栈(Push),还有其他扩展操作,如查看栈顶元素,判断栈是否为空、是否已满,读取栈的大小等

1.1、数组编写栈

代码地址:data-002-stack StackWithArray

1.2、栈示例

栈通常用于解析某种类型的文本串。通常,文本串是用计算机语言写的代码行,而解析它们的程序就是编译器 

用栈来实现分隔符匹配。如:a{b(c[d]e)f}是否正确。

分析:每次都是成对出现,分隔符匹配程序从字符串中不断地读取程序,每次读取一个字符,若发现它是左分隔符({、[、(),将它压入栈中。当读到一个右分隔符时()、]、}),弹出栈顶元素,并且查看它是否和该右分隔符匹配。如果它们不匹配,则程序报错。如果到最后一直存在着没有被匹配的分隔符,程序也报错。

代码地址:data-002-stack 中的测试代码 StackWithArrayTest,其中主要逻辑

    public boolean check() {
        int length = input.length();
        StackWithArray<Character> stackWithArray = new StackWithArray(length);

        for (int i = 0; i < length; i++) {
            char ch = input.charAt(i);
            switch (ch) {
                case '{':
                case '[':
                case '(':
                    stackWithArray.push(ch);
                    continue;
                case '}':
                case ']':
                case ')':
                    if (!stackWithArray.isEmpty()) {
                        Character character = stackWithArray.pop();//左侧
                        if ((character == '{' && ch != '}') ||
                                (character == '[' && ch != ']') ||
                                (character == '(' && ch != ')')) {
                            System.out.println("匹配出错,字符是" + ch + ",下标:" + i);
                            return false;
                        }
                    }
                    continue;
                default:
                    continue;

            }

        }
        if (!stackWithArray.isEmpty()) {
            System.out.println("匹配出错,有未关闭的括号");
            return false;
        }
        return true;

    }
View Code

相关文章:

  • 2021-09-28
  • 2022-01-02
  • 2021-09-25
  • 2022-12-23
  • 2022-12-23
  • 2021-08-21
  • 2021-09-11
  • 2022-12-23
猜你喜欢
  • 2022-01-08
  • 2021-06-15
  • 2021-07-28
  • 2021-08-07
  • 2021-09-23
  • 2022-12-23
相关资源
相似解决方案