最简单的方法就是N中的每个数分别和max,min比较,看似2N次比较,其实大于max的就不必和min比较,小于min的也不必和max比较,因此比较的次数不足2N次,程序如下:
[cpp] view plaincopy
- bool MaxMin(std::vector<T> array, T* max, T* min) {
- if (array.size() < 1) {
- return false;
- }
- *max = array[0];
- *min = array[0];
- size_t array_size = array.size();
- for (int i = 1; i < array_size; ++i) {
- if (array[i] > *max) {
- 10. *max = array[i];
- 11. } else if (array[i] < *min) {
- 12. *min = array[i];
- 13. }
- 14. }
- 15. return true;
16. }
其次方法是数组中的一对一对的数相互比较,比较中较大的一个和max比较,较小的和min比较,总计有N/2对数,分别和max和min进行一次比较,共计3N/2次比较,程序代码如下:
[cpp] view plaincopy
- template<typename T>
- bool MaxMin_1(std::vector<T> array, T* max, T* min) {
- if (array.size() < 1) {
- return false;
- }
- *max = array[0];
- *min = array[0];
- int index = 1;
- int array_size = array.size();
- 10. while(index < array_size && index +1 <array_size) {
- 11. if (array[index] >= array[index + 1]) {
- 12. if (array[index] > *max) {
- 13. *max = array[index];
- 14. }
- 15. if (array[index + 1] < *min) {
- 16. *min = array[index + 1];
- 17. }
- 18. } else {
- 19. if (array[index + 1] > *max) {
- 20. *max = array[index + 1];
- 21. }
- 22. if (array[index] < *min) {
- 23. *min = array[index];
- 24. }
- 25. }
- 26. index += 2;
- 27. }
- 28. if (index < array.size()) {
- 29. if (array[index] > *max) {
- 30. *max = array[index];
- 31. }
- 32. if (array[index] < *min) {
- 33. *min = array[index];
- 34. }
- 35. }
- 36. return true;
37. }
最后一种方法是分治法,比较次数也是3N/2,程序如下:
[cpp] view plaincopy
- template<typename T>
- bool MaxMin_2(std::vector<T> array, int start, int end, T* max, T* min) {
- if (end - start > 1) {
- MaxMin_2(array, start, (start + end) / 2, max, min);
- MaxMin_2(array, (start + end) / 2 + 1, end, max, min);
- } else {
- if (array[end] > array[start]) {
- if (array[end] > *max) {
- *max = array[end];
- 10. }
- 11. if (array[start] < *min) {
- 12. *min = array[start];
- 13. }
- 14. } else {
- 15. if (array[start] > *max) {
- 16. *max = array[start];
- 17. }
- 18. if (array[end] < *min) {
- 19. *min = array[end];
- 20. }
- 21. }
- 22. }
23. }
24. template<typename T>
25. bool MaxMin_3(std::vector<T> array, int start, int end, T* max, T* min) {
- 26. if (end > start) {
- 27. MaxMin_2(array, start, (start + end) / 2, max, min);
- 28. MaxMin_2(array, (start + end) / 2 + 1, end, max, min);
- 29. } else {
- 30. if (array[start] > *max) {
- 31. *max = array[start];
- 32. }
- 33. if (array[start] < *min) {
- 34. *min = array[start];
- 35. }
- 36. }
37. }
为了测试性能,完成比较程序如下:
[cpp] view plaincopy
- #include <stdio.h>
- #include <vector>
- #include <stdlib.h>
- #include <sys/time.h>
- template<typename T>
- bool MaxMin(std::vector<T> array, T* max, T* min) {
- if (array.size() < 1) {
- return false;
- }
- 10. *max = array[0];
- 11. *min = array[0];
- 12. size_t array_size = array.size();
- 13. for (int i = 1; i < array_size; ++i) {
- 14. if (array[i] > *max) {
- 15. *max = array[i];
- 16. } else if (array[i] < *min) {
- 17. *min = array[i];
- 18. }
- 19. }
- 20. return true;
21. }
22. template<typename T>
23. bool MaxMin_1(std::vector<T> array, T* max, T* min) {
- 24. if (array.size() < 1) {
- 25. return false;
- 26. }
- 27. *max = array[0];
- 28. *min = array[0];
- 29. int index = 1;
- 30. int array_size = array.size();
- 31. while(index < array_size && index +1 <array_size) {
- 32. if (array[index] >= array[index + 1]) {
- 33. if (array[index] > *max) {
- 34. *max = array[index];
- 35. }
- 36. if (array[index + 1] < *min) {
- 37. *min = array[index + 1];
- 38. }
- 39. } else {
- 40. if (array[index + 1] > *max) {
- 41. *max = array[index + 1];
- 42. }
- 43. if (array[index] < *min) {
- 44. *min = array[index];
- 45. }
- 46. }
- 47. index += 2;
- 48. }
- 49. if (index < array.size()) {
- 50. if (array[index] > *max) {
- 51. *max = array[index];
- 52. }
- 53. if (array[index] < *min) {
- 54. *min = array[index];
- 55. }
- 56. }
- 57. return true;
58. }
59. template<typename T>
60. bool MaxMin_2(std::vector<T> array, int start, int end, T* max, T* min) {
- 61. if (end - start > 1) {
- 62. MaxMin_2(array, start, (start + end) / 2, max, min);
- 63. MaxMin_2(array, (start + end) / 2 + 1, end, max, min);
- 64. } else {
- 65. if (array[end] > array[start]) {
- 66. if (array[end] > *max) {
- 67. *max = array[end];
- 68. }
- 69. if (array[start] < *min) {
- 70. *min = array[start];
- 71. }
- 72. } else {
- 73. if (array[start] > *max) {
- 74. *max = array[start];
- 75. }
- 76. if (array[end] < *min) {
- 77. *min = array[end];
- 78. }
- 79. }
- 80. }
81. }
82. template<typename T>
83. bool MaxMin_3(std::vector<T> array, int start, int end, T* max, T* min) {
- 84. if (end > start) {
- 85. MaxMin_2(array, start, (start + end) / 2, max, min);
- 86. MaxMin_2(array, (start + end) / 2 + 1, end, max, min);
- 87. } else {
- 88. if (array[start] > *max) {
- 89. *max = array[start];
- 90. }
- 91. if (array[start] < *min) {
- 92. *min = array[start];
- 93. }
- 94. }
95. }
- 96.
97. int GetTime() {
- 98. timeval tv;
- 99. gettimeofday(&tv, NULL);
- 100. return tv.tv_sec * 1000000 + tv.tv_usec;
101. }
102. int main(int argc, char** argv) {
- 103. const int kArraySize = 10000;
- 104. std::vector<int> array;
- 105. for (int i = 0; i < kArraySize; ++i) {
- 106. array.push_back(rand());
- 107. // printf("%d ", array[i]);
- 108. }
- 109. printf("\n");
- 110. int max;
- 111. int min;
- 112. int start;
- 113. start = GetTime();
- 114. MaxMin(array, &max, &min);
- 115. printf("time elapse:%d\n", GetTime() - start);
- 116. printf("max:%d min:%d\n", max, min);
- 117.
- 118. start = GetTime();
- 119. MaxMin_1(array, &max, &min);
- 120. printf("time elapse:%d\n", GetTime() - start);
- 121. printf("max:%d min:%d\n", max, min);
- 122. start = GetTime();
- 123. MaxMin_2(array, 0, array.size() - 1, &max, &min);
- 124. printf("time elapse:%d\n", GetTime() - start);
- 125. printf("max:%d min:%d\n", max, min);
- 126. start = GetTime();
- 127. MaxMin_3(array, 0, array.size() - 1, &max, &min);
- 128. printf("time elapse:%d\n", GetTime() - start);
- 129. printf("max:%d min:%d\n", max, min);
130. }
执行结果:
[cpp] view plaincopy
- ./a.out
- time elapse:187
- max:2147469841 min:100669
- time elapse:216
- max:2147469841 min:100669
- time elapse:86513
- max:2147469841 min:100669
- time elapse:82481
10. max:2147469841 min:100669
结论:最简单的方法效率最高,分治法由于迭代效率非常差,这是我想到了分治法的归并排序,估计性能也不会好,改天比较一下。
寻找数组中的最大值和最小值
《编程之美》2.10
算法1:
if(arr[0] > arr[1])
max=arr[0]
min=arr[1]
else
max=arr[1]
min=arr[0]
loop:i从3到n
if(max < arr[i])
max=arr[i]
else
if(min > arr[i])
min = arr[i]
平均比较次数:1+n-2+(n-2)/2=3*(n-2)/2+1
算法2:
if(arr[0] > arr[1])
max=arr[0]
min=arr[1]
else
max=arr[1]
min=arr[0]
loop:i从3到n(i每次递增2)
if(arr[i] > arr[i+1])
if(arr[i] > max)
max=arr[i]
if(arr[i+1]<min)
min=arr[i+1]
else
if(arr[i] < min)
min=arr[i]
if(arr[i+1] > max)
max = arr[i+1]
比较次数:1+3*(n-2)/2
代码:
#include <iostream>
using namespace std;
//algorithm
void maxMin1(int *arr, int b, int e){
int max, min;
if (arr[b] < arr[b+1])
{
max = arr[b+1];
min = arr[b];
}else{
max = arr[b];
min = arr[b+1];
}
for (int i = b + 2; i < e; i += 2)
{
if (arr[i] < arr[i +1])
{
if (max < arr[i+1])
max = arr[i+1];
if (min > arr[i])
min = arr[i];
}else{
if (max < arr[i])
max = arr[i];
if (min > arr[i+1])
min = arr[i+1];
}
}
if ((e - b)%2)
{
if (arr[e-1] > max)
max = arr[e-1];
if (arr[e-1] < min)
min = arr[e-1];
}
cout << "max = " << max << ", min = " << min << endl;
}
//algorithm:divide and conquer
void maxMinDivideAndConquer(int *arr, int b, int e, int &max, int &min){
if (e - b == 1)
{
max = arr[b];
min = arr[b];
return;
}
if (e - b == 2)
{
if (arr[b] < arr[b+1])
{
max = arr[b+1];
min = arr[b];
}else{
max = arr[b];
min = arr[b+1];
}
return;
}
int mid = b + (e-b)/2;
int leftMax, leftMin;
maxMinDivideAndConquer(arr, b, mid, leftMax, leftMin);
int rightMax, rightMin;
maxMinDivideAndConquer(arr, mid, e, rightMax, rightMin);
if (leftMax > rightMax)
max = leftMax;
else
max = rightMax;
if (leftMin < rightMin)
min = leftMin;
else
min = rightMin;
}
void main(){
int arr1[] = {6, 5, 8, 3, 9, 7};
int arr2[] = {6, 5, 8, 3, 9, 7, 20};
// maxMin1(arr1, 0, 6);
// maxMin1(arr2, 0, 7);
int max, min;
maxMinDivideAndConquer(arr1, 0, 6, max, min);
cout << "max = " << max << ", min = " << min << endl;
maxMinDivideAndConquer(arr2, 0, 7, max, min);
cout << "max = " << max << ", min = " << min << endl;
}
扩展问题:要找出N个数组中的第二大数。
法1:通过n-1次比较,找出最大数;在除去最大数的数组中找最大数。比较次数:n-1+n-2=2n-3
法2:把数组中的元素每两个分为一组,每组中的最大数为F,第二大数为S。假设现在已知相邻两组的最大数和第二大数分别是:Fi,Si,Fj,Sj,。则这两组合并为一组后,其中最大数和第二大数可能是:
1、若Fi > Fj,则最大数是Fi;
若Si>Fj,则第二大数是Si;否则,第二大数是Fj
2、若Fi < Fj,则最大数是Fj
若Fi>Sj,则第二大数是Fi;否则,第二大数是Sj
共有N/2组,每组需要比较一次得出本组的最大数和第二大数;共需比较N/2 * 2次。
法3.、分治法divide and conquer
把数组分成两部分,其最大数和第二大数分别是:Fleft,Sleft,Fright,Sright。合并时的情况可能为:
1、Fleft > Fright,最大数是Fleft;若Sleft>Fright,则第二大数是Sleft,否则第二大数是Fright;
2、 Fleft < Fright,最大数是Fright;若Fleft>Sright,则第二大数Fleft,否则第二大数是Sright。
算法如下:
secondMax(int begin, int end, int F, int S)
if(begin + 1 == end)
if(a[begin] > a[end])
F = a[begin]
S = a[end]
else
F = a[end]
S = a[begin]
int mid = begin + (end - begin)/2;
secondMax(begin, mid, Fleft, Sleft)
secondMax(mid+1, right, Fright, Sright)
if(Fleft > Fright)
F = Fleft
if(Sleft > Fright)
S = Sleft
else
S = Fright
else
F = Fright
if(Fleft > Sright)
S = Fleft
else
S = Sright
比较次数:设n=2^(k+1)
F(n)=2*F(n/2)+2
=2*( 2*F(n/2^2) + 2) + 2
=2^2 * F(n/2^2) + 2^2 + 2
=2^2 * (2*F(n/2^3) + 2) + 2^2 +2
=2^3*F(n/2^3) + 2^3 + 2^2 + 2
=2^k * F(n/2^k) + 2^k + 2^(k-1) + …+ 2^2 + 2^1
=2^k*F(2)+2^k+2^(k-1)+…+2^2+2^1
=2^(k+1)+2^k+…+2^1
=2*n-2
寻找数组中最大值和最小值
解法一:
扫描一次数组找出最大值;
再扫描一次数组找出最小值。
代码(略)
比较次数2N-2
解法二:
将数组中相邻的两个数分在一组, 每次比较两个相邻的数,将较大值交换至这两个数的左边,较小值放于右边。
对大者组扫描一次找出最大值,对小者组扫描一次找出最小值。
代码(略)
比较1.5N-2次,但需要改变数组结构
解法三:
每次比较相邻两个数,较大者与MAX比较,较小者与MIN比较,找出最大值和最小值。
代码如下:
void GetMaxAndMin(int* arr, int len, Result* rlt)
{
for(int i=2; i< len-1; i=i+2)
{
if(NULL==arr[i+1])
{
if(arr[i]>rlt->Max)
rlt->Max=arr[i];
if(arr[i]<rlt->Min)
rlt->Min=arr[i];
}
if(arr[i]>arr[i+1])
{
if(arr[i]>rlt->Max)
rlt->Max=arr[i];
if(arr[i+1]<rlt->Min)
rlt->Min=arr[i+1];
}
if(arr[i]<arr[i+1])
{
if(arr[i+1]>rlt->Max)
rlt->Max=arr[i+1];
if(arr[i]<rlt->Min)
rlt->Min=arr[i];
}
}
}
比较次数1.5N-2,但是不用改变原数组结构。
解法四:
分治法,算出前N/2个数的MAX和MIN,再算出后N/2个数的MAX和MIN。代码如下:
void GetMaxAndMin1(int* arr, int len, Result* rlt)
{
if(len==0||!arr)
return;
if(len==1)
{
if(arr[0]>rlt->Max)
rlt->Max=arr[0];
if(arr[0]<rlt->Min)
rlt->Min=arr[0];
return;
}
GetMaxAndMin(arr, len/2, rlt);
GetMaxAndMin(&arr[len/2], len-len/2, rlt);
}
需比较1.5/N-2次。
试验代码:
#include "stdio.h"
#include "stdlib.h"
#define LEN(arr) sizeof(arr)/sizeof((arr)[0])
struct Result{
int Max;
int Min;
};
int main()
{
int test[10]={3,2,4,1,5,2,7,9,0};
Result* rlt = (Result*)malloc(sizeof(Result));
rlt->Max = rlt->Min = test[0];
int len=LEN(test);
GetMaxAndMin(test, len, rlt);
printf("Max=%d\nMin=%d\n", rlt->Max, rlt->Min);
getchar();
}