目录
一、基本的排序算法:
冒泡√:
冒泡思路:
基于比较
循环比较相邻两个元素 如果不符合要求 就交换 最后那个已然符合要求
每次冒出来一个
所以循环 n-1 次 可以达成目标n^2-n
O(n^2)
①未优化版本
void buble_sort(int* &arr, int len) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { if (arr[j] > arr[j+1]) swap(arr[j], arr[j + 1]); } } }
![]()
②优化后:
思路:就是一次遍历之后,发现一次都没有去交换,表明已经是有序的了。
void buble_sort(int* &arr, int len) { int flag = -1; for (int i = 0; i < len - 1; i++) { flag = 0; for (int j = 0; j < len - i - 1; j++) { if (arr[j] > arr[j + 1]) { swap(arr[j], arr[j + 1]); flag = 1;//说明至少交换过1次,有必要再继续进行下去 } } if (flag == 0) break; travel(arr, 10); } }
少运行3次~~~
个人有关参数的心得:最外层for->就是总共需要的次数,归位n-1个即可,也就是最外层n-1次,内层的参数下界从0不断的把本次需要的最大升到本层的最高处(j-i-1),关于减去i+1是因为当i=1时,已经有一个归位了,只需要循环剩下的部分即可。
选择√
选择:
每次选择最小的,放到应该放的位置
选 n-1 次完事void select_sort(int*& arr, int len) { for (int i = 0; i < len -1; i++)//只需要比较len-1即可。 { int min_index = i;/*挑出最小的放在最前面,默认在i之后的数组里,下表为i的位置为min*/ for (int j = i;j < len; j++)//此处必须是len,剩下的部分都要进行比较 { if (arr[min_index] > arr[j]) min_index = j; } if (min_index != i) swap(arr[min_index], arr[i]); travel(arr,10); } }
插入√插入思路:
把待排数组的第一个元素看成是一个有序数组
然后一个个的把其他元素插入到这个有序数组中去如何插入:
临时存储待插入数据
从待插数据的前一个位置开始 从后往前找插入位置
没找到插入位置前 往后覆盖
找到插入位置 结束循环
然后待插数据覆盖当前位置void insert_sort(int*& arr, int len) { for (int i =0 ; i < len-1; i++) { int j; int temp=arr[i+1];//暂存带插入的元素 arr[i + 1] = arr[i];//覆盖 for ( j = i+1; j >0&&arr[j-1]>temp; j--) {//寻找适合插入的位置(注:less<int>) arr[j] = arr[j - 1]; } arr[j] = temp; travel(arr, 10); } }
注意:参数细节->尤其是arr[j-1]>temp和arr[j]=temp这两个地方。->画图
shell√
shell思路:
先分组 在组内做插入排序
一般是先分成 len/2 组
然后分成 len/2/2 组
。。。。
2组
最后 1组
组的数量 我们称之为 步长(step)
step: len/2 len/4 ... 2 1希尔排序时间复杂度是 O(n^(1.3-2)),空间复杂度为常数阶 O(1)。
void shell_sort(int*& arr, int len) { int step = len / 2; while (step) { for (int i = step; i < len; i++)//恰巧模拟了插入排序的依次向其中插一个一个元素的情况 {//循环插入arr[i] int temp = arr[i]; arr[i] = arr[i - step]; int j ; for (j = i; j >= step&&arr[j-1]>temp; j-=step) { arr[j] = arr[j - step]; } arr[j] = temp; } travel(arr, 10); step /= 2; } }
如何将图中的思想转化为代码->写好希尔排序的参数很重要!!(隔一个step依次插入)
基数排序√
数组下标天然有序
限制超级多:
1. 只能是正整数 (如果有负数,转成正数先)
2. 不能重复
3. 需要特别注意空间O(n)
步骤:
1 .创建一个临时数组
2 .给临时数组全部赋值为一个不会出现的数
3 .根据数组下标来把a数组中数据放到临时数组中去
4 .依序把pTemp中数据放会原数组
5 .释放内存
void redix_sort(int*& p, int len, int max) { int* pArr = new int[max + 1];//开辟内存 int k=0; for (int i = 0; i < max + 1; i++) { pArr[i] = -1;//赋值一个不会出现的数字 } for (int i = 0; i < len; i++) { pArr[p[i]] = p[i];//根据索引自动进行 } for (int i = 0; i < max + 1; i++) { if (pArr[i] != -1) p[k++] = pArr[i]; } delete[]pArr; }
桶(箱)√
桶(箱)排序:
先把数据分成若干个桶,然后桶内用其他排序方式排序,排完之后再合并
非常稳定空间换时间
注:思路图见->桶排序 - 简书 (jianshu.com)
依次让个位有序、让十位有序、让百位有序···
void bucket_sort(int*& p, int len) { int** Arr = new int* [10];//0-9 1.先把桶准备好 for (int i = 0; i < 10; i++) { Arr[i] = new int[len]; } int wei = 1; while(wei<AREA) { for (int i = 0; i < 10; i++) { for (int j = 0; j < len; j++) { Arr[i][j] = -1;//初始化桶 } } //2.在0-9的桶去对应,第一次的遍历为个位顺序,第二次为十位顺序 for (int i = 0; i < 10; i++)//每个桶进行分类 { for (int j = 0; j < len; j++) { if (p[j] / wei % 10 == i) Arr[i][j] = p[j]; } } travel(p, len); //3. 放完之后,依次取出(第一次取出就已经能保证是个位有序的了。。。 int k = 0; for (int i = 0; i < 10; i++) { for (int j = 0; j < len; j++) { if (Arr[i][j] != -1) p[k++] = Arr[i][j]; } } wei *= 10; } }
(其余下次)
归并、分组 快排、堆排序
20227.17补:计数排序(解决重复元素问题)
void CountSort(int array[], int arrayNum) { //准备一个容器, int* countArray = (int*)calloc(sizeof(int), 100); //calloc自动初始化位0 assert(countArray); for (int i = 0; i < arrayNum; i++) { countArray[array[i]]++; //把数据当做数组下标,去统计元素出现次数 } int* sortArray = (int*)malloc(sizeof(int) * arrayNum); assert(sortArray); int k = 0; for (int i = 0; i < 100; i++) { //printf("%d\n", countArray[i]); while (k<arrayNum &&countArray[i] != 0) { sortArray[k++] = i; countArray[i]--; } } memcpy(array, sortArray, arrayNum * sizeof(int)); //还原到原数组 free(countArray); free(sortArray); }
桶、基数排序的其他写法:
//8.基数排序(桶排序的升级版) //拆分数字的每一位: 辅助函数 int getPosNum(int num, int pos) { int temp = 1; //123 for (int i = 0; i < pos - 1; i++) //123/100 { temp *= 10; //123/10 12 } return (num / temp) % 10; //123/10=12%10=2 } void BucketSort(int array[], int arrayNum, int pos) { int* bucketArray[10] = { NULL }; for (int i = 0; i < 10; i++) { bucketArray[i] = (int*)calloc(sizeof(int), arrayNum); assert(bucketArray[i]); } //装桶 for (int i = 0; i < arrayNum; i++) { int index = getPosNum(array[i], pos); for (int j = 0; j < arrayNum; j++) { if (bucketArray[index][j] == 0) { bucketArray[index][j] = array[i]; break; } } } //出桶 int k = 0; for (int i = 0; i < 10; i++) { for (int j = 0; j < arrayNum; j++) { if (bucketArray[i][j] != 0) { array[k] = bucketArray[i][j]; bucketArray[i][j] = 0; k++; } } } } //找最大值 int getMaxNum(int array[], int arrayNum) { int max = array[0]; for (int i = 1; i < arrayNum; i++) { if (max < array[i]) max = array[i]; } return max; } //最大值有多位 int getMaxNumCount(int num) { int count = 1; while (num / 10) { count++; num /= 10; } return count; } //基数排序 void RadixSort(int array[], int arrayNum) { int maxNum = getMaxNum(array, arrayNum); int loop = getMaxNumCount(maxNum); for (int i = 1; i <= loop; i++) { BucketSort(array, arrayNum, i); } }
二、 运算时间测量:
法一:
头文件:#include<windows.h>
函数:GetCurrentTime()返回ms
法二:<time.h>的clock()方法和常数CLOCKS_PER_SEC(推荐)![](https://img-blog.csdnimg.cn/ba706b20a4af40dd8dd66cd400b160f4.png)
核心:clock()&CLK_TCK&double强制转化