之前笔试遇到了很多排序的题,问第一轮排序后的结果,每次都有点蒙。于是决定手撕一下各种排序算法,包含冒泡排序,选择排序,插入排序,归并排序,快速排序
全局变量和代码块如下
int a[10] = {69, 70, 21, 26, 18, 21, 94, 43, 4, 37}; const int N = 10; void show() { for(int i = 0; i < N; i++) cout << a[i] << " "; cout << endl; }原理: 将大的数沉下去,小的数慢慢浮上来。比较相邻的两个数,第i次排序将第i大的数放到倒数第i位。
//冒泡排序 /* 将大的数沉下去,小的数慢慢浮上来 比较相邻的两个数 第i次排序将第i大的数放到倒数第i位 */ void Bubble_sort() { for(int i = 0; i < N; i++){//每次下层第i个数 for(int j = 0; j < N-i-1; j++){ if(a[j] > a[j+1]) swap(a[j], a[j+1]);//交换 } cout << "冒泡排序每一轮结果" << endl; show(); } }每轮排序之后的结果如下
每次找到第i小的数放到位置i上,从第i+1开始找,得到最小值的下标
//选择排序 /* 从头至尾扫描序列,找出最小的一个元素 和第一个元素交换 接着从剩下的元素中继续这个操作 */ void Select_sort() { for(int i = 0; i < N; i++){ int idx = i;//带寻找到的下标 for(int j = i+1; j < N; j++){ if(a[j] < a[idx]) idx = j; } swap(a[i], a[idx]); cout << "选择排序每一轮的结果" << endl; show(); } }插入排序是将前面的序列看成已经排好序的,将后面的数字插入到对应的位置。比如23 45 78 30 25,排到30的时候,把30放到23和45中间就行。这里有两步操作,找到位置然后后移
//插入排序 /* 将待排序的数看成一个有序序列 每次取当前的数插入到合适的位置 从第二个数开始 */ void Insert_sort() { for(int i = 1; i < N; i++){ int pos = i-1;//最后一个有序的位置 int cur = a[i]; while(pos >= 0 && cur < a[pos]){ a[pos+1] = a[pos]; pos--;//找到合适的位置 } a[pos+1] = cur; cout << "插入排序每轮的排序结果" << endl; show(); } }归并排序相比之前的排序要稍微复杂一点。归并排序的思想是将数组2分成一段一段的数组,然后将分段的数组分别排序,然后在合并成有序的数组
//因为会分成长度为2的小数组 //所以可以认定t1,t2是有序的 void Merge(int L, int mid, int R) { int n1 = mid-L+1;//左边数组的长度 int n2 = R-mid; vector<int> t1, t2; for(int i = 0; i < n1; i++) t1.push_back(a[L+i]); for(int i = 0; i < n2; i++) t2.push_back(a[mid+i+1]); int k = L;//开始重新装到原数组里面 int i = 0, j = 0;//i, j对应t1, t2的下标 while(k <= R){ if(i < n1 && j < n2){ if(t1[i] < t2[j]){ a[k] = t1[i]; i++; } else{ a[k] = t2[j]; j++; } k++; } else{ while(i < n1 && k <= R){ a[k] = t1[i]; i++; k++; } while(j < n2 && k <= R){ a[k] = t2[j]; j++; k++; } } } } //归并排序 /* 将排序的数组分治划分为小的数组 对小的数组排序 合并成大的数组 */ void Merge_sort(int L, int R) { if(L < R){ int mid = (L+R)/2; Merge_sort(L, mid); Merge_sort(mid+1, R); Merge(L,mid, R); show(); } }从运行过程可以看得出来是先划分成小块,然后对小块排序,在合成有序的大块
快速排序也可以说是利用的分治的思想,但是快排是选定一个目标值,将数组分为有序两个部分,即左边的比目标值小,右边的比目标值大。但是左右两边的数组又是无序的,只要将两边的数组有序,即完成排序
void quick_sort(int L, int R) { if(L < R){ //找到分割的下标 int i = L, j = R; int x = a[i];//比x小的都放到左边,大的都放到右边去 while(i < j){ //从右往左找第一个小于x的数 while(i < j && a[j] > x) j--; if(i < j) a[i++] = a[j]; //从左往右找到第一个大于x的数 while(i < j && a[i] < x) i++; if(i < j) a[j--] = a[i]; } a[i] = x; show(); quick_sort(L, i-1); quick_sort(i+1, R); } }具体来说就是选定第一个值作为目标值,然后从右往左找到第一个小于它的,交换位置。然后从左往右找第一个大于它的交换位置。左右交接处就是目标值的位置,这就是一次快速排序。