排序算法之归并排序(Python-C++)
今天我们来学习一下归并排序的算法, 归并排序呢相对于前面的冒泡啊,插入啊,选择啊,速度和效率上是有明显优势的,尤其是对于大数据的排序效果更好,对于小数据可以使用前面的算法,如果对于大数据还使用前面的算法,,,你试试1G的数据排序要多久,10G,100G呢?
归并排序算法原理:
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并算法呢,对于两个相对有序的数组排序会非常快,比如下面两个数组:
int arr1[] = {1,3,5,7};
int arr2[] = {2,4,6,8};
那么对于这两个数组归并算法是如何进行处理的呢?
很简单,就是简单的对比,小的放前面,大的放后面
定义一个新数组放排序好的数
int arr3[8] = {0};//数组长度呢是两个数组的和
第一步:1和3进行比较,1小,所以1放进新数组arr3[0] = 1,然后arr1自增一
第二步:3和2比较,2小,所以2放进新数组arr3[1] = 2,然后arr2自增一
第二步:3和4比较,3小,所以3放进新数组arr3[2] = 3,然后arr1自增一
第二步:5和4比较,4小,所以4放进新数组arr3[3] = 4,然后arr2自增一
…直到比完
如果数组未奇数,则最后一个元素后就不比较了,直接追加到arr3的尾部,至此完成排序
那么一般排序都是一个数组啊,你怎么整两个数组排序呢?其实啊我这里是把一个数组分两半来给你们解释归并是如何进行的,一般啊要归并的数组是这样的[1,3,5,7,2,4,6,8],即一个数组的前一半和后一半相对是有序的这样才能进行归并。
完整代码:
Python代码:
def merge_list(sort_list1,sort_list2):
i = j = 0
r_list = []
while i < len(sort_list1) and j < len(sort_list2):
if sort_list1[i] < sort_list2[j]:
r_list.append(sort_list1[i])
i += 1
else:
r_list.append(sort_list2[j])
j += 1
while i < len(sort_list1):
r_list.append(sort_list1[i])
i += 1
while j < len(sort_list2):
r_list.append(sort_list2[j])
j += 1
return r_list
C++代码:
void mergeList(int* list, int left, int mid, int right,int *r_list) {
int i = left;//左边数组起始位置
int j = mid;//分割位置
int k = left;//存放新数据数组的起始位置
while (i < mid && j <=right)//当左边数组没有到尾部,或者右边数组没有到尾部的时候持续循环
{
if (list[i] < list[j]) {//如果左边数组的数小于右边数组的数
r_list[k++] = list[i++];//把小数追加到新数组里存起来,然后继续下一个数比较
}
else
{//否则就是右边数组小,就把右边数组的数存到新数组里,然后右边数组拿出下一个数作比较
r_list[k++] = list[j++];
}
}
//这里是为了解决当出现排序数组为奇数或者左边数组的数全部比右边数组的数大(或者反着的情况)的情况,这样会造成有一个数组的数没有读取完或者完全没有读取,这里判断一下,如果没到尾部,那么就把剩下的数都追加到新数组尾部把,剩下的肯定是最大的。
while (i < mid)
{
r_list[k++] = list[i++];
}
while (j <= right)
{
r_list[k++] = list[j++];
}
memcpy(list + left, r_list + left, sizeof(int) * (right - left + 1));//将新数组数据还给原数组
}
好了,归并的原理就是这样的,那么就有疑问了,哪有呢么多数组都是这样的特例情况,难道普通的无序数组就不能排序了么?那当然是可以啊,这里又要用到分治法了哦,‘
所以 归并算法 = 分治法 + 归并
归并只能处理两个相对有序的数组,那么我们拆分来想
以以下数组为例:
int arr[10] = {161,152,131,178,165,122,177,181,199,145};
这样一个数组前后无序怎么排序啊,那我们先给他执行二分,分成两半
原数组:[161,152,131,178,165,122,177,181,199,145]
第一次:
[161,152,131,178,165] - [122,177,181,199,145]
还是不行啊,那我们继续
第二次:
[161,152]----[ 131,178,165]
[122,177]----[181,199,145]
还是无序 啊,继续,分就完了
第三次:
[161]----[152]
[ 131]----[178,165]
[122]----[177]
[181,199,145]
第四次:
[161]----[152]
[ 131]
[178]----[165]
[122]----[177]
[181]
[199]----[145]
好了,这次是不是看出什么了,
当我们分到一个数得时候是不是就是有序数组了,即使这个数组只有一个元素,这样不就可以使用归并了么?
我们这里直接上代码讲解:
Python代码:
def merge_sort(sort_list):
if len(sort_list) <=1:
return sort_list
middle = len(sort_list) // 2
left = merge_sort(sort_list[:middle])
right = merge_sort(sort_list[middle:])
return merge_list(left,right)
C++代码:
void mergeSort(int *list,int left,int right,int *tempList){
int mid = 0;//初始化分割的位置
if (left < right) {//当左边起始位置不等于右边起始位置的时候就表示还没有分到成为数组元素为一个的时候,即[0,0],所以继续调用归并
mid = left + (right - left)/2;//防止越界
mergeSort(list,left,mid,tempList);//左边数组范围
mergeSort(list,mid +1,right,tempList);//右边数组范围
//分成有序的以后执行归并,然后递归函数返回上一级,再执行归并
mergeList(list,left,mid+1,right,tempList);
}
}
如此便完成了归并排序,重要的是理解思想与方法,实现方式也并不是唯一!