目录
根据主定理有

【子问题平衡原理】划分规模:等长>不等长规模



只剩一个数据时 max=x[low]
对元素进行分组,中间下标mid=(low+high)/2,递归使用findmax(x,low,mid,tempmax1) ,findmax(x,mid+1,high,tempmax2) 返回两区间最大值tempmax1 和tempmax2
最大值为tempmax1 和tempmax2 的较大值,
T(n) = 2*T(n/2) + 5; n>1
T(n)=O(1) ;n=1
设a=2 b=2 f(n)=5=n^(log_2 2-1)=O(1)
根据主定理 T(n)=O(n)
- #include
- #include
- using namespace std;
-
- void findmax(int x[],int low,int high,int &max)
- {
- int tempmax1=0,tempmax2=0;
- if(low==high)
- {
- max = x[low] ;
- return ;
- }
- int mid=(low+high)/2;
- findmax(x,low,mid,tempmax1);
- findmax(x,mid+1,high,tempmax2);
- if(tempmax2< tempmax1)max=tempmax1;
- else max=tempmax2;
- }
-
- int main()
- {
- int n=10;
- int x[n];
- for(int i=0;i
- {
- x[i]=30+rand()%10;
- cout<
" "; - }
- int max=0;
- findmax(x,0,n-1,max);
- cout<
-
- return 0;
- }
分治*大数乘法:
【例5-2】设X, Y是两个n位的十进制数,求X*Y

问题分析:
1.1 计算方法:

1.2 时间复杂度:


2.1 计算方法:

2.2 时间复杂度:


计算模型
(1) 计算公式

(2)递归结束条件
当x=0或y=0时,结果为0。
当n=1时,返回x*y 。
思考题:
算法描述
输入:两个n位十进制数x,y
核心操作:三个乘法
时间复杂度:T(n)=3*T(n/2)+c*n
设a=3,b=2 ,f(n)=cn,
,
有f(n)=
取
=log_2 3/2 >0 符合主定理(1),因此

算法分析:
算法设计与描述 算法分析 输入:两个n位十进制数 输出:乘积 Karatsuba(x,y)
{
if(x==0||y==0)return 0;
if(n==1)return x*y;
n<- n/2;
x1<- x / (int)pow(10,n) ,x0<- x % (int)pow(10,n);
y1<- y/ (int)pow(10,n),y0<- y % (int)pow(10,n);
//计算
xy1<- Karatsuba(x1,y1);
xy0<- Karatsuba(x0,y0);
sum<- (x1-x0)*(y0-y1);
return xy1*pow(10,(2*half) ) + (sum+xy1+xy0)*pow(10,half) +xy0;
} (1)输入两个n位十进制数,
(2)核心语句:将两数分为前后两部分x1 x0 y1 y0,递归计算
(3)
时间复杂度:T(n)=3*T(n/2)+c*n
设a=3,b=2 ,f(n)=cn,
,
有f(n)=
取
=log_2 3/2 >0 符合主定理(1),因此

代码:
- #include<bits/stdc++.h>
- using namespace std;
- /*
- unsigned int 0~4294967295
- int -2147483648~2147483647
- unsigned long 0~4294967295
- long -2147483648~2147483647
- long long的最大值:9223372036854775807
- long long的最小值:-9223372036854775808
- unsigned long long的最大值:18446744073709551615
-
- __int64的最大值:9223372036854775807
- __int64的最小值:-9223372036854775808
- unsigned __int64的最大值:18446744073709551615
- */
-
-
- //Karatsuba方法 将大数拆分 两数位数相同
- //分治
- long long Karatsuba(long long num1,long long num2)
- {
- // cout<<num1<<" "<<num2<<endl;
- if(num1<10 ||num2<10)return num1*num2;
- int size1=ceil(log(num1)/log(10));//位数
- int size2=ceil(log(num2)/log(10));
- int half=max(size1,size2)/2;
- // cout<<size1<<" h "<<half<<endl;
- //拆分为 abcd
- long long x1=num1 / (int)pow(10,half) ,x0= num1 % (int)pow(10,half);
- long long y1=num2/ (int)pow(10,half),y0=num2 % (int)pow(10,half);
- // cout<<x1<<" "<<x0<<endl;
- //计算
- long long xy1=Karatsuba(x1,y1);
- long long xy0=Karatsuba(x0,y0);
- long long sum= (x1-x0)*(y0-y1);
- // cout<<pow(10,5)<<endl;
- return xy1*pow(10,(2*half) ) + (sum+xy1+xy0)*pow(10,half) +xy0;
- }
-
- int main()
- {
- cout<<endl<<"Karatsuba:"<<Karatsuba(155,999);//但是要注意 long long的数字限制
-
- return 0;
- }
-
-
思考题:二分治法 和 VS算法 矩阵相乘

算法效率:
普通的二分治算法:
T(n)=O(1) n=2
T(n)=8*T(n/2)+
(n^2) n>2
设a=8,b=2,f(n)=
(n^2),n^(log_2 8 -1)=n^2.
有f(n)=
(log_2 8 -1)=
(n^2) 取
=1>0
根据主定理 T(n)=
(n^3)
VS算法:【8次->7次乘法 m不唯一,但也增加了加法运算量】
T(n)=O(1) n=2
T(n)=7*T(n/2)+
(n^2)
设a=7,b=2,f(n)=
(n^2),n^(log_2 7 -1)=n^2.
有f(n)=
(log_2 7 -0.8)=
(n^2) 取
=0.8>0
根据主定理 T(n)=
(n^2.8)

7个乘法,18个加法

因此VS算法比普通二分治算法效率高
代码:
- #include
- using namespace std;
-
- class Mat{
-
- public:
- int **m;
- int n;
-
- Mat(int nn){
- // cout<<"Mat:"<
- n=nn;
- m=new int*[n];
- for(int i=0;i
- {
- m[i]=new int[n];
- }
- for(int i=0;i
- {
- for(int j=0;j
- {
- m[i][j]=0;
- }
- }
- // cout<<"over"<
- }
- void input01(int** x)
- {
- int n=this->n;
- for(int i=0;i
- {
- for(int j=0;j
- {
- this->m[i][j]=x[i][j];
- }
- }
- }
- void show()
- {
- for(int i=0;i
- {
- for(int j=0;j
- {
- cout<
"\t"; - }
- cout<
- }cout<
- }
- Mat operator + (Mat &a)// 定义重载运算符"+"的友元函数
- {
- Mat c(a.n);
- for(int i=0;i
- {
- for(int j=0;j
- {
- c.m[i][j]=a.m[i][j]+this->m[i][j];
- }
- }
- return c;
- }
- Mat operator - (Mat &a)// 定义重载运算符"-"的友元函数
- {
- Mat c(a.n);
- for(int i=0;i
- {
- for(int j=0;j
- {
- c.m[i][j]=this->m[i][j] -a.m[i][j];
- }
- }
- return c;
- }
- };
- int ** change(int x[][4])
- {
- int n=4;
- // int **xx=malloc(4*sizeof(int*));
- int **xx=new int*[4];
- for(int i=0;i
- {
- xx[i]=new int[4];
- for(int j=0;j
- {
- xx[i][j]=x[i][j];
- cout<
"\t"; - }
- cout<
- }
- cout<
- return xx;
- }
-
- int a[4][4]={
- 1,0,2,1,
- 4,1,1,0,
- 0,1,3,0,
- 5,0,2,1
- };
- int **aa=change(a);
-
- int b[4][4]={
- 0,1,0,1,
- 2,1,0,4,
- 2,0,1,1,
- 1,3,5,0
- };
- int **bb=change(b);
-
- int n=4;
- Mat ma(n),mb(n),mc01(n),mc02(n);
-
- //二分治法
-
- void bs(int n,Mat a,Mat b,Mat c)
- {
- // cout<
- if(n==1)
- {
- c.m[0][0]=ma.m[0][0] * mb.m[0][0];
- // cout<<"n==1"<
- return ;
- }
- else if(n==2)
- {
- // cout<<"n==2"<
- c.m[0][0]=a.m[0][0]*b.m[0][0]+a.m[0][1]*b.m[1][0];
- c.m[0][1]=a.m[0][0]*b.m[0][1]+a.m[0][1]*b.m[1][1];
- c.m[1][0]=a.m[1][0]*b.m[0][0]+a.m[1][1]*b.m[1][0];
- c.m[1][1]=a.m[1][0]*b.m[0][1]+a.m[1][1]*b.m[1][1];
-
- // cout<<"n==2"<
- return ;
- }
- //划分为4个矩阵
-
- Mat a00(n/2),a01(n/2),a10(n/2),a11(n/2);
- Mat b00(n/2),b01(n/2),b10(n/2),b11(n/2);
- // cout<<"划分"<
- for(int i=0;i
2;++i) - {
- for(int j=0;j
2;++j) - {
- //左上
- // cout<<"左上"<
- a00.m[i][j]=a.m[i][j];
- b00.m[i][j]=b.m[i][j];
- // cout<<"右上"<
- //右上
- a01.m[i][j]=a.m[i][j+n/2];
- b01.m[i][j]=b.m[i][j+n/2];
- //左下
- a10.m[i][j]=a.m[i+n/2][j];
- b10.m[i][j]=b.m[i+n/2][j];
- //右下
- a11.m[i][j]=a.m[i+n/2][j+n/2];
- b11.m[i][j]=b.m[i+n/2][j+n/2];
-
- }
- }
- // cout<<"递归"<
- //递归求四个方阵
- Mat ab0000(n/2);
- bs(n/2,a00,b00,ab0000);
- Mat ab0110(n/2);
- bs(n/2,a01,b10,ab0110);
- Mat ab0001(n/2);
- bs(n/2,a00,b01,ab0001);
- Mat ab0111(n/2);
- bs(n/2,a01,b11,ab0111);
- Mat ab1000(n/2);
- bs(n/2,a10,b00,ab1000);
- Mat ab1110(n/2);
- bs(n/2,a11,b10,ab1110);
- Mat ab1001(n/2);
- bs(n/2,a10,b01,ab1001);
- Mat ab1111(n/2);
- bs(n/2,a11,b11,ab1111);
-
- Mat c00(n/2),c01(n/2),c10(n/2),c11(n/2);
- c00=ab0000+ab0110;
- c01=ab0001+ab0111;
- c10=ab1000+ab1110;
- c11=ab1001+ab1111;
- // c00 =m1+m4-m5+m7;
- // c01 =m3+m5;
- // c10=m2+m4;
- // c11=m1+m3-m2+m6;
-
- //合并
- for(int i=0;i
2;++i) - {
- for(int j=0;j
2;++j) - {
- c.m[i][j]=c00.m[i][j];
- c.m[i][j+n/2]=c01.m[i][j];
- c.m[i+n/2][j]=c10.m[i][j];
- c.m[i+n/2][j+n/2]=c11.m[i][j];
- }
- }
- }
-
- //VS算法
-
-
- void vs(int n,Mat a,Mat b,Mat c)
- {
- // cout<
- if(n==1)
- {
- c.m[0][0]=ma.m[0][0] * mb.m[0][0];
- // cout<<"n==1"<
- return ;
- }
- else if(n==2)
- {
- // cout<<"n==2"<
- c.m[0][0]=a.m[0][0]*b.m[0][0]+a.m[0][1]*b.m[1][0];
- c.m[0][1]=a.m[0][0]*b.m[0][1]+a.m[0][1]*b.m[1][1];
- c.m[1][0]=a.m[1][0]*b.m[0][0]+a.m[1][1]*b.m[1][0];
- c.m[1][1]=a.m[1][0]*b.m[0][1]+a.m[1][1]*b.m[1][1];
-
- // cout<<"n==2"<
- return ;
- }
- //划分为4个矩阵
-
- Mat a00(n/2),a01(n/2),a10(n/2),a11(n/2);
- Mat b00(n/2),b01(n/2),b10(n/2),b11(n/2);
- // cout<<"划分"<
- for(int i=0;i
2;++i) - {
- for(int j=0;j
2;++j) - {
- //左上
- // cout<<"左上"<
- a00.m[i][j]=a.m[i][j];
- b00.m[i][j]=b.m[i][j];
- // cout<<"右上"<
- //右上
- a01.m[i][j]=a.m[i][j+n/2];
- b01.m[i][j]=b.m[i][j+n/2];
- //左下
- a10.m[i][j]=a.m[i+n/2][j];
- b10.m[i][j]=b.m[i+n/2][j];
- //右下
- a11.m[i][j]=a.m[i+n/2][j+n/2];
- b11.m[i][j]=b.m[i+n/2][j+n/2];
-
- }
- }
- // cout<<"递归"<
- //递归求四个方阵
- int half=n/2;
- //m1=(a00+a11)*(b00+b11)
- Mat m1(n/2);
- vs(n/2,a00+a11,b00+b11,m1);
- // cout<<"m1"<
- //m2=(a10+a11)*(b00)
- Mat m2(n/2);
- vs(n/2,a10+a11,b00,m2);
- //m3=(a00)*(b01-b11)
- Mat m3(n/2);
- vs(n/2,a00,b01-b11,m3);
- //m4=(a11)*(b10-b00)
- Mat m4(n/2);
- vs(n/2,a11,b10-b00,m4);
- //m5=(a00+a01)*(b11)
- Mat m5(n/2);
- vs(n/2,a00+a01,b11,m5);
- //m6=(a10-a00)*(b00+b01)
- Mat m6(n/2);
- vs(n/2,a10-a00,b00+b01,m6);
- //m7=(a01-a11)*(b10+b11)
- Mat m7(n/2);
- vs(n/2,a01-a11,b10+b11,m7);
- // cout<<"finish m1-7"<
- Mat c00(n/2),c01(n/2),c10(n/2),c11(n/2);
- c00 =m1+m4-m5+m7;
- c01 =m3+m5;
- c10=m2+m4;
- c11=m1+m3-m2+m6;
- //合并
- for(int i=0;i
2;++i) - {
- for(int j=0;j
2;++j) - {
- c.m[i][j]=c00.m[i][j];
- c.m[i][j+n/2]=c01.m[i][j];
- c.m[i+n/2][j]=c10.m[i][j];
- c.m[i+n/2][j+n/2]=c11.m[i][j];
- }
- }
- }
-
- int main()
- {
- ma.input01(aa);
- mb.input01(bb);
-
- vs(n,ma,mb,mc01);
- mc01.show();
-
- bs(n,ma,mb,mc02);
- mc02.show();
-
-
- return 0;
- }
- /*
-
- 1 0 2 1
- 4 1 1 0
- 0 1 3 0
- 5 0 2 1
- 0 1 0 1
- 2 1 0 4
- 2 0 1 1
- 1 3 5 0
- 5 4 7 3
- 4 5 1 9
- 8 1 3 7
- 5 8 7 7
- 5 4 7 3
- 4 5 1 9
- 8 1 3 7
- 5 8 7 7
- */
棋盘覆盖问题:
【例5-4】残缺棋盘
残缺棋盘是一个有2^
k
×2^
k
(k≥1)个方格的棋盘,其中恰
有一个方格残缺。如图给出k=1时各种可能的残缺棋盘,其
中残缺的方格用阴影表示。

这样的棋盘称作“三格板”,残缺棋盘问题就是要用这四
种三格板覆盖更大的残缺棋盘。在此覆盖中要求:
1)两个三格板不能重叠
2)三格板不能覆盖残缺方格,但必须覆盖其他所有的方格
在这种限制条件下,所需要的三格板总数为(2^
k
×2^
k -1 )/3。【(方格数-1)/3】
问题分析:s=size/2 分治

分4种情况:
1. 若坏格子在左上角,则把图5-2中①号放置在二分后的中间
位置,如图(2)
2. 若坏格子在右上角,则把图5-2中②号放置在二分后的中间
位置,如图(3)
3. 若坏格子在左下角,则把图5-2中③号放置在二分后的中间
位置,如图 (4)
4. 若坏格子在右下角,则把图5-2中④号置在二分后的中间位
置,如图(5)
如何确定棋盘,如何区分棋盘?
——用棋盘左上角进行定位,用棋盘边长划定范围。
计算模型
(1)棋盘:用二维数组CBoard[n][n]存储
(2)棋盘的识别
• tr 棋盘中左上角方格所在行。
• tc 棋盘中左上角方格所在列。
• dr 残缺方块所在行。
• dc 残缺方块所在列。
• size 棋盘的行数或列数。
覆盖残缺棋盘所需要的三格板数目为:( size^
2
-1 ) / 3
将这些三格板编号为1到( size^
2
-1 ) / 3。则将残缺棋
盘三格板编号的存储在数组
CBoard[n][n]
的对应位置中
(3)计算过程
设s=size/2,当s或size<2时,覆盖结束。
• 当 行坐标dr时,坏格在左上子棋盘
中,用①(tr+s-1, tc+s);(tr+s, tc+s-1) ; (tr+s, tc+s)。//红色部分
• 当dr
中,用② (tr+s-1, tc+s-1); (tr+s, tc+s-1) ; (tr+s, tc+s)。
• 当dr≥tr+s and dc
中,用③(tr+s-1, tc+s-1); (tr+s-1, tc+s) ; (tr+s, tc+s)。
• 当dr≥tr+s and dc≥tc+s时,坏格在右下子棋盘 中,
用④ (tr+s-1, tc+s-1); (tr+s-1, tc+s) ; (tr+s, tc+s-1)。
算法分析


算法设计与描述:

代码:
- #include
- using namespace std;
-
- int n=8;//需要是2^x
- int amount=1;
- //棋盘
- int CBoard[100][100];
- //坏格子坐标
-
- //覆盖之后棋盘
- int chessboard[100][100];
-
- //左上角方格所在行int tr,左上角 列int tc, (tr.tc)
- //残缺 行int dr,残缺 列int dc (dr,dc )
- //棋盘的行数or列数int size)
- void CBCover(int CBoard[][100],int tr,int tc,int dr,int dc,int size)
- {
- if(size<2)return;
- int t=amount;
- amount++;//所使用的三格板的数目
- //二分
- int s=size/2;//子问题的棋盘
- //残缺方格位于左上棋盘 1号隔板
- if(dr
- {
- //递归
- CBCover(CBoard,tr,tc,dr,dc,s);
- //到最接近的 结束
-
- //覆盖这三块方格 1号隔板
- CBoard[tr+s-1][tc+s]=t;//注意是相对于隔板的标记坐标
- CBoard[tr+s][tc+s-1]=t;//不是相对于残格的坐标
- CBoard[tr+s][tc+s]=t; //
-
- //覆盖其余部分
- //下侧棋盘 覆盖的那块隔板 会在新的棋盘上占用一个方格 也就是一个坏块
- CBCover(CBoard,tr,tc+s,tr+s-1,tc+s,s);
- //右侧
- CBCover(CBoard,tr+s,tc,tr+s,tc+s-1,s);
- //右下侧
- CBCover(CBoard,tr+s,tc+s,tr+s,tc+s,s);
-
- }
- //残缺方格位于右上棋盘 2号隔板
- else if(dr
=tc+s )- {
- //递归
- CBCover(CBoard,tr,tc+s,dr,dc,s);
-
- CBoard[tr+s-1][tc+s-1]=t;//覆盖2号三格板
- CBoard[tr+s][tc+s-1]=t;
- CBoard[tr+s][tc+s]=t;
- //覆盖其余部分
- CBCover(CBoard,tr,tc,tr+s-1,tc+s-1,s);
- CBCover(CBoard,tr+s,tc,tr+s,tc+s-1,s);
- CBCover(CBoard,tr+s,tc+s,tr+s,tc+s,s);
-
- }
- //残缺方格位于左下棋盘 3号隔板
- else if(dr>= tr+s && dc < tc+s )
- {
- //递归
- CBCover(CBoard,tr+s,tc,dr,dc,s);
- CBoard[tr+s-1][tc+s-1]=t;//上
- CBoard[tr+s-1][tc+s]=t;//右上
- CBoard[tr+s][tc+s]=t;//右
- //覆盖其余部分
- CBCover(CBoard,tr,tc,tr+s-1,tc+s-1,s);
- CBCover(CBoard,tr,tc+s,tr+s-1,tc+s,s);
- CBCover(CBoard,tr+s,tc+s,tr+s,tc+s,s);
-
- }
- //残缺方格位于右下棋盘 4号隔板
- else if(dr>=tr+s && dc>=tc+s )
- {
- //递归
- CBCover(CBoard,tr+s,tc+s,dr,dc,s);
-
- CBoard[tr+s-1][tc+s-1]=t;//覆盖2号三格板
- CBoard[tr+s-1][tc+s]=t;
- CBoard[tr+s][tc+s-1]=t;
- //覆盖其余部分
- CBCover(CBoard,tr,tc,tr+s-1,tc+s-1,s);
- CBCover(CBoard,tr,tc+s,tr+s-1,tc+s,s);
- CBCover(CBoard,tr+s,tc,tr+s,tc+s-1,s);
-
- }
-
- }
- void output(int a[][100])
- {
- cout<<"a:"<
- for(int i=0;i
- {
- for(int j=0;j
- {
- cout<"\t";
- }
- cout<
- }
-
- }
- int main()
- {
- output(CBoard);
- CBCover(CBoard,0,0,0,0,n);
- output(CBoard);
- return 0;
- }
选择性问题:——非等分
选最大值、最小值、选中位数、选第二大值
一般性描述:
设A是含有n个元素的集合,从A中选出第k小的元素,其中
1≤k≤n。这里的第k小是指当A中元素从小到大排序之后,
第k个位置的元素,当k=1时,选出的是A中的最小值,当
k=n时,选出的就是最大值。
问题分析:
(1)排序--找第k小的元素,时间渐近复杂度为O(nlogn)——高级排序算法 极限
(2)蛮力算法--当k=1或k=n时【最大或最小】,一趟即可找到解,时间渐近复杂度只有O(n)。
(3)二分治策略--当k=2时,将原数列分为两个子集,每个子 集各选出一个最小值和第二小值,从这个4个数字里可找到当前的最小值
选择性问题:选第k小值
计算模型
选择pivot=a[left]值,j=right对集合进行二分
(1) j-left=k-1,则分界数据就是选择问题的答案
(2) j-left>k-1,则选择问题的答案继续在左子集中找,问题规模变小了。
(3) j-left
算法分析
(1)最坏情况下的复杂性是O(n
2
),left 总是为空,第k个元素总是位于 right
子集中。
(2)设n=2
k
,算法的平均复杂性是O (n+logn)。若仔细地选择分界元素,则
最坏情况下的时间开销也可以变成O(n)。
(3)它与本章第一个例子非常相似,只对一半子集进行搜索,所不同的时,
由于pivot点选择的不同,多数情况下它是非等分的。
算法设计与分析 输入 输出
int select(int a[],int left,int right,int k)
{
int i,j,pivot,t;
if(left>=right)return a[left];
i=left;
j=right+1;
pivot=a[left];
while(true)
{
do{
i++;
}
while(a[i] if(i>=j)break;
t=a[i];
a[i]=a[j];
a[j]=t;
}
if(j-left+1==k) return pivot;
a[left]=a[j];
a[j]=pivot;
if(k<(j-left+1))select(a,left,j-1,k);
else select(a,j+1,right,k-j-j+left);
}
代码:
- #include
- using namespace std;
-
- void show(int a[])
- {
- cout<<"a[]:";
- for(int i=0;i<8;i++)
- cout<"\t";
- cout<
- }
-
- int select(int a[],int left,int right,int k)
- {
- cout<
"select:left:"<" right:"<" k: "< - cout<<"left不变 right不变"<
- show(a);
-
- int i,j,pivot,t;
- if(left>=right) {
- return a[left];
- }
- i=left;
- j=right+1;
- pivot=a[left];
- cout<<"left:"<
" a[left] = pivot: "< - while(true)
- {
- cout<
"in while:"< - do{
- i++;
- }
- while(a[i]
-
- do{
- j--;
- }while(a[j]>pivot);
- cout<<"now pivot is "<
" 从left到i都小于pivot "<":"<" 从j到right都大于pivot "<":"< - if(i>=j){
- cout<<"i>=j break;"<
- break;
- }
-
- t=a[i];
- a[i]=a[j];
- a[j]=t;
- cout<<"swap "<" "<
- show(a);
- }
- cout<
"while结束 此时 j left k 是"<" "<" "< -
-
- cout<
"最开始right-left+1等于总的元素个数,现在j往前移动 也就是比pivot大的数有(right-j)个"< - <<"选第k小的元素 应该是有sum1=k-1个数比x小,有sum2=right-left+1-k个数比x大"<
- <<"此时 sum2=(right-j) 那么k=right-left+1-(right-j) =j-left+1 也就是此时是第(j-left+1)小 "<
- <<"需要让此时的 (j-left+1)==k 就求出了答案 "<
-
- if(j-left+1==k) return pivot;
- cout<<"然而 (j-left+1)!=k 需要继续寻找 "<
- cout<<"a[left]是基准元素,j小于等于基准,因此交换 "<
- cout<<"交换 left j 的元素"<
- a[left]=a[j];
- a[j]=pivot;
- show(a);
-
- if(k<(j-left+1))
- {
- cout<
"左侧"; - select(a,left,j-1,k);
- }
- else
- {
- cout<
"右侧"; - select(a,j+1,right,k-j-1+left);
- }
- }
-
- int a[]={1,4,5,3,2,6,8,7};
- int k=2;
- int main()
- {
-
- int left=0;
- int right=7;
- int res= select(a,left,right,k);
- cout<
- return 0;
- }
思考题:正元素 负元素排序

问题分析:
使数组中所有负数位于正数之前,空间效率:原数组的空间不可改变,临时变量尽可能少,在原数组上改变 不增加结果数组。时间效率:运算次数尽可能少。
一定会遍历一遍数组,且每个元素与0进行比较,因此从两侧开始,若左侧小于0 不变,大于0需要后移,右侧大于0不变,小于0需要后移。因此找到两位置left right ,进行交换。再以此为范围进行下一轮递归,直到left>=right 结束递归。
计算模型:
从[left,right]范围内进行二分。
(1)left>=right 结束循环
(2)从left开始找到第一个大于0的元素下标,更新left
(3)从right开始找到第一个小于0的元素下标,更新right
(4)若left>=right 结束循环
(5)否则从新的【left,right】范围进行递归排序
算法设计与分析
算法设计与描述
算法分析 输入:数组a[] 输出:排序后数组 void fun(int a[],int left,int right)
{
if(left>=right) {
return ;
}
while(a[left]<0) ++left;
while(a[right]>0) --right;
if(left {
t=a[left];
a[left]=a[right];
a[right]=t;
fun(a,left,right);
}
else return ;
}
(1)输入规模n
(2)核心语句:比较和交换语句
(3)
时间复杂度 按最坏情况 每交换一次 都只能纠正2个元素的位置,则需要递归n/2次 :
T(n)= T(n-2) + c
=T(n-4) + 2*c
=T(n-6)+3*c
共n/2次 T(n)=O(n)
空间复杂度:则S(n)= n/2 +2;

思考题:用分治法 求 数列的最大子段和
-
相关阅读:
什么是war包?war包该怎么运行?
嵌入式学习笔记(16)反汇编工具objdump
Linux系统管理
Pandas 2.1中的新改进和新功能
Bash变量--位置参数变量
深圳市第十二届职工技术创新运动会暨2022年深圳技能大赛—集成电路应用开发职业技能竞赛
电阻值的优先值
java设计模式之命令设计模式的前世今生
【Pytest实战】Pytest+Allure+Jenkins自动化测试框架搭建
Linux内核设计与实现 第九章 内核同步与介绍
-
原文地址:https://blog.csdn.net/iivan_cpp/article/details/123517470