表、栈、队列

来源:互联网 发布:网站在线下订单源码 编辑:程序博客网 时间:2024/06/09 10:22

一、抽象数据类型(ADT)

1、抽象数据类型是带有一组操作的一些对象的集合。在ADT的定义中没有地方提到关于这组操作是如何实现的任何解释。诸如表、集合、图以及与它们各自的操作一起形成的这些对象都可以被看作是抽象数据类型。对于集合ADT,可以有像添加、删除以及包含这样一些操作,也可以只要两种操作并和查找。

2、程序中需要对ADT实施操作的任何其他部分可以通过调用适当的方法来进行。

二、表ADT

1、对于除空表(大小为0)外的任何表,Ai后继Ai-1(或继Ai-1后,i<N)并称Ai-1前驱Ai(i>0)。表中的第一个元素是A0,最后一个元素是AN-1。不定义A0的前驱元,也不定义AN-1的后继元,元素Ai在表中的位置为i+1。

2、在表ADT上进行操作的集合,printList和makeEmpty是常用的操作。功能:find返回某一项首次出现的位置;insert和remove一般是从表的某个位置插入和删除元素;findKth则返回(作为参数而被指定的)某个位置上的元素。

3、表的简单数组实现

(1)对表的所有操作都可以通过使用数组来实现。

(2)数组的实现可以使得printList以线性时间被执行,findKth操作花费常数时间。

(3)最坏情形O(N):在位置0插入、删除第一个元素。

(4)如果所有的操作都发生在表的高端,那么就没有元素需要移动,而添加和删除只花费O(1)时间。

4、简单链表

(1)为了避免插入和删除的线性开销,我们需要保证表可以不连续存储,否则表的每个部分都可能需要整体移动。

(2)链表由一系列节点组成,这些节点不必在内存中相连。每一个节点均含有表元素和到包含该元素后继元的节点的链,我们称之为next链。最后一个单元的next链引用null。

(3)调用findKth常常是以(按i)排序后的方式进行。例如,findKth(2),findKth(3),findKth(4),findKth(6)可通过对表的一次扫描同时实现。

(4)remove方法可以通过修改一个next引用来实现。

(5)insert方法需要使用new操作符从系统取得一个新节点,此后执行两次引用的调整。

(6)向链表插入或从链表中删除一项的操作不需要移动很多的项,而只涉及常数个节点链的改变。删除最后一项必须找出指向最后节点的项,把它的next链改成null,然后再更新持有最后节点的链。

(7)让每一个节点持有一个指向它在表中的前驱节点的链,称之为双链表。

5、JavaCollections API中的表

(1))Collection接口

Collection API位于java.util包中,集合的概念在Collection接口中得到抽象,它存储一组类型相同的对象。

Collection的remove方法必须先找出要被删除的项。

(2)Iterator接口

实现Iterable接口的集合必须提供一个称为iterator的方法,该方法返回一个Iterator类型的对象。

Iterator接口的思路是,通过iterator方法,每个集合均可创建并返回给客户一个实现Iterator接口的对象,并将当前位置的概念在对象内部存储下来。

当直接使用Iterator(而不是通过一个增强的for循环间接使用)时,如果对正在被迭代的集合进行结构上的改变(即对该集合使用add、remove或clear方法),那么迭代器就不再合法(并且在其后使用该迭代器时将会有ConcurrentModicationException异常被抛出)。

6、List接口、ArrayList类和LinkedList类

(1)表(list)是由java.util包中的List接口指定。List接口继承了Collection接口,因此它包含Collection接口的所有方法,包括其他一些方法。

(2)ArrayList类提供了ListADT的一种可增长数组的实现。使用ArrayList对get和set的调用花费常数时间。

(3)LinkedList类提供了ListADT的双链表实现。使用LinkedList新项的插入和现有项的删除均开销很小。在表的前端进行添加和删除都是常数时间的操作。

(4)在ArrayList中有一个容量的概念,它表示基础数组的大小。在需要的时候,ArrayList将自动增加其容量以保证它至少具有表的大小。

三、栈ADT

1、栈模型

(1)栈(stack)是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶。对栈的基本操作有push(进栈)和pop(出栈),push相当于插入,pop是删除最后插入的元素。最后插入的元素可以通过使用top例程在执行pop之前进行考查。

(2)栈有时又叫做LIFO(后进先出)表。

(3)一般的模型是,存在某个元素位于栈顶,而该元素是唯一的可见元素。

2、栈的实现

(1)因为栈是一个表,因此任何实现表的分都能实现栈。栈操作是常数时间操作。

(2)栈的链表实现

栈的第一种实现方法是使用单链表。通过在表的顶端插入来实现push,通过删除表顶端元素实现pop。top操作只是考查表顶端元素并返回它的值。

(3)栈的数组实现

与每个栈相关联的操作是theArray和topOfStack,对于空栈它是-1(空栈初始化的做法)。为将某个元素x推入栈中,将topOfStack增1然后置theArray[topOfStack]=x。为了弹出栈元素,置返回值为theArray[topOfStack]然后使topOfStack减1.

3、应用

(1)平衡符号

做一个空栈。读入字符直到文件结尾。如果字符是一个开放符号,则将其推入栈中。如果字符是一个封闭符号,则当栈空时报错。否则,将栈元素弹出。如果弹出的符号不是对应的开放符号,则报错。在文件结尾,如果栈非空则报错。

(2)后缀表达式

使用一个栈,当见到一个数时就把它推入栈中;在遇到一个运算符时该运算符就作用于从该栈弹出的两个数(符号)上,再将所得结果推入栈中。

(3)中缀到后缀的转换

当看到一个操作符时,把它放入栈中。栈代表挂起的操作符。栈中有些具有高优先级的操作符现在直到当它们不再被挂起时要完成使用,应该被弹出。在把当前操作符放入栈中之前,那些在栈汇中并在当前操作符之前要完成使用的操作符被弹出。

(4)方法调用

当存在方法调用时,需要存储的所有重要信息,诸如寄存器的值和返回地址等,都要以抽象的方式存在“一张纸上”并被置于一个堆的顶部。然后控制转移到新方法,该方法自由的用它的一些值代替这些寄存器。当该方法要返回时,它查看堆顶部的那张“纸”并复原所有的寄存器,然后进行返回转移。

所存储的信息或称为活动记录或栈帧。

尾递归设计在最后一行的递归调用,尾递归可以通过将代码放到一个while循环中并用每个方法参数的一次赋值代替递归调用而被手工消除。

四、队列ADT

1、队列(queue)也是表,对于队列而言,任何的表的实现都是合法的。使用队列时插入在一端进行而删除则在另一端进行。

2、队列模型

(1)队列的基本操作是enqueue(入队),它是在表的末端(队尾)插入一个元素,dequeue(出队),它是删除(并返回)在表的开头(队头)的元素。

(2)队列的数组实现

(3)队列的应用

 


代码:点击打开链接

原创粉丝点击