目录
- 1.归并排序
- 1.1递归
- 1.1基本思想
- 1.2算法描述
- 1.3画图解释
- 1.4代码实现
- 1.2非递归
- 2.计数排序
- 2.1基本思想
- 2.2算法描述
- 3.画图解释
1.归并排序
1.1递归
1.1基本思想
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
特性:
时间复杂度:O(Nlog N)
空间复杂度:O(N)
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题
1.2算法描述
- 把长度为n的序列分为2个亮度为n/2的子序列
- 对这2个子序列分别采用归并排序
- 将2个排序好的子序列合成一个最终的排序序列
1.3画图解释
1.4代码实现
// 归并排序递归实现
void _MergeSort(int* a,int*tmp, int left,int right)
{//表示该区间只有一个元素或者该区间不存在if (left >= right)return;int mid = left + ((right - left) >> 1);//[left,mid] [mid+1,right]//如果有序就进行归并,没有序就继续分治_MergeSort(a,tmp, left, mid);_MergeSort(a,tmp, mid+1, right);//归并int begin1 = left;int begin2 = mid + 1;int i = left;while (begin1 <= mid && begin2 <= right){//两子序列比较大小if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}//两子序列其中一个序列走完了//1.假设第1个子序列走完了,将第2个子序列放入tmp数组中//2.假设第2个子序列走完了,将第1个子序列放入tmp数组中while (begin1 <= mid){tmp[i++] = a[begin1++];}while (begin2 <= right){tmp[i++] = a[begin2++];}//放入tmp数组完成//将tmp数组的数copy到a数组中memcpy(a+left, tmp+left, (right - left + 1) * sizeof(int));
}
void MergeSort(int* a, int n)
{//申请空间int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}//申请空间成功_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp = NULL;
}
1.2非递归
- 先11归并,再22归并,再44归并…以2的倍数进行归并
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i+ gap - 1;int begin2 = i + gap, end2 =i + 2 * gap - 1;int j = begin1;//如果第二组越界,第二组就不用归并了if (begin2 >= n){break;}//如果第二组只一部分越界,就修改第二组的范围if (end2 >= n){end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2){//两子序列比较大小if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}//两子序列其中一个序列走完了//1.假设第1个子序列走完了,将第2个子序列放入tmp数组中//2.假设第2个子序列走完了,将第1个子序列放入tmp数组中while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}//将tmp数组中元素copy到a数组中memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));}gap *= 2;}free(tmp);tmp = NULL;
}
2.计数排序
2.1基本思想
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
特性:
- 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
- 时间复杂度:O(MAX(N,范围))
- 空间复杂度:O(范围)
2.2算法描述
- 找出待排序的数组中最大和最小的元素;
- 统计数组中每一个值为i的元素出现的次数,存入新数组的第i项;
- 对所有的计数累加;
- 反向填充目标数组:将每个元素i放在新数组的第i项,每放一个元素就-1.
3.画图解释
// 计数排序
void CountSort(int* a, int n)
{//找最大,最小值int max =a[0];int min =a[0];for (int i = 1; i < n; i++){if (max < a[i])max = a[i];if (min > a[i])min = a[i];}//申请空间// 计数int* count = (int*)malloc(sizeof(int) * (max - min + 1));memset(count, 0, sizeof(int)*(max-min+1));for (int i = 0; i < n; i++){count[a[i] - min]++;}//排序int range = (max - min + 1);int j = 0;for (int i = 0; i < range; i++){while (count[i]--){a[j++] = i + min;}}
}