归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
归并排序是一种稳定的排序算法,和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。
/// <summary>
/// 这是归并排序,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
/// 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,
/// 再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
/// 归并排序是一种稳定的排序方法。和选择排序一样,
/// 归并排序的性能不受输入数据的影响,
/// 但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static List<int> MergeSort(List<int> list)
{
if(list.Count<=1)//若集合内元素只有一个,不需要排序,返回
{
return list;
}
int mid = list.Count / 2;
List<int> left = new List<int>();//将list集合分为左右两个小集合,分别加入这两个小集合
List<int> right = new List<int>();
for (int i = 0; i < mid; i++)
{
left.Add(list[i]);
}
for (int i = mid; i < list.Count; i++)
{
right.Add(list[i]);
}
left = MergeSort(left);//两个小集合通过递归排序
right = MergeSort(right);
return Merge(left, right);//合并两个小集合,在合并过程中排序
}
public static List<int> Merge(List<int> left, List<int> right)
{
List<int> temp = new List<int>();//temp为存放两个小集合合并后的的临时集合
while(left.Count!=0 && right.Count!=0)//循环取两个小集合中最小的元素加入temp中
{
if(left[0]<=right[0])
{
temp.Add(left[0]);
left.RemoveAt(0);
}
else
{
temp.Add(right[0]);
right.RemoveAt(0);
}
}
//此次循环跳出后,一定是left.Count!=0 && right.Count!=0条件不满足了。
//即有可能其中一个集合有剩余元素没有加入(当然最好的情况是两个集合元素已经都加入了)
//不会出现两个集合都有剩余元素的情况
if (left.Count>0)//对于没有加入的元素,加入temp就好了
{
for (int i = 0; i < left.Count; i++)
{
temp.Add(left[i]);
}
}
if(right.Count>0)
{
for (int i = 0; i < right.Count; i++)
{
temp.Add(right[i]);
}
}
return temp;
}
以下是C++版本的代码
void Merge(int arr[], int l, int mid, int r)
{
int* help = new int[r - l + 1]; //开辟一个新的数组空间O(N)
int i = 0;
int p1 = l; //左侧的指针
int p2 = mid + 1; //右侧的指针
while (p1 <= mid && p2 <= r) //数组的左侧和右侧的元素不断进行对比,较小的元素赋值进数组
{
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p2 <= r) //将两侧剩余的较大的元素全部赋值进去
help[i++] = arr[p2++];
while (p1 <= mid) //和上一个while循环一样,这两个while循环只能发生一个
help[i++] = arr[p1++];
for (int i = 0; i < r - l + 1; i++) //将help数组赋值给arr数组
arr[l + i] = help[i];
delete[]help; //c++需要手动删除,进行内存管理
}
void Mergesort(int arr[], int l, int r)
{
if (l == r)
return;
int mid = l + (r - l) / 2;
Mergesort(arr, l, mid); //左侧排好序
Mergesort(arr, mid + 1, r); //右侧排好序
Merge(arr, l, mid, r); //排序
}