电话面试遇到一个题目,删除所有的偶数。
先上代码。
1 #include <vector> 2 #include <iostream> 3 #include <algorithm> 4 #include <stdlib.h> 5 6 #define IS_EVEN(a) (0 == (a) % 2) 7 #define IS_ODD(a) (0 != (a) % 2) 8 9 bool isEven(unsigned int a) 10 { 11 return !(a % 2); 12 } 13 14 int main(int argc, char** argv) 15 16 { 17 if (argc < 3) 18 { 19 std::cout << "\n===================================================" 20 << "\n" << argv[0] << " [size][alog][y/n])]" 21 << "\n size: acount of numbers" 22 << "\n alog: algorithm 1.common loop 2. exchange and move if not delete from end 3. exchange and never move" 23 << "\n numberstput: \'y\' to numberstput result" 24 << "\n===================================================\n"; 25 } 26 int VEC_SIZE = atoi(argv[1]); 27 int head = 0, tail = VEC_SIZE - 1; 28 29 // init data 30 std::vector<int> numbers(VEC_SIZE); 31 for (int i = 0; i < VEC_SIZE; i++) 32 { 33 numbers.at(i) = (int)(rand() % (VEC_SIZE * 10)); 34 } 35 36 if (argc > 3 && 'y' == *argv[3]) 37 { 38 std::cout << "\n============================= before ===========================\n"; 39 tail = numbers.size() ; 40 for (int i = 0; i < tail; i++) 41 std::cout << numbers.at(i) << " "; 42 } 43 44 if ('1' == *argv[2]) 45 { 46 // algo 1: loop common. stable. 47 for (int i = 0; i < numbers.size();) 48 { 49 if (numbers[i] % 2 == 0) 50 numbers.erase(numbers.begin() + i); 51 else 52 ++i; 53 } 54 } 55 56 57 else if ('2' == *argv[2]) 58 { 59 // will trigger memory movement if no delete from end. not stable 60 for(; head <= tail;) 61 { 62 // odd - even 63 if (IS_ODD(numbers[head]) && IS_EVEN(numbers[tail])) 64 { 65 numbers.erase(numbers.begin() + tail); 66 --tail; 67 ++head; 68 } 69 // even - odd 70 else if (IS_EVEN(numbers[head]) && IS_ODD(numbers[tail])) 71 { 72 numbers[head] = numbers[tail]; 73 numbers.erase(numbers.begin() + tail); 74 ++head; 75 --tail; 76 } 77 // odd - odd 78 else if (IS_ODD(numbers[head]) && IS_ODD(numbers[tail])) 79 { 80 ++head; 81 --tail; 82 } 83 // even-even 84 else if (IS_EVEN(numbers[head]) && IS_EVEN(numbers[tail])) 85 { 86 numbers.erase(numbers.begin() + tail); 87 --tail; 88 } 89 } 90 } 91 92 else if ('3' == *argv[2]) 93 { 94 // always delete from end, never trigger memory movement. not stable 95 for(; head <= tail;) 96 { 97 // odd - even 98 if (IS_ODD(numbers[head]) && IS_EVEN(numbers[tail])) 99 { 100 numbers[tail] = *numbers.rbegin(); 101 numbers.pop_back(); 102 103 --tail; 104 ++head; 105 } 106 // even - odd 107 else if (IS_EVEN(numbers[head]) && IS_ODD(numbers[tail])) 108 { 109 numbers[head] = *numbers.rbegin(); 110 numbers.pop_back(); 111 112 ++head; 113 --tail; 114 } 115 // odd - odd 116 else if (IS_ODD(numbers[head]) && IS_ODD(numbers[tail])) 117 { 118 ++head; 119 --tail; 120 } 121 // even - even 122 else if (IS_EVEN(numbers[head]) && IS_EVEN(numbers[tail])) 123 { 124 numbers[tail] = *numbers.rbegin(); 125 numbers.pop_back(); 126 --tail; 127 } 128 } 129 } 130 131 else if ('4' == *argv[2]) 132 { 133 // always overide even with a adjacent odd. stable 134 head = 0, tail = 1; 135 for(;tail < VEC_SIZE;) 136 { 137 if (IS_EVEN(numbers[head]) && IS_ODD(numbers[tail])) 138 { 139 numbers[head] = numbers[tail]; 140 numbers[tail] = 0; // make it as a EVEN. 141 ++head; 142 ++tail; 143 } 144 else if (IS_ODD(numbers[head]) && IS_EVEN(numbers[tail])) 145 { 146 ++head; 147 ++tail; 148 } 149 else if (IS_EVEN(numbers[head]) && IS_EVEN(numbers[tail])) 150 { 151 ++tail; 152 } 153 else if (IS_ODD(numbers[head]) && IS_ODD(numbers[tail])) 154 { 155 head+=2; 156 tail+=2; 157 } 158 } 159 // erase all the unused number from head. 160 numbers.erase(numbers.begin()+head, numbers.end()); 161 } 162 163 else if ('5' == *argv[2]) 164 { 165 //call remove_if 166 std::vector<int>::iterator tail = remove_if(numbers.begin(), numbers.end(), isEven); 167 numbers.erase(tail, numbers.end()); 168 } 169 170 if (argc > 3 && 'y' == *argv[3]) 171 { 172 std::cout << "\n============================= after ===========================\n"; 173 tail = numbers.size() ; 174 for (int i = 0; i < tail; i++) 175 std::cout << numbers.at(i) << " "; 176 } 177 }
测试环境:i7-6600U 8G RAM
分支1: 菜鸡强撸,数据量10w 大约60秒+, 100w好久都跑不出结果
分支2,两端向中间扫描,奇数替换偶数,不从末尾删除会导致memory move。非稳定算法,删除后,item顺序乱掉。
分支3,同2,不同在于一直从末尾删除,不触发memory move。非稳定算法,删除后,item顺序乱掉。
分支4,从开头扫描每次扫描两个item,奇数替换偶数,不触发memory move。 稳定算法。
分支5,调用STL 算法
事实证明STL的remove_if的原理和分支4一致。
同样开启-O3优化选项。
1billion数据量,处理时间均在1.6 second左右。
为了最大限度模拟生产环境,数据初始化用了随机数。 此种情况下,分支4和STL 速度一致。
如果用下标初始化每个item。STL在1.4秒左右处理 1billion。 比分支4快15%左右。maybe此种情况下编译器有特殊优化。不得而知。