算法导论 第二章作业

//作业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;

}

时间: 2024-11-08 10:10:19

算法导论 第二章作业的相关文章

算法导论 第二章

2014-12-02 20:21:40 http://www.cnblogs.com/sungoshawk/p/3617652.html 上面链接指向算法导论第二章的预习博客,很值得一看,很详细. 插入算法: 1 #include <iostream> 2 3 using namespace std; 4 void insert_sort(int *datas, int length); 5 int main() 6 { 7 int a[10]={1,2,4,35,6,1,4,7,9,7};

算法导论第二章C++实现归并算法排序

归并算法排序的思想算法导论中讲的还算比较清楚. #include<iostream> using namespace std; void guibing(int *_array,int p,int q,int r); void merge_sort(int *_array,int p,int r); int main() { int a[8]={2,4,5,7,1,2,3,6}; int j1=0; int j2=7; merge_sort(a,j1,j2); int i=0; for(;i&

【算法导论第二章】算法基础

2.1插入排序 扑克牌这个栗子不错.以后得多用扑克牌来形象化思考排序问题. 根据伪代码用java实现插入排序 package com.panjn.java; /** * Created by panjianning on 2016/7/10. */ public class InsertionSort { public static void main(String[] args) { int[] array = new int[]{1, 3, 5, 7, 9, 2, 4, 6, 8, 10};

算法导论第二章

插入排序源码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 void insert_sort(int a[]) 7 { 8 for(int j=1;j<10;j++) 9 { 10 int key=a[j]; 11 int i=j-1; 12 while(i>=0 && a[i]>key) 13 { 14 a[i+1]=a[i]; 15 i--; 16

算法导论--第二章、插入排序

1. 插入排序类似于整理扑克牌(排列好顺序的扑克和待排序的扑克): 2. 插入排序(INSERTION-SORT)参数是一个数组A[1..n]共n个数,输入的各个数字原地排序(sorted in place),分为排好序的和待排序的,每次取一个待排序元素,找到插入的位置,插入已排好序的部分中.元素取完程序结束,复杂度为O(n^2): 3. 伪代码如下: INSERTION-SORT(A) for j <- 2 to length(A) do key <- A[j] //Insert A[j]

算法导论 第一章

算法导论 第一章,为了让自己基本功更加的扎实,从今天起开始学习算法导论. 我以一位学长的博客为学习的参考资料,开始我的学习吧! 附上一句话: Having a solid base of algorithm knowledge and technique is one characteristic that separates the truly skilled programmers from the novices. 是否具有扎实的算法知识和技术基础,是区分真正熟练的程序员与新手的一项重要特

补基础:自学:计算机科学导论 第二章 数字系统

2.2 位置化数字系统 在数字中符号所占据的位置决定了其表示的值.在该系统中,数字这样表示: +-(Sk-1  --S2S1S0 --S-l)b 它的值是: n = +-(Sk-1 * bk-1 + -- + S1 * b 1 + S0 * b0 + S-1 * b-1 + -- + S-l * b-l) S是一套符号集,:b是底(或基数),它等于S符号集中的符号总数. 2.2.1 十进制系统(以10为底) 十进制(decimal)来源于拉丁词根decem. 在该系统中,底b = 10, 并且用

算法导论第九章中位数和顺序统计量(选择问题)

本章如果要归结成一个问题的话,可以归结为选择问题,比如要从一堆数中选择最大的数,或最小的数,或第几小/大的数等, 这样的问题看似很简单,似乎没有什么可研究的必要,因为我们已经知道了排序算法,运用排序+索引的方式不就轻松搞定了?但细想,排序所带来的时间复杂度是不是让这个问题无形之中变得糟糕.那算法研究不就是要尽可能避免一个问题高复杂度地解决,让那些不敢肯定有无最优解的问题变得不再怀疑,这也是算法研究者所追求的一种极致哲学.既然排序让这个问题解决的性能无法确定,那我们就抛开排序,独立研究问题本身,看

MIT算法导论——第二讲.Solving Recurrence

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解.(http://v.163.com/special/opencourse/algorithms.html) 第二节-------渐近符号.递归及解法 Solving Recurrence 第二节课的内容比较偏数学化,没有算法方面的知识.但尽管