归并排序
思想:
1、先对数据的整体进行划分:把数据划分为左右均等的两部分,继续划分,直到数据分组有序为止;
1、先对数据的整体进行划分:把数据划分为左右均等的两部分,继续划分,直到数据分组有序为止;
2、每个分组只剩下一个元素则是有序的
3、把两个部分(数据)归并成一个部分:逐次归并:给定一个辅助空间,给定一个指针放在第一个数组的起始位置x1,给定另一个指针放在另一个数组的起始位置x2,给定第三个指针放在辅助空间的位置x3比较x1和x2,将较小的元素搬移到辅助空间中,把刚刚较小的那个元素的指针向该数组的下一个位置移动。x3向后走一步,继续比较x1和x2,并搬移元素。
实现代码
//合并需要给定两个数组的空间及辅助空间 void MergeData(int *array, int left, int mid,int right,int *tmp) { //计算出空间的范围 int beginL = left;//左边的左边界 int endL= mid;//左边的右边界 int beginR = mid;//右边的左边界 int endR = right;//右边的右边界 int index = left;//临时空间的起始位置 while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据 { if (array[beginL] < array[beginR]) //搬到辅助空间里去 tmp[index++] = array[beginL++]; else tmp[index++] = array[beginR++]; } //左边的数据没有搬移完 while (beginL < endL) { tmp[index++] = array[beginL++]; } //右边的数据没有搬移完 while (beginR < endR) { tmp[index++] = array[beginR++]; } } void _MergeSort(int *array, int left, int right, int *tmp) { if (right-left>1)//只剩下一个元素则不进行划分 { int mid = left + ((right - left) >> 1); //递归进行划分 //排左边 _MergeSort(array, left, mid, tmp); //排右边 _MergeSort(array, mid, right, tmp); //将两个分组归并成一个分组,放入临时空间里 MergeData(array, left, mid, right, tmp); //把临时空间里面的数据拷贝至待排序的空间中去 memcpy(array + left, tmp + left, sizeof(array[0])*(right - left)); } } void MergeSort(int *array, int size) { //申请辅助空间 int *tmp = (int *)malloc(size*sizeof(array[0])); if (NULL == tmp) { assert(0); return; } //排序 _MergeSort(array, 0, size,tmp); //释放空间 free(tmp); }
时间复杂度:每层需要O(n),平衡树,深度为lgN所以时间复杂度为O(nlgN);没有最好和最差的场景
空间复杂度:O(n):借助了一个辅助空间
稳定性:稳定的,相邻元素归并在一起,不可能出现跨区间交换……
适用于:数据量比较大,一次加载不了的数据(外部排序)
4、非递归的方式实现(也需要辅助空间)
//合并需要给定两个数组的空间及辅助空间 void MergeData(int *array, int left, int mid, int right, int *tmp) { //计算出空间的范围 int beginL = left;//左边的左边界 int endL = mid;//左边的右边界 int beginR = mid;//右边的左边界 int endR = right;//右边的右边界 int index = left;//临时空间的起始位置 while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据 { if (array[beginL] < array[beginR]) //搬到辅助空间里去 tmp[index++] = array[beginL++]; else tmp[index++] = array[beginR++]; } //左边的数据没有搬移完 while (beginL < endL) { tmp[index++] = array[beginL++]; } //右边的数据没有搬移完 while (beginR < endR) { tmp[index++] = array[beginR++]; } } void MergeSortNor(int *array, int size) { int gap = 1; int i = 0; //申请辅助空间 int *tmp = (int *)malloc(size*sizeof(array[0])); if (NULL == tmp) { assert(0); return; } while (gap<size)//gap==size为一个分组,也不用处理 { for (i = 0; i < size; i += 2 * gap)//i+=2*gap:第一次归并第0个和第1个,第二次归并第2个和第三个……两两归并 { //计算区间 int left = i; int mid = left + gap; int right = mid + gap; //归并 if (mid > size)//防止mid越界 mid = size; if (right > size)//防止right越界 right = size; MergeData(array, left, mid, right, tmp); } //将元素拷回去 memcpy(array, tmp, size*sizeof(array[0])); //归并下一次的数据 gap *= 2; } free(tmp); }