2 #include < iostream >
3 #include < time.h >
4 #include < sys / timeb.h >
5 #include < sys / time.h >
6 #include < vector >
7
8 using namespace std;
9
10 double timeDelay()
11 {
12 double delay = 0;
13 static timeval first;
14 timeval second;
15 gettimeofday(&second,0);
16 delay = (second.tv_sec-first.tv_sec)*1000000+(second.tv_usec-first.tv_usec);
17 first = second;
18 return static_cast<int>(delay);
19}
20 /**/ /*
21 *double timeDelay()
22 *{
23 * double delay = 0;
24 * static timeb first;
25 * timeb second;
26 * ftime(&second);
27 * delay = (second.time - first.time)*1000 + (second.millitm-first.millitm);
28 * first = second;
29 * return static_cast<int>(delay);
30 *}
31 */
32
33 /**/ /*
34 *int timeDelay()
35 *{
36 * double delay = 0;
37 * static time_t first;
38 * time_t second;
39 * second = time(NULL);
40 * delay = second - first;
41 * first = second;
42 * return static_cast<int>(delay);
43 *}
44 */
45
46 // cubic maximum contiguous subsequence sum algorithm.
47 int maxSubSum1( const vector < int >& a)
48 {
49 int startIndex = 0;
50 int endIndex = 0;
51 int maxSum = 0;
52 for ( int i=0; i<a.size(); ++i)
53 for ( int j=i; j<a.size(); ++j)
54 {
55 int thisSum = 0;
56 int k=i;
57 for ( ; k<=j; k++) {
58 thisSum += a[k];
59 if ( thisSum>maxSum) {
60 maxSum = thisSum;
61 startIndex = i;
62 endIndex = k;
63 }
64 }
65 }
66 cout << "in maxSubSum1\nstartIndex is " << startIndex << endl
67 << "endIndex is " << endIndex << endl
68 << "maxSum is " << maxSum << endl;
69 return maxSum;
70}
71
72 // Quadratic maximum contiguous subsequence sum algorithm
73 int maxSubSum2( const vector < int >& a)
74 {
75 int startIndex = 0;
76 int endIndex = 0;
77 int maxSum = 0;
78 for ( int i=0; i<a.size(); ++i) {
79 int thisSum = 0;
80 for ( int j=i; j<a.size(); ++j) {
81 thisSum += a[j];
82 if ( thisSum>maxSum) {
83 maxSum = thisSum;
84 startIndex = i;
85 endIndex = j;
86 }
87 }
88 }
89 cout << "in maxSubSum2\nstartIndex is " << startIndex << endl
90 << "endIndex is " << endIndex << endl
91 << "maxSum is " << maxSum << endl;
92 return maxSum;
93}
94
95 int maxSumRec( const vector < int >& a, int left, int right)
96 {
97 int startIndex = 0;
98 int endIndex = 0;
99
100 if (left==right) //Base case
101 if (0==a[left])
102 return a[left];
103 else
104 return 0;
105
106 int center = (left+right)/2;
107 int maxLeftSum = maxSumRec(a,left,center);
108 int maxRightSum = maxSumRec(a,center+1,right);
109
110
111 int maxLeftBorderSum = 0, leftBorderSum = 0;
112 for ( int i=center; i>=left; i--) {
113 leftBorderSum += a[i];
114 if ( leftBorderSum>maxLeftBorderSum)
115 maxLeftBorderSum = leftBorderSum;
116 }
117
118 int maxRightBorderSum = 0, rightBorderSum = 0;
119 for ( int i=center+1; i<=right; i++) {
120 rightBorderSum += a[i];
121 if ( rightBorderSum>maxRightBorderSum)
122 maxRightBorderSum = rightBorderSum;
123 }
124
125 int re;
126
127 if (maxLeftSum > maxRightSum)
128 re = maxLeftSum;
129 else
130 re = maxRightSum;
131
132 if (re < (maxLeftBorderSum+maxRightBorderSum))
133 re = (maxLeftBorderSum+maxRightBorderSum);
134
135 return re;
136}
137
138 // Recursive maximum contiguous subsequence sum algorithm.
139 // Finds maximum sum in subarray spanning a[left..right].
140 // Does not attempt to maintain actual best sequence.
141 int maxSubSum3( const vector < int >& a)
142 {
143 return maxSumRec(a,0,a.size()-1);
144}
145
146 // Linear-time maximum contiguous subsequence sum algorithm.
147 int maxSubSum4( const vector < int >& a)
148 {
149 int thisSum = 0;
150 int maxSum = 0;
151 for ( int i=0; i<a.size(); ++i) {
152 thisSum += a[i];
153 if (thisSum<=0) {
154 thisSum = 0;
155 } else if (thisSum>maxSum) {
156 maxSum = thisSum;
157 }
158 }
159 cout << "in maxSubSum4, maxSum is " << maxSum << endl;
160 /**//*
161 *cout << "in maxSubSum1\nstartIndex is " << startIndex << endl
162 * << "endIndex is " << endIndex << endl
163 * << "maxSum is " << maxSum << endl;
164 */
165 return maxSum;
166}
167
168 int main()
169 {
170 vector<int> array;
171 fstream input;
172 input.open("data.txt");
173 if (!input) {
174 cout << "file open failure" << endl;
175 }
176
177 int temp;
178 while (input >> temp) {
179 array.insert(array.end(),temp);
180 }
181 input.close();
182
183 timeDelay();
184
185 cout << "=====================================\n";
186 maxSubSum1(array);
187 cout << timeDelay() << endl;
188
189 cout << "=====================================\n";
190 maxSubSum2(array);
191 cout << timeDelay() << endl;
192
193 cout << "=====================================\n";
194 cout << "maxSum is " << maxSubSum3(array) << endl;
195 cout << timeDelay() << endl;
196
197 cout << "=====================================\n";
198 maxSubSum4(array);
199 cout << timeDelay() << endl;
200 return 0;
201
202}
203
该笔记是学习《数据结构与算法分析》P35-43的记录与心得
第三种方法没有搞明白怎么去计算子序列开始和结束的索引,懂的同学看到了告诉我,谢谢~~
最大的子序列和问题:
给定整数A1,A2,。。。,AN(可能有负数),求sum(Ai+A(i+1)+...A(j))的最大值
例如,对于输入-2,11,-4,13,-5,-2,答案为20(从A2到A4)
算法一是穷举式的尝试所有的可能。运行时间为O(N的3次方)
算法二通过撤出一个for循环来避免三次运行时间,通过式子
sum(a(i)+a(i+1)+...+a(j))=a(j)+sum(a(i)+a(i+1)+...+a(j-1))
因此我们可以去掉最内一层循环,O(N的2次方)
算法三采用分治策略(divide and conquer)策略。其想法是把问题分成两个大致相等的自问题,然后递归的对他们求解,这是“分”的部分。“治”阶段将两个子问题的解合并到一起并可能再作少量的附加工作,最后得到整个问题的解。
在我们的例子中,最大子序列和可能出现在三处地方,或者整个出现在输入数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归求解。第三种情况的最大和可以通过求出前半部分的最大和(必须包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后将两个和加在一起。例如对于序列:
4 -3 5 -2 -1 2 6 -2
前半部分最大子序列和为6,后半部分为8,跨越两部分通过中间的为4+7=11,因此对该序列最好的情况为第三种情况。
对于程序,100-104行处理基准情况
107-108行执行两个递归调用
111-116,118-123行计算达到中间分界处的两个最大的和数,因为必须要从某个元素开始来求解最大子序列,所以可以这么写for循环。
算法三比前面两种工作量的都要大,但是程序短并不是总意味着程序好。
算法四是一个聪明的算法:
如果我们不需要知道最佳的子序列在哪里,那么i的使用可以从程序中优化掉。
1.如果下一个数是负数,那么我们就记录下当前的最大和。
如果加上该负数后,我们的和还是正数,那么我们就不改变最大和,但记录下此时的和,继续往下加,或许出现值使得和重新超过最大和。
如果加上该负数后,我们的和是负数了。那么我们就不该遍最大和,此时的和清零,继续往下加,开始一个新的子序列,或许出现值使得和重新超过最大和。
2.如果下一个数是整数,那么就往下加,更新此时的和以及最大和。
该算法一个附带的优点是:
它只对数据进行一次扫描,一旦a[i]被读入并被处理,它就不需要被记忆。因此,如果数组在磁盘或者磁带上,它就可以被顺序读入,在主存中不必存储数组的任何部分。不仅如此,在任意时刻,算法都能对它已经读入的数据给出子序列问题的正确答案(其他算法不具有这个特性)。具有这种特性的算法叫做联机算法(on-line algorithm).仅需常量空间并以线性时间运行的联机算法几乎是完美的算法。
该程序输出结果如下:
第一次:
=====================================
in maxSubSum1
startIndex is 226
endIndex is 650
maxSum is 2276
8.89795e+06
=====================================
in maxSubSum2
startIndex is 226
endIndex is 650
maxSum is 2276
17265
=====================================
maxSum is 2276
277
=====================================
in maxSubSum4, maxSum is 2276
27
第二次:
=====================================
in maxSubSum1
startIndex is 226
endIndex is 650
maxSum is 2276
8.86029e+06
=====================================
in maxSubSum2
startIndex is 226
endIndex is 650
maxSum is 2276
17781
=====================================
maxSum is 2276
278
=====================================
in maxSubSum4, maxSum is 2276
27
ps:
1,生成data文件的代码如下:我使用的大小为2000.
#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;
const int maxsize = 2000;
int main()
{
fstream output;
output.open("data.txt",ofstream::out);
if (!output) {
cout << "file open failed!" << endl;
return 1;
}
int randint;
for ( int i=0; i<maxsize; i++) {
randint = rand()%100;
if (0==rand()%2) {
randint = 0-randint;
}
cout << randint << endl;
output << randint << endl;
}
return 0;
}
2. timeDelay函数用于计算算法的运行时间,刚开始用的time,秒级别的。
发现记录时间时出现0,于是使用ftime,毫秒级别的,结果有几个算法时间相同,于是使用gettimeofday,微妙级别的,就可以看到程序运行时间的差别了~~
关于这几个函数的差别可以man一下,注意time要用man 2 time