龙书的P431中有一个quicksort的不含嵌套函数及高阶函数的例子,我实现的时候居然错了,真的太菜了。虽然整体的思想都是让问题退化为解决枢轴两边的快排问题,但是在处理细节上是不同的。虽然基础,但是好记性不如烂笔头,还是硬着头皮写下吧>_<
方法一
public class Qs { private int[] numbers; private int number; public void sort(int[] values) { if (values == null || values.length < 2) { return; } this.numbers = values; number = values.length; quicksort(0, number - 1); } int partition(int low, int high) { int pivotKey = numbers[low]; while (low <= high) { while (numbers[low] < pivotKey) { low++; } while (numbers[high] > pivotKey) { high--; } if (low <= high) { exchange(low, high); low++; high--; } } return low; } private void quicksort(int low, int high) { int i = partition(low, high); if (low < i - 1) { quicksort(low, i - 1); } if (high > i) { quicksort(i, high); } } private void exchange(int i, int j) { int temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; } public static void main(String[] args) { int[] arr = { -4, 4, 3, -1, 2, 1, -3, -2, 0 }; Qs qs = new Qs(); qs.sort(arr); for (int ele : arr) System.out.print(ele + " "); } }
方法二(修改方法一中的partition和quicksort)
int partition(int low, int high) { int pivotKey = numbers[low]; while (low < high) { while (low < high && numbers[high] >= pivotKey) high--; exchange(low, high); while (low < high && numbers[low] <= pivotKey) low++; exchange(low, high); } return low; } private void quicksort(int low, int high) { if (low < high) { int pivotKey = partition(low, high); quicksort(low, pivotKey - 1); quicksort(pivotKey + 1, high); } }
注意细节即可,这里就不演示了。想了解一下细节的话可以加断点细细分析;或者加些aspect的信息来看一下。下面是直接用aspectj插入的一些信息:
public aspect QsAspectj { private int callDepth = -1; pointcut MethodInfo(int low,int high):call (* *(..))&&this(Qs)&&args(low,high); before(int low,int high):MethodInfo(low,high){ callDepth++; System.out.print(callDepth); for(int i = 0; i< callDepth;i++) System.out.print(" "); System.out.println(thisJoinPointStaticPart.getSignature().getName()+"("+low+", "+high+")"); } after(int low,int high):MethodInfo(low,high){ System.out.print(callDepth); for(int i = 0; i< callDepth;i++) System.out.print(" "); System.out.println(thisJoinPointStaticPart.getSignature().getName()+"("+low+", "+high+")"); callDepth--; } pointcut sortInfo():call(public void sort(int[]))&&within(Qs); Object around():sortInfo(){ long begin = System.nanoTime(); Object result = proceed(); long end = System.nanoTime(); System.out.println("total time: "+(end-begin)); return result; } before():sortInfo(){ System.out.println("*** "+thisJoinPointStaticPart.getSignature().getName()+" ***"); } after():sortInfo(){ System.out.println("*** "+thisJoinPointStaticPart.getSignature().getName()+" ***"); } }
class Quicksort { def sort(a: Array[Int]): Array[Int] = if (a.length < 2) a else { val pivot = a(a.length / 2) sort(a filter (pivot >)) ++ (a filter (pivot ==)) ++ sort(a filter (pivot <)) } } object Quicksort extends Application { val qs = new Quicksort val a = Array(-4, 4, 3, -1, 2, 1, -3, -2, 0) // val start = System.nanoTime() val sorted = qs.sort(a) // val end = System.nanoTime() // println("total time: " + (end - start)) sorted.foreach(n => (print(n), print(" "))) }
貌似这样的做法不怎么高效(不妨看看运行时间),但鉴于我的scala还只勉强达到入门级,如何改进还得以后再说。
不懂编译原理没法在实验室混啊,开始写些流水帐笔记,目的只是为了重新补上这一课;仅代表个人知识水平,万不可因此而怀疑我的师兄和同学们>_<。参考教材Compilers: Principles, Techniques, and Tools(龙书)。
-------------------------------------------------------
Lexical analyzer生成token给parser用,分析过程还得和symbol table交互;在分析过程中需要干掉comments和whitespace(whitespace指的是blank,newline和tab或其他用于分隔token的东东,而不仅仅是空格)。
token的样子是(token-name,attribute-value),其中attribute-value对保留字、操作符是不需要的;对于token-name是id的情况,attribute-value一般是指向其所在符号表中的项的pointer;对于数字这样的输入,可以让attribute-value表示对应的值,但实际一般还是用一个pointer指向表示它的字符串。
lexeme是源程序中的具体字符序列;pattern是对模式的描述;token可看成对lexeme的泛化(类似于OO中的class)
识别lexeme时需要向前看几个字符(比如看到<有可能是<=或<);同时为减少io读取次数,使用双buffer。
每次需检查buffer终点并确定读入的字符是什么,为求统一使用sentinel(输入中不会出现的字符,如eof)
DFA$\subset$NFA,DFA初初始态不可为$\varepsilon$且每一个状态只有一个出边;DFA和NFA等价,可以类比群中的加法和乘法;其中DFA中的一个状态可看成NFA中的状态组成的集合(subset construction)。