//作业2. 1-2
template<class T>
void insert(T* A, int n)
{
for (int j = 1; j < n; ++j)
{
T key = A[j];
int i = j - 1;
while (i >= 0 && key > A[i])
{
A[i + 1] = A[i];
--i;
}
A[i + 1] = key;
}
}
//2. 1-3
template<class T>
void find(T* A, int n, T v)
{
int i = -1;
for (int j = 0; j < n; ++j)
{
if (A[j] == v)
{
i = j;
break;
}
}
if (i == -1)
v = Nil;
}
/*
循环不变式:
初始化:i == -1,v还没和任何A数组中的元素比较,所以是-1,它为真。
保持:如果j循环到k时为真,那么说明i还是-1),
j到了k+1,如果A[k + 1] != v, 那么i还是Nil。
终止:A[j] == v,此时终止,可以得到i就等于j 得知此时的A[i]是v
或者i是-1,此时赋值Nil给v
*/
//2. 1-4
/*
输入:两个序列A,B,每个序列为n位2进制整数
输出:一个存放前面两个序列相加结果的n+1位2进制整数数组c
*/
void add2(int* A, int* B, int *C, int n)
{
int temp=0;
for (int i = n - 1; i >= 0; --i)
{
C[i + 1] = (A[i] + B[i]) % 2 + temp;
temp = (A[i] + B[i]) /2;
}
C[0] = temp;
}
//2. 2-1
//O-(n^3)
//2. 2-2
template<class T>
void select(T* A, int n)
{
for (int i = 0; i < n - 1; ++i)
{
int min = A[i];
int pos = i;
for (int j = i; j < n; ++j)
{
if (min > A[j])
{
min = A[j];
i = j;
}
}
T temp = A[i];
A[i] = A[pos];
A[pos] = temp;
}
}
/*
循环不变式:
初始化:i == 0 后面还有n个数需要排序;
保持:i == k, k前面的已经排序好了,i == k+1时,第k+1个数会找到后面的最小的数,
这个数只可能大于等于k,因为k找到的是当时k后面的最小的那个数。 循环成立。
终止:i==n, n个数全部排序完成。
只需要排序n-1个数的原因,前面n-1个数都是比n大的,n就是最大的,就不需要排序了。
最好的情况==最差的情况:O-(n^2)
*/
//2. 2-3
/*
平均需要检查的元素长度为:(n + 1)/2
最坏情况:n
平均情况==最坏情况:O-(n)
证明:
查找的元素等可能,每个元素被找的概率为1/n。
找的长度len == (1/n * 1 + 1/n * 2... 1/n * n) == (1 + 2 + 3 +... + n)/n == (n + 1) / 2;
*/
//2. 2-4
//直接针对某一种情况来设计算法解决问题就可以获得良好的最好情况运行时间
//2. 3-2
template<class T>
void merge(T* A, int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int i, j;
i = 0;
j = n1;
T* B = new T[n1 + n2];
memmove(B, A + p, sizeof(T)*(n1 + n2));
while (i != n1 && j != n1 + n2)
{
if (B[i] < B[j])
{
A[p] = B[i];
++i;
}
else
{
A[p] = B[j];
++j;
}
++p;
}
if (i == n1)
{
while (p != r)
{
A[p] = B[j];
++p;
++j;
}
}
else
{
while (p != r)
{
A[p] = B[i];
++p;
++i;
}
}
delete[] B;
}
//2. 3-3
/*
n == 2: T(n) == 2 == 2*1 == 2*lg(2)
n == k时成立:T(k) == k*lg(k)。 n == k * 2时:T(2*k) == 2*T(k) + 2*k == 2*k*lg(k) + 2*k
== 2k* (lg(k) + 1) == 2k * lg(2k); n==2*k时成立。由此得证。
*/
//2. 3-4
//T(n)=={ 1 (n ==1)
// T(n - 1) + n(n > 1)
// }
//2. 3-5
template<class T>
int binaryFind(T* A, int l, int r, const T& v)
{
if (l <= r)
{
int m = (l + r) / 2;
if (v == A[m])
return m;
if (v < A[m])
binaryFind(A, l, m - 1, v);
else
binaryFind(A, m + 1, r, v);
}
else
return -1;
}
//最坏情况就是一直查到1.
//T(n) =={ 1 (n == 1)
// T(n/2) (n > 1) }
//通过递归树得到运行最坏结果为O-(lg(n));
//2. 3-6
//并不能缩短,insertion-sort主要占时间的不是查找,而是插入时需要移动大量的元素。
//2. 3-7
//使用nlog(n)的排序算法先排好序,然后从i=0和j=n开始相加,如果大于x就--j,继续加,小于x就++i;
//如果最后i==j就返回false,否则返回i j 值。
//2-1
/*a:每个k大小的区间,最差情况下:k(k+1)/2,一共有n/k个区间,最后得到k(k+1)/2 * n/k
== n(k+1)/2 : O-(nk);
b:每一层的代价是n,一共有lg(n/k)+1层,向上合并就得到O-(nlg(n/k))
c: nk+nlg(n/k) <= nlg(n): k <=lg(n); k的最大值就是 lg(n);
d: 在插入排序比归并排序快的情况下,取k的最大值。
*/
//2-2
/*
a:必须证明A'是A的一种排序。
b:j位置的元素永远是j到A.length区间中最小的。
初始化:j == A.length。只有一个元素,所以符合最小的条件。
保持: j不断减小,因为A[j]是j到A.length区间中最小的,比较A[j-1]和A[j],如果A[j]小于A[j-1]就
交换两个位置的值,j变成了原先的j-1,j还是最小的。
终止:j == i ,结果使得i这个位置的元素成为 i到 A.length区间最小的元素。
c:区间1到i 一直都是排序好的状态
初始化:i=1,区间1到1只有一个元素,已经排序好。
保持:1到i-1已经排序好了,i通过第二个for循环,使得i成为了i到A.length区间最小的元素,
加上前面排序好的1到i-1,区间1到i呈现已经排序好的状态。
终止:i等于A.length-1,得到结果1到A.length-1是已经排序好的状态,而且i-1 小于 i(第二个循环的结果),
所以1到A.length都已经排好序了。
d:最坏情况的运行时间:O-(n(n-1)/2),性能和插入排序一样,除了最差情况,插入排序要比冒泡排序好,因为冒泡排序的
运行时间总是O-(n^2)的。
*/
//2-3
// a:O-(n+1)加法 + O-(n+1)乘法
int power(int x, int n)
{
int res = 1;
for (int i = 0; i < n; ++i)
res *= x;
return res;
}
void sum(int* A, int n,int x)
{
int y = 0;
for (int i = 0; i < n; ++i)
y += A[i] * power(x,n);
}
/*
b:运行时间:O-(n)加法 + O-(n(n-1)/2)乘法。效率相比霍纳规则差,多了很多乘法时间。
c:初始化:i == n ,y == k从0到-1,也就是没有区间,也就是y==0;
保持:每次i+1都有y== a[n]*(x^(n-i-2)) +a[n-i-3]*(x^2)...+a[i+2]*(x^(0)),轮到i时y==a[i+1] + y*x==
a[n]*(x^(n-i-1))+...+a[i+1],符合式子。
终止:i==-1,y==a[n]*(x^n)+...+a[0],就是式子。
d:y==式子==P(x)就是正确答案。。。
*/
//2-4
/*
a:(2,1)(3,1)(8,1)(6,1)(8,6)
b:{n,n-1,n-2...2,1},有n(n-1)/2对逆序对。
c:逆序对越少,插入排序用时越少。
逆序对增加的情况就是小的数被换到序列后面了,每换一个数到后面,这个数在排序的时候要回到正确位置就需要
比较 换的距离 次。
d: */
int invertion_aux(int* A, int l, int m, int r)
{
int n1 = m - l + 1;
int n2 = r - m;
int i, j;
i = 0;
j = n1;
int sum = 0;
int* B = new int[n1 + n2];
memmove(B, A + l, sizeof(int)*(n1 + n2));
while (i != n1 && j != n1 + n2)
{
if (B[i] < B[j])
{
A[l] = B[i];
++i;
}
else
{
A[l] = B[j];
++j;
sum += n1 - i;
}
++l;
}
if (i == n1)
{
while (l <= r)
{
A[l] = B[j];
++l;
++j;
}
}
else
{
while (l <= r)
{
A[l] = B[i];
++l;
++i;
}
}
delete[] B;
return sum;
}
int invertion(int* A, int l, int r)
{
if (l < r)
{
int m = (l + r) / 2;
int a = invertion(A, l, m);
int b = invertion(A, m + 1, r);
int sum = invertion_aux(A, l, m, r);
return a + b + sum;
}
return 0;
}