目录
有不正确请提出
第一章
1.1
应该把形参 换成引用
int x--> int &x
1.2
#include<iostream>
using namespace std;
template <class T,class T1> //模板形参的类型
int
count (T array,int end,T1 value){
int i =0,count=0;
while(i<end){
if (array[i++] == value)
count++;
}
return count ;
}
int main(){
int array[]{23,45,6,0,0,77,99,7};
cout<< count(array,sizeof(array)/sizeof(array[0]),0);
}
1.3
#include<iostream>
using namespace std;
template <class T,class T1>
int
fill(T array,int end,T1 value){
int i =0;
while(i<end){
array[i++]= value;
}
return 1;
}
int main(){
int array[10];
cout<< fill(array,10,66);
cout << array[8];
}
1.4
#include<iostream>
using namespace std;
template<class T,class T2>
int
inner_product(T a1, T a2,T2 n){
int i=0;
int value=0;
while( i<n){
value = value +a1[i]*a2[i];
i++;
}
return value;
}
int main(){
int a[]={1,2,3,4};
int b[]={10,10,100};
cout<< inner_product(a,b,3)<<endl;
}
1.5
#include<iostream>
using namespace std;
template<class T>
void
iota (T array,int n){
int i=0;
while( i!=n){
array[i] += i;
i++;
}
}
int main(){
int a[]{1,2,3,4,5,6};
iota(a,5);
for(int i=0;i!=5; i++){
cout<<a[i];
}
return 0;
}
1.6
应该还包括递减的情况
#include<iostream>
using namespace std;
template<class T>
bool
is_sorted(T array,int n){
int i=0;
while(i!=n-1){
if(array[i]>array[i+1])
return false;
i++;
}
return true;
}
int main(){
int a[]{1,4,6,78,666};
cout<< is_sorted(a,5);
return 1;
}
1.7
#include<iostream>
using namespace std;
template<class T>
int
mismatch(T a,T b,int end){
int i(0);
while( i!=end){
if(a[i]!= b[i])
return i;
i++;
}
return -1;
}
int main(){
int a[]{1,2,34,6};
int b[]{1,2,6,888};
cout<< mismatch(a,b,4);
return 0;
}
1.8
具有相同的签名 ,形参的个数和类型相同,与返回值无关
1.9
都调用模板abc, 因为有三个形参
1.10 /1.11
#include<iostream>
using namespace std;
int
abc(int a,int b,int c){
if(c<1)
throw "有异常!!!"; // 抛出异常
return a+b+c;
}
int main(){
try{
cout<<abc(-2,-3,-5)<<endl;
}
catch (int value){ //补货整型
cout<< value;
}
catch (const char *c){ //字符串常量是 const char*
cout <<c<<endl;
}
return 0;
}
1.12
#include<iostream>
using namespace std;
template <class T,class T1>
bool
make2_array(T **&array,int number_OF_rows,T1 row_Size){
int i=0;
try{
array = new T* [number_OF_rows]; //创建数组指针 类型就是 T **
while(i< number_OF_rows){
array[i] = new T [ row_Size[i] ];
i++;
}
return 1;
}
catch (bad_alloc){
return false;
}
}
int main(){
char **a;
int row_size[]{1,2,4,5,6};
cout<< make2_array(a,3,row_size);
return 1;
}
1.13
#include<iostream>
using namespace std;
template<class T>
T*
change_Length(T *a,int newLength,int oldlength){
if(newLength <=oldlength)
return NULL;
T *newArry = new T [newLength];
for(int i=0; i<oldlength;i++){
newArry[i] = a[i];
}
delete [] a; //
return newArry;
}
int main(){
int a[]{1,2,4,5,6};
int oldlength = sizeof(a)/sizeof (a[0]);
int * newp = change_Length(a,10,oldlength);
cout << "new array size is: "<< sizeof(sizeof(a)/sizeof (a[0]))<<'\n'<< newp[2];
return 0;
}
1.14
注意: 为数组声明空间时 new 后面的无名数组的 数组名类型必须与 初始化的对象一致
如
int ** a = new int *[];
//int *[] 是个无名数组 ,数组名类型为 int** 与 a一致 可以赋值
#include<iostream>
using namespace std;
template<class T >
T**
changeLength_2D(T ** &array,int row,int col,int oldRow,int oldCol){
T ** newRow= new T * [row];
for(int i=0;i <col ;i++){
newRow[i]= new T[col];
} //init
for (int i=0;i<oldRow;i++){
for(int j = 0;j<oldCol;j++){
newRow[i][j]= array[i][j];
delete [] array[i];
}
}
delete [] array;
return newRow;
}
int main(){
int **a = new int *[3];
for( int i=0;i<3;i++){
a[i] = new int [5];
}
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
a[i][j]=666;
}
}
int ** new_a= changeLength_2D(a,10,10,3,5);
new_a[9][9]=999;
cout<< new_a[2][3]<<' '<<new_a[9][9];
return 0;
}
1.15
[-max_number / 101 ,+max_number/101]
(不确定 dollar *100 + cents <= max number)
1.16
(转换出现了问题)
#include<iostream>
using namespace std;
enum signType{plus,minus};
class currency{
public:
currency (signType theSign= signType::plus,unsigned long theDollars=0,unsigned int theCents = 0); //构造函数 外部定义 诺省初始值--> 则按此默认给
~currency(){};//析构函数 为空
void setValue(signType,unsigned long,unsigned int ); //原型 定义在class 外部
currency add(const currency&) const; //此const表示 不改变参数的内容
void output() const;
void input(); //(1)
double subtract(double x);//(2)
currency percent(double x);//3
currency mulitiply(double x);
currency div(double x);
private : //只能通过成员函数访问 不能对象私自 访问
signType sign;
unsigned long dollars;
unsigned int cents;
}; //最后也要加分号
currency::currency (signType theSign,unsigned long theDollars,unsigned int theCents){
setValue(theSign,theDollars,theCents);
}
void currency::setValue(signType Sign,unsigned long Dollars,unsigned Cents){ // 如显示初始化对象 ,则调用此 64row
//给调用对象 的成员赋值
if(Cents >99){
throw "Max of Cents";
}
sign = Sign; //没用 . 就代表 访问 调用对象的成员
dollars = Dollars;
cents = Cents;
}
currency currency::add(const currency & x) const{
currency result;
long a1,a2,a3;
a1=dollars*100 + cents; //a1 调用对象的 转换为数字值
if(sign ==signType:: minus)
a1 = -a1;
a2 = x.dollars*100 +x.cents; // a2 代表形参传进来的对象
if(x.sign == signType:: minus)
a2= -a2;
a3= a1+a2;
if(a3<0){
result.sign =signType:: minus;
a3 = -a3;
}
else result.sign = signType::plus;
result.dollars = a3/100;
result.cents = a3-result.dollars*100;
return result;
}
void currency::output() const{
if(sign == signType::minus)
cout<<'-';
cout<< dollars
<< '.'
<< cents <<'\n';
}
void currency::input(){
double temp;
cin>> temp;
temp *=100;
if(temp <0){
sign = signType::minus;
temp = -temp;
}
else sign =signType:: plus;
dollars =(unsigned long)temp/100;
if(temp <0){
cents = (unsigned) (temp-0.01 -dollars*100);
}
else cents = (unsigned)(temp+0.01 - dollars*100);
}
double currency::subtract(double x){
double temp = dollars*100+cents ;
return temp/100 -x;
}
currency currency:: percent(double x){
currency result;
double temp = dollars*100+cents ;
temp =temp* (x/100);
result.dollars = temp /100;
result.cents = temp -dollars*100;
return result;
}
currency currency:: mulitiply(double x){
double temp= (dollars*100+cents )/100;
temp *=x;
currency result;
result.dollars = temp;
if(temp <0){
result. cents = (unsigned) (temp-0.01 -dollars*100);
}
else result. cents = (unsigned)(temp+0.01 - dollars*100);
return result ;
}
currency currency:: div(double x){
double temp= (dollars*100+cents )/100;
temp /=x;
currency result;
result.dollars = temp;
result.cents = (temp-dollars)*100;
return result ;
}
int main(){
currency a(signType::plus,3,22),b(signType ::minus,2,22);
a.input();
a.output();
a.div(10).output();
a.mulitiply(5).output();
//cout<< a.subtract(2.9)<<'\n';
// a.percent(10).output(); //不知道小数为啥不对
return 0;
}
1.17
一样的(只是换成了一个总额 amount 无需dollars 和cents
见 1.18
1.18
#include<iostream>
using namespace std;
enum signType{plus,minus};
class currency{
public:
currency (signType theSign= signType::plus,unsigned long theDollars=0,unsigned int theCents = 0); //构造函数 外部定义 诺省初始值--> 则按此默认给
~currency(){};//析构函数 为空
void setValue(signType,unsigned long,unsigned int ); //原型 定义在class 外部
currency add(const currency&) const; //此const表示 不改变参数的内容
void output() const;
void input();
double subtract(double x);
currency percent(double x);
currency mulitiply(double x);
currency div(double x);
//--------符号函数
currency operator-(currency &) ; //(1)
currency operator%(currency &);
currency operator*(currency&);
currency operator/(currency&);
friend istream& operator>>(istream&, currency &); // 友元 不是成员函数也能访问
friend ostream& operator<<(ostream&, const currency &) ;
private : //只能通过成员函数访问 不能对象私自 访问
long amount;
}; //最后也要加分号
currency::currency (signType theSign,unsigned long theDollars,unsigned int theCents){
setValue(theSign,theDollars,theCents);
}
void currency::setValue(signType Sign,unsigned long Dollars,unsigned Cents){ // 如显示初始化对象 ,则调用此 64row
//给调用对象 的成员赋值
if(Cents >99){
throw "Max of Cents";
}
amount = Dollars*100+ Cents;
if(Sign== signType::minus)
amount = -amount;
}
currency currency::operator-(currency &x) {
currency result;
result.amount = amount-x.amount;
return result;
}
istream& operator>>(istream &in ,currency &x){ // 友元不是成员函数!! 不用加::
long temp;
in>>temp ;
x.amount = temp*100;
return in;
}
ostream& operator<<(ostream& out,const currency &x) {
long theA=x.amount;
if(theA <0){
out<<'-';
theA = -theA;
}
out<<theA/100<<'.'<<theA-theA/100;
return out;
}
currency currency::operator%(currency &x){
currency result ;
result.amount = amount%x.amount;
return result;
}
currency currency::operator*(currency &x){
currency result;
result.amount = amount*x.amount;
return result;
}
currency currency::operator/(currency &x){
currency result;
result.amount = amount/x.amount;
return result;
}
int main(){
currency a,b;
cin>>a>>b;
cout<<a-b;
return 0;
}
1.19
#include<iostream>
using namespace std;
int factorial(int n){
int result=1;
while(n>0){
result *=n--;
}
return result;
}
int main(){
cout<<factorial(5);
return 0;
}
1.20
#include<iostream>
using namespace std;
int count;
int Fibonacci(int n){
int f;
::count++;
if(n==0)
return 0;
else if(n==1||n==2)
f=1;
else
f=Fibonacci(n-1)+Fibonacci(n-2);
return f;
}
int fib(int n){
if(n <=2){
return 1;
}
int f,f1=1,f2=1;
while(n>2){
f=f1+f2;
f2=f1;
f1=f;
n--;
}
return f;
}
int main(){
cout<< Fibonacci(5)<<' '<< ::count <<'\n'<<fib(5);
return 0;
}
1.21
#include<iostream>
using namespace std;
int fun1(int n){
if(n%2 ==0)
return n/2;
else
return fun1(3*n+1);
}
int fun2(int n){
if(n%2 == 0)
return n/2;
else
return (3*n+1)/2;
}
int main(){
cout<< fun1(3)<<'\n'<<fun2(3);
return 0;
}
1.22
#include<iostream>
#include<math.h>
using namespace std;
int Ack(int i,int j){
if(i ==1&& j>=1){
return pow(2,j);
}
else if( i>=2 && j==1)
Ack(i-1,2);
else if(i>=2 && j>=2)
Ack(i-1,(Ack(i,j-1)) ) ;
else return 0;
}
int main(){
cout<<Ack(2,2);
return 0;
}
1.23
证明:Fibonacci 数列及其计算方法_Ivan 的专栏-CSDN博客_fibonacci数列
#include<iostream>
using namespace std;
int Gcd(int x,int y){
if(y == 0)
return x;
return Gcd(y,x%y);
}
int main(){
cout<<Gcd(112,42);
return 0;
}
1.24
#include<iostream>
using namespace std;
template<class T>
bool
fun(T* array,T value,int end){
for( int i=0;i<end;i++){
if(array[i]== value)
return true;
}
return false;
}
int main(){
int array[]{25,78,0,666};
cout<<fun(array,666,4);
return 0;
}
1.25
类似二叉树分支
#include<iostream>
using namespace std;
void Subset(char a[], int n, int len) {
if (n == 0) { // 递归终止条件
for (int i = 0; i < len; i++) cout << a[i];
cout << endl;
delete[] a; // 这里的a 就是temp
return;
}
for (int j = 0; j <= 1; j++) { //每次需要做两种决策
char *temp = new char[len];
for (int i = 0; i < len; i++) temp[i] = a[i]; //用临时数组来覆盖原来数组
if (j == 0) {
temp[n - 1] = '0';
}else {
temp[n - 1] = '1';
}
Subset(temp, n - 1,len);
}
}
int main()
{
char a[3] = { 'a','b','c'};
Subset(a, 3,3);
return 0;
}
1.26
#include<iostream>
using namespace std;
void
GrayCode(int n){
if(1== n)
cout<<1;
else {
GrayCode(n-1);
cout<<n;
GrayCode(n-1);
}
}
int main(){
GrayCode(4);
return 0;
}
1.27
#include<iostream>
using namespace std;
template <class T>
int
accumulate(T array,int end,int value){
for(int i =0;i<end ;i++){
value+=array[i];
}
return value;
}
int main(){
int a[]={1,2,5,3,8};
cout<< accumulate(a,5,0);
return 0;
}
1.28
#include<iostream>
using namespace std;
template<class T,class funP>
int
accumulate(T array,int end ,int result,funP p){
for(int i=0; i<end;i++){
result *= p(array,i);
}
return result;
}
int
get_value(int *array,int i){
return array[i];
}
int main(){
int array[]={1,5,10,8};
cout<< accumulate(array,4,1,get_value);
return 0;
}
1.29
#include<iostream>
using namespace std;
template<class T>
bool
Copy(T a,int n,T b){
for(int i= 0;i<n;i++){
b[i]= a[i];
}
return true;
}
int main(){
int a[]= {1,5,7,9,10};
int b[10];
if( Copy(a,5,b) )
cout<< b[4];
return 0;
}
1.30
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int a[]={1,2,10};
sort(a,a+3); //无回调函数 默认升序
do{
cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
}while(next_permutation(a,a+3));// next 初始值之后的全排列
return 0;
}
1.31
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int a[]={2,3,1};
cout << "next is:"<<endl ;
do{
cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
}while(next_permutation(a,a+3));// next 初始值之后的全排列
cout<< "pre is"<<endl;
a[0]=2;
a[1]=3;
a[2]=1;//恢复初始值
do{
cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
}while(prev_permutation(a,a+3));
return 0;
}
1.32
#include<iostream>
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int a[]={2,3,1};
while(next_permutation(a,a+3));// 直接到底
do{
cout<<a[0]<<' '<<a[1]<<' '<<a[2]<<endl;
}while(next_permutation(a,a+3));// next 初始值之后的全排列 A32
}
1.33
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
vector<int> a;
for(int i=0;i<6;i++)
{
int temp;
cin>>temp;
a.push_back(temp);
}
cout<<count(a.begin(),a.end(),6);
return 0;
}
1.34
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int a[10];
fill(a,a+10,6); //参数应是个迭代器类型(指针)
for(int i=0;i<10;i++){
cout<< a[i]<<' ';
}
cout<< endl;
return 0;
}
1.35
#include<numeric> // inner_product 在此头文件
#include<iostream>
using namespace std;
int main(){
int a[]={1,2,3,4,5,6};//内积?? 自己跟自己
cout<<inner_product(a,a+6,a,0);
return 0;
}
1.36
#include<iostream>
#include<numeric>
using namespace std;
int main(){
int a[8];
iota(a,a+8,6); //初始值 递增 !
for(int i=0;i<8;i++){
cout<<a[i]<<' ';
}
cout<<endl;
return 0;
}
1.37
#include<iostream>
#include<numeric>
using namespace std;
int main(){
int a[]={99,8,6,4,2};
cout<<is_sorted(a,a+5)<< endl; //若已经增排序 返回true
return 0;
}
1.38
pair 没学到 不太会 matching返回的是什么?
#include<iostream>
#include<algorithm>
#include <utility>
using namespace std;
int main(){
int a[]={1,2,3,4,5,6};
int b[]={1,2,3,4,5,999};
pair<int *,int *> result;
result = mismatch(a,a+6,b); //返回不相等的两个元素??
cout<< *result.first<<' '<<*result.second;
return 0;
}
1.39
#include<iostream>
using namespace std;
template <class T>
int
STL_count(T start, T end,int value){
int result =0;
for( int i=0; start+i<end;i++){
if(value == start[i])
result++;
}
return result;
}
int main(){
int a[]{2,5,7,8,666,8};
cout<<STL_count(a,a+6,8);
return 0;
}
1.40
#include<iostream>
using namespace std;
template<class T>
void
STL_fill(T *start,T* end,T value){
for(int i =0; start+i<end;i++){
start[i]= value;
}
}
int main(){
int a[9];
STL_fill(a,a+9,6);
for(int i =0;i<9;i++){
cout<<a[i];
}
}
1.41
#include<iostream>
using namespace std;
template<class T>
T
inner(T *start,T *end,T* start1,T *end1){
int i=0;
int result =0;
while( start+i<end && start1+i <end1){
result = result + start[i]*start1[i];
i++;
}
return result;
}
int main(){
int a[]{1,2,4,5,6};
int b[]{1,2,3};
cout<< inner(a,a+5,b,b+3);
return 0;
}
1.42
#include<iostream>
using namespace std;
template<class T>
void
ioat(T *start,T *end,T value){
for(int i=0;start+i<end;i++){
start[i]=value++;
}
}
int main(){
int a[10];
ioat(a,a+10,10);
for(int i=0;i<10;i++)
cout<< a[i]<<' ';
return 0;
}
1.43
#include<iostream>
using namespace std;
template<class T>
bool
is_sorted(T start,T end){
int i=0;
while(start+i<end-1){
if(start[i]>start[i+1])
return false;
i++;
}
return true;
}
int main(){
int a[]{1,2,5,8,999};
cout<< is_sorted(a,a+5);
return 0;
}
1.44
#include<iostream>//错的 待改
using namespace std;
template<class T>
// 该返回什么????
mismatch(T strart,T end,T strart1){
int i=0;
while(strart+i<end){
if(strart[i] != strart1[i] )
return [strart[i],strart1[i]];
i++;
}
return nullptr;
}
int main(){
int a[]={1,2,3,4,5,6};
int b[]={1,2,3,4,5,999};
pair<int *,int *> result;
result = mismatch(a,a+6,b); //返回不相等的两个元素??
cout<< *result.first<<' '<<*result.second;
return 0;
}
1.45
因为每一条语句 本身就是从句(无再细分布尔式)
1.46
{a,3}
a={2,4,1}
1.47
两条 : 1 2 3? 4
1.48
n条执行路径(当n固定时 步骤也是固定的 ,递归)
执行的语句条数为 2N+2
第一章总结:
c++部分 :
函数传参:
a 传值
b 传引用 (与指针一样都要临时变量空间
c 传指针
模板参数:
template <class T ,...>
函数体
异常 :
throw
try{}
catch()
动态分配:
new
delete
自定义类class
构造函数
析构函数
方法
符号重载
友元(不算成员函数
递归
归纳
-->基础表达式
STL (重点
自带的算法
测试与调试
重点:测试的目的是为了暴露程序的错误,而不是证明是否正确
测试集 :
黑盒 : 分结果种类
白盒:
语句覆盖:每条语句至少执行一次
分支覆盖 :程序的每个条件都分别去true 和 false
从句覆盖: 最小子单元的判断-->从句
执行路径覆盖: 有可能走的路径 都要经过 ?
边界测试:如数组边界时
调试:
逻辑推理
必要时重新设计
增量测试
第二章(时间/空间复杂度)
2.1
有更多的空间留作他用
模拟计算程序最大的规模
2.2
省钱
有更大市场
2.3
都有可能
2.4
硬件/编译器/优化/使用的语言
2.5
24 4k 8k 2w 24 324
2.6
12* MAX[n-1,1]
2.7
非递归n! S= 0
1-29 为8N
时间
2.8
v=v*2+C(n-i)
2.9
r= [2,1,5,4,8]
2.10-2.17
略 自己画图很简单
2.18
2n
2.19
n-1次
2.20
a={5,4,3,2,1}.
只要使a[i] != r[i] 即可
2.21
(row-1)的平方
2.22
就是swap的频率
row*(row-1)/2
2.23
n的三次方
2.24
n*p*m
2.25
2* {(m-k+1)k[1,m]的连加}
2.26
2*(n-1).
n-1
下一个性能更好
2.27
n+1
2n+1
2.29
#include<iostream>
using namespace std;
void
fun(int *x,int n){
int count =0;
count++ ;
for(int i=0;i<n;i++){
count ++;
x[i]+=2;
}
int i=1; count++;
count ++;
while(i<n/2){
x[i] += x[i+1];
i++;
count +=2;
}
cout<< count <<endl;
}
void
fun1(int *x,int n){
int count =0;
count++ ;
for(int i=0;i<n;i++){
count ++;
}
int i = 1; count++;
count ++;
while(i<n/2){
i++;
count +=2;
}
cout<< count<<endl;
}
int main(){
int a[]={1,2,43,57,4};
fun(a,5);
fun1(a,5);
}
2.30
(1)- (8) 略
(9 :
最坏: 2n+4
(10:
最好 :n
最坏: 3n+n*(n-1)/2 -2
(11:
最好 :3n+1
最坏: 3n(n-1)/2 +n+1
(12:
调用函数步数都是一样的 ,关键看被调用里面的函数步数
最好: n+n-1+ (n+3) n=[1,n-1]的累加
最坏: n+n-1+ (2n+3) n=[1,n-1]的累加
(13:
最坏:
n+2(n-1)+(2+n)(n-1)-1+(n-1)
(14:
(2n-1) n=【2,n】 的累加
(15:
(4n-1)n=【2,n】 的累加
1.31
略
1.32
1):
(3n+3)/2
2):
(2n+6)/2
3):
(3n+8)/2
1.33
条件一样时可以交换??
1.34
2-12: 3/2 *n的平方-1/n-1
2-15: n方+5n-7
2-13: 2*n方+n-3
最坏应该冒泡比较好?
1.35
不一定吧,因为内存S(q)可能跟特征值没关系
1.36
技巧:算出n不是非基础部分的次数 ,最后一次就是基础部分
1) 【n,1】 共n次非基础部分 2*n + 基础部分 2
--> 总 2n+2
2) (n-1)/2 +1
3) 2n n[1,n]的累加
4) 2的n-1次方 +1
5) 3的n-1次方+1
第二章总结:
分为 空间复杂度和时间复杂度
空间:(变量,常量,返回地址等)
C+S(n) : 其中s(n) 是可变的 -->实列特征
与多种可能有关
时间:
编译时间+ 运行时间
因为编译时间不受实列特征影响,所以我们注重运行时间 !
运行时间:
a 找出关键操作(加法,乘法次数
b 确定总步数 (包括调用,递归等)
B步数:
分为最好情况和最坏情况
平均 == (最坏+最好)/2 因为每一个概率都相等
步数方法:
1 变量法 设置全局变量写进代码 来++
2 剖析法:
确定每一条语句的步数 *频率
小技巧::
for循环时 :
for本身次数 : 如果有边界 [ a,b ) 为b-a+1
如果没有边界 [a,b] 为a-b+2
进入for的次数: 为for本身次数-1
递归时:
如果非基础部分易看 , 可以分析出进行非基础部分递归的次数
然后加以条件 再加基础部分
补充: 新算法排序(名次排序) new rank数组 --> 记录下标元素比原数组小的数 +本数左边与其相等的数 。 rank数组的值 就应该是对应的位置 a[r[0]]= a[0]
第三章
3.1
统一 p(n)/q(n) ,因为最高次不一样 就会趋于0
证明完成
3.2
O(). 取最大次项 ,再将系数化为1即可
3.3
3n+7<3n+n=4n 当c= 8 时 使得g(n) 大于f(n)
所以f(n) = O(n).
其他一样证
3.4
一样 ,取最大项
3.5
g(n) / f(n) 看是否趋于 0即可
或推导 >= 都 c n0
3.6
最大次项
3.7
Ω(n) <= f(n) <= O(n)
直接找
3.8
因为多元 :
小技巧: 如果一个式子是因式,则直接消除
如 3mn^2+7m^2n+4mn+8m+2n+16
-->后四项都是前面的因式
--> =O(mn^2+m^2)
渐进数学: 难死了 数学还是重要
3.9
找 n0 c 推出
3.10
用两式子相除,得到大于 >=(<=) C
注意:Θ 要两边除 得到两边边界。
3.11
用定理或定义 推出正确结果
3.12
还真不会 应该是:
大于等于 (每次少最小一项 ) -->
最后>= an^m
3.13
反证? 存在 m<n0 使得 g(n) <= c[1,c0]*f(n)
3.14
反过来不知道怎么证, 后条件只能证明 g(n) 是f(n) 的上界呀 ,
怎么证明f(n)一定渐进小于g(n) ,不包括等于的情况
3.15
纯数学求和 ,建议百度
E4,5
这个通项公式是一个非常特别的
公式为
1^k+2^k+...+n^k=((n+1+p)^(k+1)-p^(k+1))/(k+1)
我们先要求一个数字p,p满足以下规则
(1+p)^(k+1)-p^(k+1)=0这个里面首先要展开,展开后对于p,p^2 p^3等,我们要当成一个整体对待,比
E6
最大次
E7
放缩法
E8
lim[1/(n+1)+1/(n+2)+......+1/(n+n)]=lim(1/n)[1/(1+1/n)+1/(1+2/n)+......+1/(1+n/n)]=定积分(上限1,下限0)[1/(1+x)]dx=ln(1+x)(上限1,下限0)=ln(1+1)-ln(1+0)=ln2.
3.16
只可意会不可言传
3.17
还真不会
不过应该往松条件取
3.18
1) Θ (n)
Θ (n)
Θ (n)
Θ (n^2)
Θ (n^3)
Θ (m*p*n)
Θ (n)
Θ (n)
Θ (n)
10) Θ (n^2)
Θ (n*n!)
Θ (n^2)
Ω(n). O(n^2)
Θ (n^2)
Ω(n). O(n^2)
Θ (n^2)
17). Ω(n). O(n^2)
3.19
1) n>100
2) n>2
3) n<10
4) 带数测试 n[2^13,2^14] 中间取到相等
3.20
略 ,乘上倍数就行了
3.21
n不同 t(n) 的规模也不同。
以n== 100 为例子 n的最高次每增加一次 效率是1/100 倍 然后根据x的增加 比较一下即可
第三章总结:
渐进记忆法:
1 O(n) 最小上界
2 Ω(n) 最大下届
3 Θ(n) f的上界和下界都是同一个函数的情况 ,C可以不同
4 o(n) 小于上界, f(n) 一定渐进小于 cg(n),不包括等于
1:
定义: 存在 C,n0 ,使得 n>n0 时 f(n) <= C*g(n)
a: g(n) 的类型就是我们通常算时间复杂度的函数类型(如对数阶
b: 可以通过找C ,g(n) 来确定O(n).
c: 通常找最小上界,才有实际意义
定理:
f(n) = O(最高次的项)
f(n)/g(n) <= C 当且仅当 f(n) = O(g(n) )
2.
定义: 存在 C,n0 ,使得 n>n0 时 f(n) >= C*g(n)
a: 这就是下界 ,f(n) 一定渐进大于或等于 cg(n)
b:通常最大下届取
定理:
f(n) = O(最高次的项)
f(n)/g(n) >= C 当且仅当 f(n) =Ω (g(n) )
3.
定义 : 存在 c1,c2,n0 ,使得n>n0时 c1*g(n) <= f(n) <= c2*g(n)
定理:
f(n) = O(最高次的项)
假设f(n) 和g(n) 都有极限 f(n)/g(n) 和 g(n)/f(n) 存在 , 当且仅当
f(n)/g(n)<=c 以及 g(n)/f(n)<= c 存在
4.
严格小于c*g(n)
另外:也可以推广到多元函数 :
任意一元趋于无穷 ,两函数比例为无穷 且 另一元趋于无穷,两函数比例为0
第四章
测试模板::
#include<iostream>
#include<time.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
int main(){
int a[MAX_];
int step =10;
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//初始化数组for
//...调用函数
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<endl;
if(n==100)
step =100;
}
return 0;
}
但是n到不了1000 会溢出 不知道怎么办
4.1
因为没有除以 clocksPerMillis ,代表一毫秒
4.2
#include<iostream>
#include<time.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
void insertionSort(T *a,int n){
for(int i=1;i<n;i++){
T t=a[i];
int j;
for( j=i-1;j>=0 && t<a[j];j--)
a[j+i]=a[j];
a[j+i]= t;
}
}
int main(){
int a[MAX_];
int step =10;
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//初始化数组for
for(int i=0;i<MAX_;i++)
a[i]=100-i;//逆序 也可以顺序就是最好情况
//...调用函数
insertionSort(a,n);
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<endl;
if(n==100)
step =100;
}
return 0;
}
可以看到如果是最好情况,是线性增长的 说明O(n)
最坏:不是线性的 n不够大导致不是很明显 O(n^2)
所以2-15的程序好一点 ,最好情况是n 而2-14 都是n^2
4.3
#include<iostream>
#include<time.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
void
bubbleSort1(T *a,int n){
for(int i=n;i>1;i--){
for(int j=0;j<n-1;j++)
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}
template<class T>
void
bubbleSort2(T *a,int n){
bool swapped = true;
for(int i=n;i>1 &&swapped ;i--){
swapped = false;
for(int j=0;j<i;j++)
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
swapped = true;
}
}
}
int main(){
int a[MAX_];
int step =10;
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//初始化数组for
for(int i=0;i<MAX_;i++)
a[i]=100-i;
//...调用函数
bubbleSort1(a,n);
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
clock_t startTime2= clock();
do{
bubbleSort2(a,n);
}while (clock()- startTime2 <1000);
long double elapsedMillis2= (clock()-startTime2)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<' '
<<elapsedMillis2/numberRepetitions
<<endl;
if(n==100)
step =100;
}
return 0;
}
可以看到结果
说明最坏情况下(逆序,每两个比较都要交换) 性能基本一致
4.4/5
略 思路基本一致
4.6
正确形式应该如4.7
#include<iostream>
#include<time.h>
#include<stdlib.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
void insertionSort(T *a,int n){
for(int i=1;i<n;i++){
T t=a[i];
int j;
for( j=i-1;j>=0 && t<a[j];j--)
a[j+i]=a[j];
a[j+i]= t;
}
}
int main(){
time_t t;
srand(time(&t));//时间作为随机数种子
int a[MAX_];
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<10;n++){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
for(int i=0;i<MAX_;i++)
a[i]=rand()%65535; //每一次循环产生随机数列
do{
numberRepetitions++;
insertionSort(a,n);
}while (clock()- startTime <10);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<endl;
}
return 0;
}
固定排列数为1k 结果:
感觉平均时间是O(n)
4.7
#include<iostream>
#include<time.h>
#include<stdlib.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
void
bubbleSort1(T *a,int n){
for(int i=n;i>1;i--){
for(int j=0;j<n-1;j++)
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}
template<class T>
void
bubbleSort2(T *a,int n){
bool swapped = true;
for(int i=n;i>1 &&swapped ;i--){
swapped = false;
for(int j=0;j<i;j++)
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
swapped = true;
}
}
}
int main(){
int a[MAX_];
int step =10;
time_t t;
srand((unsigned)time(&t));
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
int count =0;
while(count<20){
for(int i=0;i<MAX_;i++)
a[i]= rand()%65535;
for(int n=0;n<= MAX_;n+= 200){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//...调用函数
bubbleSort1(a,n);
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
clock_t startTime2= clock();
do{
bubbleSort2(a,n);
}while (clock()- startTime2 <1000);
long double elapsedMillis2= (clock()-startTime2)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<' '
<<elapsedMillis2/numberRepetitions
<<endl;
}
cout<<"new rand row:"<<endl;
count++;
}
return 0;
}
结果:
明显终止冒泡平均优于普通的
4.8/9
略 思路一样
4.10
#include<iostream>
#include<time.h>
#include<stdlib.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
int
sequntialSearch(int *a,int n,const T& x){
int i;
for(i=0;i<n&& a[i]!=x;i++)
;
if(i==n) return -1;
else return i;
}
template<class T>
int
binarySearch(T *a,int n,const T&x){
int left =0;
int right=n-1;
while(left <=right){
int mid= (left+right)/2;
if(x== a[mid]) return mid;
if( x>a[mid]) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
int a[MAX_];
for(int i=0;i<MAX_;i++)
a[i]= i;
time_t t;
srand((unsigned)time(&t));
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
int count =0;
while(count<20){
int temp= rand()%MAX_;//使每个被查找概率相等
long numberRepetitions =0;
long number2=0;
clock_t startTime= clock();
do{
numberRepetitions++;
sequntialSearch(a,MAX_,temp);
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
clock_t startTime2= clock();
do{
number2++;
binarySearch(a,MAX_,temp);
}while (clock()- startTime2 <1000);
long double elapsedMillis2= (clock()-startTime2)/clocksPerMillis;
cout<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<' '
<<number2<<' '
<<elapsedMillis2/number2
<<endl;
cout<<"new rand row:"<<endl;
count++;
}
return 0;
}
结果:
折半查找明显好于 顺序查找!
4.11
最坏情况:查找元素为最后一个
#include<iostream>
#include<time.h>
#include<stdlib.h>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
int
sequntialSearch(int *a,int n,const T& x){
int i;
for(i=0;i<n&& a[i]!=x;i++)
;
if(i==n) return -1;
else return i;
}
template<class T>
int
binarySearch(T *a,int n,const T&x){
int left =0;
int right=n-1;
while(left <=right){
int mid= (left+right)/2;
if(x== a[mid]) return mid;
if( x>a[mid]) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
int a[MAX_];
for(int i=0;i<MAX_;i++)
a[i]= i;
time_t t;
srand((unsigned)time(&t));
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
int count =0;
long numberRepetitions =0;
long number2=0;
clock_t startTime= clock();
do{
numberRepetitions++;
sequntialSearch(a,MAX_,999);//最后一个时为最坏
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
clock_t startTime2= clock();
do{
number2++;
binarySearch(a,MAX_,999);
}while (clock()- startTime2 <1000);
long double elapsedMillis2= (clock()-startTime2)/clocksPerMillis;
cout<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<' '
<<number2<<' '
<<elapsedMillis2/number2
<<endl;
return 0;
}
结果:
高下立判
4.12
略
4.13
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<algorithm>
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template<class T>
void insertionSort(T *a,int n){
for(int i=1;i<n;i++){
T t=a[i];
int j;
for( j=i-1;j>=0 && t<a[j];j--)
a[j+i]=a[j];
a[j+i]= t;
}
}
int main(){
int a[MAX_];
int step =10;
time_t t;
srand((unsigned)time(&t));
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
int count =0;
//初始化数组 (最好 or最坏
for(int i=0;i<MAX_;i++)
a[i]= i;
for(int n=0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//...调用函数
insertionSort(a,n);
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
clock_t startTime2= clock();
do{
sort(a,a+n);
}while (clock()- startTime2 <1000);
long double elapsedMillis2= (clock()-startTime2)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<<' '
<<elapsedMillis2/numberRepetitions
<<endl;
if(100 == n)
step =100;
}
return 0;
}
最好结果:
最坏结果:
感觉两个运行时间差不多,性能差不多?
4.14/15
略
4.16
略
4.17
#include<iostream>
#include<algorithm>
using namespace std;
void
TransposeMatri(int **array,int n){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(j>i)//主副三角
swap(array[i][j],array[j][i]);
}
}
void
matrixMultiplication(int **a,int **b,int **c,int n){
TransposeMatri(b,n);//先转置
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
int sum =0;
for(int k=0;k<n;k++)
sum+=a[i][k]* b[j][k];//4.2公式
c[i][j]= sum;
}
}
int main(){
int **a= new int *[2];
for(int i=0;i<2;i++)
a[i]=new int [2];
a[0][0]=1; a[0][1]=2;a[1][0]=3;a[1][1]=4;
int **b= new int *[2];
for(int i=0;i<2;i++)
b[i]=new int [2];
b[0][0]=1; b[0][1]=2;b[1][0]=3;b[1][1]=4;
int **c= new int *[2];
for(int i=0;i<2;i++)
c[i]=new int [2];
matrixMultiplication(a,b,c,2);
for(int i=0;i<2;i++){
for(int j=0;j<2;j++)
cout<<c[i][j]<<' ';
cout<<endl;
}
return 0;
}
4.18
(1条消息) C++性能优化系列——矩阵转置(二)循环分块优化缓存访问_yan31415的博客-CSDN博客
自己写的有误,最远处的对角并没有互换,思路错了
#include <algorithm>
#include <iostream>
using namespace std;
void TransposeMatri(int **array, int n) { //全部转置
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) {
if(j > i) //主副三角
//swap(array[i][j], array[j][i]);
swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
}
}
void Block_transpose(int **array, int n) { //分块转置
/*
int k = 2;
for(int i = 0; i < n; i += k)
for(int j = 0; j < n; j += k)
TransposeMatri((int **)((int *)array + i * n + j), k);
*/
int k = 2;
for(int i = 0; i < n; i += k)
for(int j = 0; j < n; j += k) {
int a[k][k];
for(int y = 0; y < k; ++y) {
for(int x = 0; x < k; ++x) {
a[y][x] = (*(int (*)[n][n])array)[i + y][j + x];
}
}
//TransposeMatri((int **)((int *)array + i * n + j), k);
TransposeMatri((int **)a, k);
for(int y = 0; y < k;