最簡單的方法就是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();
}