求最大子段和的幾種方法以及效能測試

2022-08-17 01:57:18 字數 4231 閱讀 6450

我是計院出身的,但是感覺自己演算法方面比較薄弱,這些天抽些時間把以前的問題拿出來總結一下。最大子段和問題是乙個比較基礎的問題,在《資料結構與演算法:c語言實現》比較靠前的位置。

為了便於說明,假設存在乙個陣列a,長度length.a和b做下標且a小於b。

演算法一

時間複雜度:o(n^3)

演算法思想:對於每乙個可能的區間[a,b]都去求其和,找到其中的最大值。

int max_sub_sum_1(const

int a, int

length)

maxsum = thissum>maxsum ? thissum : maxsum;}}

return maxsum;

}

這個演算法是最簡單粗暴的一種,也的確非常好理解。

演算法二

int max_sub_sum_2(const

int a,int

length)}}

return maxsum;

}

這演算法其實也很好理解噠~

演算法三

時間複雜度:o(n*logn)

演算法簡述:使用分治法策略。將這個陣列一分為二,則最大子段有三種情況

先看看**

int max_sub_sum_3_part(const

int a, int left, int right)

else

}center = (left + right) / 2;

leftmaxsum = max_sub_sum_3_part(a, left, center);

rightmaxsum = max_sub_sum_3_part(a, center+1, right);

//for (i = center+1; i<=right; i++)

}for (i = center; i >=left; i--)

}return

max(max(leftmaxsum, rightmaxsum), leftbordermaxsum + rightbordermaxsum);

}

//為了保持其一致性

int max_sub_sum_3(const

int a, int

length)

左半部分和右半部分的最大子段用遞迴求得,而左半部分和右半部分兼有的最大子段就需要用點小手段了。之後將三者進行比較,返回三者最大者。

其實最不好理解的部分就是遞迴的「終點」,如果當前的值大於0則返回當前值,如果小於零則返回0。這個應該怎麼考慮呢?對於當前的單位而言,有兩種選擇,選或者不選。不選則為0。

要想理解這個演算法,我覺得最重要的還是理解清楚分治的目的到底是什麼。——>求出當前範圍內的最大值。無論當前單元是多大,哪怕只有1(雖然特殊,但是目的沒有變)。

演算法四

這個演算法其實是在大二的時候就已經看到過了,但是直到今日重新看起,還是覺得很秒。尤其是和前幾個演算法對比,不光**精簡,時間複雜度也降低到了o(n)。程式設計老師所說的好的**是藝術的,這大概就是乙份好的**。

動態規劃

時間複雜度:o(n)

演算法思想:動態規劃

int max_sub_sum_4(const

int a, int

length)

else

if (thissum < 0)

}return maxsum;

}

這個方法剛看上去有些反直覺。我的第一反應就是:這真的可以得到最大子段和麼?

首先我們看一看這個問題是否符合動態規劃演算法要求的性質:

能採用動態規劃求解的問題的一般要具有3個性質:

最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。

這個是肯定的,假設有兩個段,a和b且,a-b=a,則a的最大子段和就是b的最大子段和+(a或者0)。

無後效性:即某階段狀態一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與當前狀態有關。

如題,演算法四並沒有影響之前的狀態。

有重疊子問題:即子問題之間是不獨立的,乙個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃演算法同其他演算法相比就不具備優勢)

每一次更新都要同maxsum進行比較。

thissum(n)=max(thissum(n-1)+thisnum,thisnum)

為了生成足夠大的陣列,我寫了乙個方法,可以生成一組任意大小的隨機數。為了方便之後的對比,還會把這組隨機數寫入到檔案中儲存。

#include 

#include

#include

#include

#include

#define random(x) (rand()%x)

/******聲稱測試資料**************************/

int get_test_data_f(int *data, const

char* file_name, int size, int max_num)

srand((int)time(0));

for (int i = 0; i < size; i++)

return

0;}

呼叫測試的函式如下

#include "_data.h"

#include "stdlib.h"

#include "max_sub_sum.h"

#include "binary_search.h"

#define size 1000

#define max_num 200

int main()

start_time = clock();

printf("%d\n",max_sub_sum_1(a,size));

finish_time = clock();

printf("演算法1執行時間為:%d\n", (finish_time - start_time));

start_time = clock();

printf("%d\n", max_sub_sum_2(a, size));

finish_time = clock();

printf("演算法2執行時間為:%d\n", (finish_time - start_time));

start_time = clock();

printf("%d\n", max_sub_sum_3(a, size));

finish_time = clock();

printf("演算法3執行時間為:%d\n", (finish_time - start_time));

start_time = clock();

printf("%d\n", max_sub_sum_4(a, size));

finish_time = clock();

printf("演算法4執行時間為:%d\n", (finish_time - start_time));

system("pause");

return

0;}

當測試規模為1000時

當測試規模為5000時

這個時候明顯看到了演算法一和演算法二已經很吃效能了!

當測試規模打到10000時

我去minecraft燒了一片樹林才跑完,這個時候演算法一已經沒法看了。。

但是當測試規模達到了100000時呢?

求最大子列和的幾種方法

給出乙個陣列a與陣列長度n,求該陣列中最大子列和。子列由陣列中連續的元素組成 int maxsubseqsum1 int a,int n o n 3 if tempsum maxsum return maxsum int maxsubseqsum2 int a,int n o n 2 return ...

求最大子段和

給定乙個整數序列,你需要找出兩個連續子段,保證這兩個子段不能重疊,並且使得這兩個子段中所有整數的和最大。輸入描述 包含一系列的測試用例。第1行是乙個整數,表示測試用例的總數t,1 t 30 第1行後面跟了乙個空行。每個測試用例包括3行 第1行是乙個整數,表示該整數序列的長度n,2 n 5000 第2...

求最大子段和

給定乙個整數序列,你需要找到兩個連續子段,保證這兩個子段不能重疊,並且使得這兩個子段中 所有整數的和最大。輸入描述 包含一系列的測試用例,第1行是乙個整數,表示測試用例的總數t,1 t 30 每個測試用例包括3行 第1行是個整數,表示該整數序列的長度n,2 n 5000 第2行是乙個包含n個整數的序...