C++ 追溯 各类排序算法实现及效率
2015-01-13 20:19:25
总结:刚好数据结构课让我们做排序的实验,我来总结一下各类排序算法~
主要实现:(1)插入排序 (2)归并排序 (3)快速排序 (4)堆排序 (5)希尔排序 (冒泡,选择啥的路过辣...)
整理下各个算法的思路:
(1)插入排序,这个按照最原始的扑克插入就很好想(借算导例子...)一个一个插入即可,这个算法的姿势可以很糟糕可以很优美,也可以用二分进行优化,不多说了。
(2)归并排序,分而治之,将数列分成两块并且预先排完序后再将两者按大小归并成有序的总数列,需要借助两个全局数组L[]和R[]来存两半边的数列(尚未想到不用辅助数组的写法...)
(3)快速排序,其实也是分而治之的思想,只不过这个是以某个数为标准,将整个数列中大于和小于这个数的数分为两部分,然后再分别处理这两个部分。
在处理一个子区间时,选定的数可以是随机位置,也可以就是第一或者最后一个数,然后将比标准小的数放左,比它大的放右,最后别我忘记把标准数放回中间。
(4)堆排序,这个思路比较简单,就是直接根据数列构造出最小 / 最大堆,然后逐个出堆即可。
(5)希尔排序,插入排序的进化版,简而言之就是将数列分成那么几段:i , i + gap , i + 2*gap , i + 3*gap .... (1 <= i < gap),然后对这些段进行插入排序处理。每次处理完后
都将这个增量gap缩小,一般缩小为gap/2,直到处理完gap=1的情况。(按照这种方法,gap初始值一般设为:size / 2)
1 //Writer : Natureal 2 //Address:Soochow University 3 //Email : 564374850@qq.com 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cstring> 7 #include <ctime> 8 #include <cmath> 9 #include <set> 10 #include <map> 11 #include <stack> 12 #include <queue> 13 #include <fstream> 14 #include <string> 15 #include <iomanip> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 #define MEM(a,b) memset(a,b,sizeof(a)) 20 #define REP(i,n) for(int i = 1; i <= (n); ++i) //1~n 循环 21 #define REV(i,n) for(int i = (n); i >= 1; --i) //n~1 逆循环 22 #define FOR(i,a,b) for(int i = (a); i <= (b); ++i) //a~b 循环 23 #define FREV(i,a,b) for(int i = (a); i >= (b); --i) //b~a 逆循环 24 #define MP(a,b) make_pair((a),(b)) 25 typedef long long ll; 26 typedef pair<int,int> pii; 27 const int INF = (1 << 30) - 1; 28 const int maxn = 10010; 29 30 int or20[maxn],or200[maxn],or2000[maxn]; 31 int re20[maxn],re200[maxn],re2000[maxn]; 32 int ra20[maxn],ra200[maxn],ra2000[maxn]; 33 int now20[maxn],now200[maxn],now2000[maxn]; 34 int cnt_cmp,cnt_move;//记录关键字比较次数,移动次数 35 int ans[maxn]; //暂存的数据的辅助数组 36 int L[maxn],R[maxn]; //归并排序所用的辅助数组 37 double duration; //耗时计数器 38 clock_t st,ed; //时间记录点 39 40 void Insert_sort(int *val,int size){ //插入排序,参考《算法导论》 41 int pos; 42 cnt_cmp += size - 1; 43 FOR(i,2,size) if(val[i] < val[i - 1]){ 44 val[0] = val[i],pos = i - 1; //val[0]作为哨兵 45 cnt_move++,cnt_cmp++; 46 while(val[pos] > val[0]){ 47 val[pos + 1] = val[pos]; 48 pos--; 49 cnt_cmp++,cnt_move++; 50 } 51 val[pos + 1] = val[0]; 52 cnt_move++; 53 } 54 } 55 56 void Merge_sort(int *val,int l,int r){ //归并排序 57 if(l < r){ 58 int mid = (l + (r - l) / 2); 59 Merge_sort(val,l,mid); 60 Merge_sort(val,mid + 1,r); 61 int pl = 1,pr = 1,szl = mid - l + 1,szr = r - mid; 62 REP(i,szl) L[i] = val[l - 1 + i]; 63 REP(i,szr) R[i] = val[mid + i]; 64 cnt_move += r - l + 1; 65 FOR(i,l,r){ 66 if(pr > szr || (pl <= szl && L[pl] <= R[pr])) 67 val[i] = L[pl++]; 68 else val[i] = R[pr++]; 69 cnt_cmp++; 70 } 71 } 72 } 73 74 void Quick_sort(int *val,int l,int r){ //快速排序,递归版 75 if(l < r){ 76 int x = val[l],i = l,j = r; //这里以val[l]为基准,并把val[l]取出来存在x中 77 while(i < j){ 78 while(i < j && val[j] > x) --j,++cnt_cmp; 79 if(i < j) val[i++] = val[j],++cnt_move; //从右到左找到第一个小于x的val位置 80 while(i < j && val[i] < x) ++i,++cnt_cmp; //填补val[i](一开始的val[i]就是val[l]) 81 if(i < j) val[j--] = val[i],++cnt_move; //从左到右找到第一个大于等于x的val位置 82 } 83 val[i] = x; 84 Quick_sort(val,l,i - 1); //递归处理左半区间[l,i - 1] 85 Quick_sort(val,i + 1,r); //递归处理右半区间[i + 1,r] 86 } 87 } 88 89 struct Heap{ //堆结构体,由自己实现的独立结构(为了计算关键字次数进行了改进) 90 int sz,t[maxn << 1]; 91 void clear(){ sz = 0;} 92 void push(int val){ 93 int p = ++sz; 94 while(p > 1){ //入堆操作,加入堆树的末尾,然后向上调整 95 int fa = p / 2; 96 ++cnt_cmp; 97 if(t[fa] <= val) break; 98 t[p] = t[fa],++cnt_move; 99 p = fa; 100 } 101 t[p] = val,++cnt_move; 102 } 103 void pop(){ //出堆操作,将堆树的最后一个元素调顶,然后向下调整 104 int val = t[sz--]; 105 int p = 1; 106 while(p * 2 <= sz){ 107 int a = p * 2,b = p * 2 + 1; 108 cnt_cmp += 2; 109 if(b <= sz && t[b] < t[a]) swap(a,b); 110 if(t[a] >= val) break; 111 t[p] = t[a],++cnt_move; 112 p = a; 113 } 114 t[p] = val,++cnt_move; 115 } 116 int top(){ 117 return t[1]; 118 } 119 }; 120 121 void Heap_sort(int *val,int size){ //堆排序 122 Heap h; h.clear(); 123 REP(i,size) h.push(val[i]); 124 REP(i,size) val[i] = h.top(),h.pop(); 125 } 126 127 void Shell_sort(int *val,int size){ //希尔排序 128 for(int gap = size / 2; gap; gap /= 2){ //设定增量,从size / 2开始,然后每次的增量减半,直至为零退出 129 REP(i,gap) for(int j = i + gap; j <= size; j += gap){ 130 ++cnt_cmp; 131 if(val[j] < val[j - gap]){ 132 val[0] = val[j]; 133 int pos = j - gap; 134 ++cnt_cmp,++cnt_move; 135 while(pos > 0 && val[0] < val[pos]){ 136 val[pos + gap] = val[pos]; 137 pos -= gap; 138 ++cnt_cmp,++cnt_move; 139 } 140 val[pos + gap] = val[0]; 141 ++cnt_move; 142 } 143 } 144 } 145 } 146 147 inline void Print(){ 148 cout << " ,关键字比较次数:" << cnt_cmp 149 << " ,关键字移动次数:" << cnt_move << endl << endl; 150 } 151 152 void Solve_insert_sort(int size){ //插入排序预处理 153 cnt_cmp = cnt_move = 0; //排序前初始化 154 st = clock(); //st为排序执行前的时间点 155 Insert_sort(ans,size); 156 ed = clock(); //ed为排序执行后的时间点 157 duration = 1000.0 * (ed - st) / CLOCKS_PER_SEC; //计算排序算法耗时,单位是毫秒(ms) 158 cout << "<插入排序>耗时:" << duration << " ms"; 159 Print(); 160 } 161 162 void Solve_quick_sort(int size){ //快速排序预处理 163 cnt_cmp = cnt_move = 0; 164 st = clock(); 165 Quick_sort(ans,1,size); 166 ed = clock(); 167 duration = 1000.0 * (ed - st) / CLOCKS_PER_SEC; 168 cout << "<快速排序>耗时:" << duration << " ms"; 169 Print(); 170 } 171 172 void Solve_heap_sort(int size){ //堆排序预处理 173 cnt_cmp = cnt_move = 0; 174 st = clock(); 175 Heap_sort(ans,size); 176 ed = clock(); 177 duration = 1000.0 * (ed - st) / CLOCKS_PER_SEC; 178 cout << "<堆排序>耗时:" << duration << " ms"; 179 Print(); 180 } 181 182 void Solve_merge_sort(int size){ //归并排序预处理 183 cnt_cmp = cnt_move = 0; 184 st = clock(); 185 Merge_sort(ans,1,size); 186 ed = clock(); 187 duration = 1000.0 * (ed - st) / CLOCKS_PER_SEC; 188 cout << "<归并排序>耗时:" << duration << " ms"; 189 Print(); 190 } 191 192 void Solve_shell_sort(int size){ //希尔排序预处理 193 cnt_cmp = cnt_move = 0; 194 st = clock(); 195 Shell_sort(ans,size); 196 ed = clock(); 197 duration = 1000.0 * (ed - st) / CLOCKS_PER_SEC; 198 cout << "<希尔排序>耗时:" << duration << " ms"; 199 Print(); 200 } 201 202 void Work(){ 203 //First scale : 20 204 cout << "【数据规模】:20" << endl; 205 206 memcpy(ans,now20,sizeof(now20)); 207 Solve_insert_sort(20); 208 memcpy(ans,now20,sizeof(now20)); 209 Solve_merge_sort(20); 210 memcpy(ans,now20,sizeof(now20)); 211 Solve_quick_sort(20); 212 memcpy(ans,now20,sizeof(now20)); 213 Solve_heap_sort(20); 214 memcpy(ans,now20,sizeof(now20)); 215 Solve_shell_sort(20); 216 217 //Second scale : 200 218 cout << "【数据规模】:200" << endl; 219 220 memcpy(ans,now200,sizeof(now200)); 221 Solve_insert_sort(200); 222 memcpy(ans,now200,sizeof(now200)); 223 Solve_merge_sort(200); 224 memcpy(ans,now200,sizeof(now200)); 225 Solve_quick_sort(200); 226 memcpy(ans,now200,sizeof(now200)); 227 Solve_heap_sort(200); 228 memcpy(ans,now200,sizeof(now200)); 229 Solve_shell_sort(200); 230 231 //Third scale : 2000 232 cout << "【数据规模】:2000" << endl; 233 234 memcpy(ans,now2000,sizeof(now2000)); 235 Solve_insert_sort(2000); 236 memcpy(ans,now2000,sizeof(now2000)); 237 Solve_merge_sort(2000); 238 memcpy(ans,now2000,sizeof(now2000)); 239 Solve_quick_sort(2000); 240 memcpy(ans,now2000,sizeof(now2000)); 241 Solve_heap_sort(2000); 242 memcpy(ans,now2000,sizeof(now2000)); 243 Solve_shell_sort(2000); 244 245 } 246 247 int main(){ 248 //指定文件 249 ifstream order20("order_20.txt"); 250 ifstream order200("order_200.txt"); 251 ifstream order10000("order_2000.txt"); 252 ifstream reverse20("reverse_20.txt"); 253 ifstream reverse200("reverse_200.txt"); 254 ifstream reverse10000("reverse_2000.txt"); 255 ifstream random20("random_20.txt"); 256 ifstream random200("random_200.txt"); 257 ifstream random10000("random_2000.txt"); 258 259 srand((unsigned)time(NULL)); 260 261 //读入数据 262 REP(i,20){ 263 order20 >> or20[i]; 264 reverse20 >> re20[i]; 265 random20 >> ra20[i]; 266 } 267 REP(i,200){ 268 order200 >> or200[i]; 269 reverse200 >> re200[i]; 270 random200 >> ra200[i]; 271 } 272 REP(i,2000){ 273 order10000 >> or2000[i]; 274 reverse10000 >> re2000[i]; 275 random10000 >> ra2000[i]; 276 } 277 //测试各类排序 278 279 cout << "顺序数据:=======================================================" << endl << endl; 280 memcpy(now20,or20,sizeof(or20)); 281 memcpy(now200,or200,sizeof(or200)); 282 memcpy(now2000,or2000,sizeof(or2000)); 283 Work(); 284 285 cout << "逆序数据:=======================================================" << endl << endl; 286 memcpy(now20,re20,sizeof(re20)); 287 memcpy(now200,re200,sizeof(re200)); 288 memcpy(now2000,re2000,sizeof(re2000)); 289 Work(); 290 291 cout << "随机数据:=======================================================" << endl << endl; 292 memcpy(now20,ra20,sizeof(ra20)); 293 memcpy(now200,ra200,sizeof(ra200)); 294 memcpy(now2000,ra2000,sizeof(ra2000)); 295 Work(); 296 297 return 0; 298 }