数据结构笔记第一章

6 篇文章 0 订阅

第一章

第三节

1.3.1应用实例:最大子列和问题

给定 N N N个整数的数列{ A 1 , A 2 , . . . , A N A_1, A_2, ..., A_N A1,A2,...,AN},求函数
f ( i , j ) = m a x f(i, j) = max f(i,j)=max{ 0 , ∑ k = 0 j A k 0, \sum_{k=0}^jA_k 0,k=0jAk}的最大值

算法1

//算法一

int MaxSubseqSum1(int A[], int N){
	int ThisSum, MaxSum = 0;
	int i, j, k;
	for(i = 0; i < N; i++){/*i是子列左端位置*/
		for(j = i; i<N; j++){/*j是子列右端位置*/
			ThisSum = 0;/*ThisSum是从A[i]到A[j]的子列和*/
			for(k = i; k <=j; k++){
				ThisSum +=A[k];
				if(ThisSum > MaxSubseqSum1)/*如果刚得到的这个子列和更大*/
				MaxSum = ThisSum;/*则更新结果*/
			}
		}/*j循环结束*/
    }/*i循环结束*/
	
    return MaxSum;
}

T ( N ) = O ( N 3 ) T(N)=O(N^3) T(N)=O(N3)

算法2

//算法二

int MaxSubseqSum1(int A[], int N){
	int ThisSum, MaxSum = 0;
	int i, j, k;
	for(i = 0; i < N; i++){/*i是子列左端位置*/
	    ThisSum = 0;/*ThisSum是从A[i]到A[j]的子列和*/
		for(j = i; i<N; j++){/*j是子列右端位置*/
			ThisSum += A[j];
			/*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
			if(ThisSum > MaxSum)/*如果刚得到的这个子列和更大*/
			  MaxSum = ThisSum;/*则更新*/
		}/*j循环结束*/
    }/*i循环结束*/
	
    return MaxSum;
}

T ( N ) = O ( N 2 ) T(N)=O(N^2) T(N)=O(N2)

1.3.2算法3:分而治之

4 -3 5 -2 -1 2 6 -1

左:4 -2 5 -2 右:-1 2 6 -1
左:4 -2 右1.1:5 -2 左:-1 2 右:5 -2
左:4 右:-2 左:5 右:-2 左:-1 右:2 左:5 右:-2
第一步:将数组一分为二
第二步:递归解决左右两边的问题,得到左右两边的最大子列和
第三步:跨越左右边界的最大子列和

左:左:左的最大子列和是4 返回的结果是4
左:左:右的最大子列和是-2<0 返回的结果是0
由于左:左:左与左:左:右都只有一个元素

左:左部分最大子列和是4

左:右:左的最大子列和是5 返回的结果是5
左:右:右的最大子列和是-2<0 返回的结果是0
由于左:右:左与左:左:右都只有一个元素

左:右部分最大子列和是5

要得到左部分的最大子列和,还要看跨越左右边界的最大子列和

在左:左与左:右的分界线向左扫描
最大子列和 -3 返回0
最大子列和 -3+4=1 1>0 最大子列和更新
在左:左与左:右的分界线向右扫描
最大子列和 5 返回5
最大子列和 5-2=3 返回3 不更新

跨越左:左与左:右边界的最大子列和为5+1=6

6>4
6>5

左边的最大子列和是6

同理

右:右部分的最大子列和是6

右:左部分的最大子列和是2

跨越右:右与右:左边界的最大子列和为8

8>6
8>2

右边的最大子列和是8

在左与右的分界线向左扫描
最大子列和 -2 返回0
最大子列和-2+5=3 返回3 3>0 更新
最大子列和-2+5±3=0 返回0 0<3 不更新
最大子列和-2+5-3+4=4 返回4 4>3 更新
在左与右的分界线向右扫描
最大子列和-1 返回0
最大子列和-1+2=1 返回1 1>0 更新
最大子列和-1+2+6=7 返回7 7>1 更新
最大子列和-1+2+6-2=5 返回5 5<7 不更新

跨越左右边界的最大子列和为4+7=11

11>6
11>8

整个数组的最大子列和是11

T ( N ) = 2 T ( N / 2 ) + c N , T ( 1 ) = O ( 1 ) T(N)=2T(N/2)+cN, T(1)=O(1) T(N)=2T(N/2)+cN,T(1)=O(1)
= 2 [ 2 T ( N / 2 2 ) + c N / 2 ] + c N =2[2T(N/2^2)+cN/2]+cN =2[2T(N/22)+cN/2]+cN
= 2 k O ( 1 ) + c k N =2^kO(1)+ckN =2kO(1)+ckN 其中 N / 2 k = 1 N/2^k=1 N/2k=1
= O ( N log ⁡ N ) =O(N \log N) =O(NlogN)

1.3.3算法4:在线处理

//算法四

int MaxSubseqSum1(int A[], int N){
	int ThisSum, MaxSum = 0;
	int i;
	ThisSum = MaxSum = 0;
	for(i = 0; i < N; i++){
		ThisSum += A[i];/*向右累加*/
		if(ThisSum > MaxSum)
			MaxSum = ThisSum;/*发现更大和则更新当前结果*/
		else if(ThisSum < 0)/*如果当前子列和为负*/
		    ThisSum = 0;/*则不可能使后面的部分和增大,抛弃之*/
	}
    return MaxSum;
}

T ( N ) = O ( N ) T(N)=O(N) T(N)=O(N)

-1 3 -2 4 -6 1 6 -1

i=1
ThisSum = 0

i=2
ThisSum = 3
MaxSum = 3

i=3
ThisSum = 1

i=4
ThisSum = 5
MaxSum = 5

i=5
ThisSum = 0

i=6
ThisSum = 1

i=7
ThisSum = 7
MaxSum = 7

i=8
ThisSum = 6

“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能给出当前正确的解

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值