使用 alloc_array(type, n) 创建数组,返回一个类型为 type[] 的数组,包含 n 个元素。数组的元素存储在分配的内存中,而数组变量本身存储在局部内存中,包含指向分配内存的地址。通过 A[i] 访问数组 A 的第 i 个元素,索引从0开始。分配的内存使用默认值初始化,对于整型数组,默认值为0。越界访问(out-of-bound access)是不允许的,有效索引是0到数组长度减一。数组操作需要满足前提条件(preconditions),例如 alloc_array(type, n) 需要 n ≥ 0。
C0中Aarray变量名存储的是数列的地址,因此,假如int[] B = A,A是某个已经存在的数列,B只会复制A的地址。后续对B的操作也实际上是对于A的操作。一旦某个数列没有指针指向它,C0的Garbage Collector就会消除掉该数列。整数与整数之间不涉及到地址的问题。C0无法返回某个数组的长度,但是用Contract中的\length()可以。
Searching and Sorting
In-place: allocates constant amount of memory.
Stable: relative position of duplicates is preserved.
Linear Search
Linear Search本身没什么可以探讨的,主要是关于contracts方面的问题。
Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
bool is_in(int x, int[] A, int lo, int hi) //@requires 0 <= lo && lo <= hi && hi <= \length(A); //Check whether x is in array segment A, [lo, hi)
int linearSearch(int x, int[] A, int n) //@requires n == \length(A); /*@ensures (-1 == \result && !is_in(x, A, 0, n)) || ((0 <= \result && \result < n) && A[\result] == x); { for (int i = 0; i < n; i++) //@loop_invariant 0 <= i && i <= n; //@loop_invariant !is_in(x, A, 0, n); { if (A[i] == x) return i; } //@assert !is_in(x, A, 0, n); return -1; }
Safety and Correctness
确保搜索过程中数组索引 i 在有效范围内,即 0 <= i < n,其中 n 是数组 A 的长度。使用contract来定义函数的前提条件(@requires)和后置条件(@ensures)。前提条件:确保传入的数组长度 n 与数组 A 的实际长度相匹配。后置条件:如果找到元素 x,则返回其索引;否则返回 -1。
void merge(int[] A, int lo, int mid, int hi) //@requires 0 <= lo && lo <= mid && mid <= hi && hi <= \length(A); //@requires is_sorted(A, lo, mid) && is_sorted(A, mid, hi); //@ensures is_sorted(A, lo, hi); { int[] B = alloc_array(int, hi-lo); int i = lo; int j = mid; int k = 0;
while (i < mid && j < hi) //@loop_invariant lo <= i && i <= mid; //@loop_invariant mid <= j && j <= hi; //@loop_invariant k == (i - lo) + (j - mid); { if (A[i] <= A[j]) { B[k] = A[i]; i++; } else { //@assert A[i] > A[j]; B[k] = A[j]; j++; } k++; }
//@assert i == mid || j == hi; // Exercise: write the omitted invariants for these loops while (i < mid) { B[k] = A[i]; i++; k++; } while (j < hi) { B[k] = A[j]; j++; k++; }
// Copy sorted array back into A for (k = 0; k < hi-lo; k++) A[lo+k] = B[k]; }
// mergesort void sort(int[] A, int lo, int hi) //@requires 0 <= lo && lo <= hi && hi <= \length(A); //@ensures is_sorted(A, lo, hi); { if (hi - lo <= 1) //@assert is_sorted(A, lo, hi); return;
int partition(int[] A, int lo, int hi) //@requires 0 <= lo && lo < hi && hi <= \length(A); //@ensures lo <= \result && \result < hi; //@ensures ge_seg(A[\result], A, lo, \result); //@ensures le_seg(A[\result], A, \result+1, hi); { int pi = lo + (hi - lo)/2; int pivot = A[pi]; swap(A, pi, lo); int left = lo + 1; int right = hi;
while (left < right) //@loop_invariant lo+1 <= left && left <= right && right <= hi; //@loop_invariant ge_seg(pivot, A, lo, left); //@loop_invariant le_seg(pivot, A, right, hi); //@loop_invariant pivot == A[lo]; { if (A[left] <= pivot) { left++; } else { //@assert A[left] > pivot; swap(A, left, right-1); right--; } }
//@assert left == right; swap(A, lo, left-1); return left-1; }
// quicksort void sort(int[] A, int lo, int hi) //@requires 0 <= lo && lo <= hi && hi <= \length(A); //@ensures is_sorted(A, lo, hi); { if (hi - lo <= 1) //@assert is_sorted(A, lo, hi); return;
int p = partition(A, lo, hi); //@assert lo <= p && p < hi; //@assert ge_seg(A[p], A,lo,p) && le_seg(A[p], A,p+1,hi); sort(A, lo, p); //@assert is_sorted(A, lo, p); sort(A, p+1, hi); //@assert is_sorted(A, p+1, hi); //@assert is_sorted(A, lo, hi); }