编译原理:实验二、集合与线性表操作

(一).     实验目的

编译器处理源程序文件的过程中,集合、链表、栈是经常出现的数据结构。

与《数据结构》课程关注集合、线性表的编程实现不同,本实验关注它们的使用。在Java语言中,集合和线性表分别就是Java工具类Util包中的Set和List两个接口。特别的,本实验关注HashSet、ArrayList(或Vector)和Stack(它们分别是集合、链表和栈的实现类)的使用,为后续实验做好准备。

(二).     预备知识

1.    集合和线性表的基本操作

集合和线性表(链表和栈)的基本操作是《数据结构》课程的基础知识,这里不一一进行介绍。

2.    Collection

在Java中,集合容器(Collection)是一个对象的容器,可以存放一组对象,主要用来组织和管理存放在容器中的对象。

注:Java中,集合Set继承了Collection,因此Collection很难翻译。目前较多情况下仍将Collection译为“集合”,如“Java Collection Framework”,一般译为“Java集合框架”。但要注意,此时的“集合”指Collection。其它情况下,集合指Set。

其中,常用的几个实现类如下:

   HashSet — 使用散列算法实现Set接口

   TreeSet — 使用平衡二叉树算法实现SortedSet接口

   ArrayList — 使用数组存放对象来实现List接口

  Vector — 与ArrayList的区别在于Vector是同步、线程安 全的,而ArrayList是异步、线程不安全的。性能上,Vector比ArrayList低。

  Stack — 上图没有画出,它是Vector的直接子类,实现了栈的基本操作。

   LinkedList — 使用双向链表来实现List接口

3.    泛型(Generic)

注:泛型与范型同音,但意义相差甚远。

范型(Paradigm)的范,指一种规范的、可作为模范的样式、范例,也译为范式。如OO范式等,包含了面向对象编程许多方面的内容,与面向过程的范式作为区别。

泛型(Generic)的泛,指的是泛化的含义,因为Generic是“类属的”的意思。在C++中,泛型就是“模板(Template)”。因为同音的缘故,许多网络上的文章,把“泛型”误为“范型”,要特别注意区分。泛型的例子如下:

Set<Object>,一个存放元素是“Object”的集合;

Set<String>,一个存放元素是“String”的集合;

Stack<Integer>,一个存放元素是“Integer”的集合;

Stack<aUserDefinedClass>,一个存放由用户定义的类的集合

4.    集合与线性表基本操作的使用

通常使用形如 Set<Integer> si=new HashSet<Integer>();来声明一个存放整数的集合(注:类Integer可换成其它自定义的类)。

然后,可使用si.add(new Integer(5));来向集合中插入一个元素5”;再使用si.contains(new Integer(5))来判断集合中是否包含元素“5”;再使用si.remove(new Integer(5));来从集合中删除元素“5”。

若要遍历访问集合si中的全部元素,则需要使用迭代器Iterator。

通过Iterator<Integer> it=si.iterator();取得si的迭代器,再通过判断while(it.hasNext()){ //是否遍历到最后一个元素,若是最后元素,
                   //则hasNext为假,否则为真

              Integer i=it.next(); //访问当前元素

              //do something,对当前元素i进行操作

   }。

线性表的声明、操作与集合的声明、操作非常类似,只是换了一个类名而已。如声明Stack<String> ss=new Stack<String>;为一个存放字符串的栈,然后可通过ss.peek()、ss.push(aString)、ss.pop()来访问栈顶元素、进行入栈和出栈操作。

 需要特别注意的是,集合Set不重复保存相同元素。那么,Set要如何做,才能判断一个元素是否跟另一个元素相同?答案就是o.equals(e)。如果元素o、e都不为空,并且o.equals(e),那么集合Set就认为o和e是相同的元素。对基本数据类型,如Integer、String等,因为语言已经实现了对应的equals方法,所以可以直接使用。若集合中的元素是自定义的类,那么,则需要考虑应如何实现equals方法。在C++的STL库中,则要实现的是小于等于的LE方法。

(三).     实验内容

1.    字符集合

a)         声明一个存放非终结符的集合sc。考虑应拿什么数据类型或数据结构保存非终结符?

b)        从文件“NonTerminal.txt”中读取所有的非终结符。文件内容如下:

a, b, c, d.

也即使用逗号分隔非终结符,使用句话表示输入结束。

c)         使用迭代器遍历读入的非终结符,按一行输出一个非终结符的方式,显示在屏幕上,并同时写入到另外一个文件中。

2.    产生式

a)       产生式是形如“A è aB”之类的式子,由产生式左侧和产生式右侧2个部分组成,中间的“è”用处在于显示的时候可以分隔2端,并没有特别含义。如果我们只处理2型和3型文法,即上下文无关文法和线性文法,那么,产生式应如何设计怎样的数据结构来保存产生式。换句话说,产生式类应如何设计?

b)      特别的,产生式类中,equals(或LE)方法,应如何实现?

3.    产生式栈

a)       声明一个存放产生式的栈。产生式使用内容2中的产生式类。

b)      从文件“Production.txt”中读取所有的产生式。文法的内容如下:

A -> aB

C -> sdfdf

也即一行一个产生式,产生式中间的分隔符是“->”(或其它,可自己再定义),一直到文件结束。

将读入的产生式,按栈先进后出(First In Last Out FILO)的次序,一行一个在屏幕上显示出来,并写入到另外一个文件中。

原文地址:https://www.cnblogs.com/suiyun/p/2725558.html