十大排序算法之 归并排序


活动地址:CSDN21天学习挑战赛

正文

  • At first,我们先look一张我从某文章*的表格,来了解一下这几大算法
    alt

  • 图都看了,那我也不得不提一嘴,图里面的东西了

    • 算法效率
      在一个算法设计完成后,还需要对算法的执行情况做一个评估。一个好的算法,可以大幅度的节省运行的资源消耗和时间。在进行评估时不需要太具体,毕竟数据量是不确定的,通常是以数据量为基准来确定一个量级,通常会使用到时间复杂度和空间复杂度这两个概念。

    • 时间复杂度
      通常把算法中的基本操作重复执行的频度称为算法的时间复杂度。算法中的基本操作一般是指算法中最深层循环内的语句(赋值、判断、四则运算等基础操作)。我们可以把时问频度记为T(n),它与算法中语句的执行次数成正比。其中的n被称为问题的规模,大多数情况下为输入的数据量。

      对于每一段代码,都可以转化为常数或与n相关的函数表达式,记做f(n)。如果我们把每一段代码的花费的时间加起来就能够得到一个刻画时间复杂度的表达式,在合并后保留量级最大的部分即可确定时间复杂度,记做O(f(n)),其中的O就是代表数量级。
      常见的时间复杂度有(由低到高): O(1)、O(log2 n)、O(n)、O(n log2n)、O(n2)、o(n3)、O(2")、O(nl)。

    • 空间复杂度

    程序从开始执行到结束所需要的内存容量,也就是整个过程中最大需要占用多少的空间。为了评估算法本身,输入数据所占用的空间不会考虑,通常更关注算法运行时需要额外定义多少临时变量或多少存储结构。如:如果需要借助一个临时变量来进行两个元素的交换,则空间复杂度为O(1).

时间复杂度与空间复杂度的分类

时间复杂度

  • 最坏的情况
    最坏的情况莫过于,完整的遍历了整个集合,也没有找到需要找的的元素,循环执行次数与n相关,所以时间复杂度为O(n).

  • 最好的情况
    第一次循环便找到了元素,则时间复杂度为常数级O(1);

  • 平常的情况
    综合两种情况,顺序查找的时间复杂度为O(n),属于查找较慢的算法。

空间复杂度

算法不会改变原有的元素集合,只需要一个额外的变量控制索引变化,所以空间复杂度为常数级:O(1)。

归并排序 Merge Sort

  • 什么是归并排序
    归并字面上的意思是合并,归并算法的核心思想是分治法,就是将一个数组一刀切两半,递归切,直到切成单个元素,然后重新组装合并,单个元素合并成小数组,两个小数组合并成大数组,直到最终合并完成,排序完毕。

看图说话alt
alt
伪代码:

    n1=q-p+1;
    n2=r-q;
    create new arrays L[n1+1] and R[n2+1]
    for i=0 to n1-1
        L[i]=A[p+i]
    for j=0 to n2-1
        R[j]=A[q+1+j]
    L[n1]=1000//假设1000是无穷大
    R[n2]=1000
    i=j=0
    for k=p to r
        if(L[i]<=R[j])
            A[k]=L[i]
            i=i+1
        else
            A[k]=R[j]
            j=j+1
MERGE_SORT(A,p,r)
    if p<r
        q=floor((p+r)/2)
        MERGE_SORT(A,p,q)
        MERGE_SORT(A,q+1,r)
        MERGE(A,p,q,r)
        ~~~

归并排序:把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。可从上到下或从下到上进行。

~~~c++
template<typename T>
void merge_sort(T arr[], int len) {
	T* a = arr;
	T* b = new T[len];
	for (int seg = 1; seg < len; seg += seg) {
		for (int start = 0; start < len; start += seg + seg) {
			int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
			int k = low;
			int start1 = low, end1 = mid;
			int start2 = mid, end2 = high;
			while (start1 < end1 && start2 < end2)
				b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
			while (start1 < end1)
				b[k++] = a[start1++];
			while (start2 < end2)
				b[k++] = a[start2++];
		}
		T* temp = a;
		a = b;
		b = temp;
	}
	if (a != arr) {
		for (int i = 0; i < len; i++)
			b[i] = a[i];
		b = a;
	}
	delete[] b;
}

递归实现:

template<typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end) {
	if (start >= end)
		return;
	int len = end - start, mid = (len >> 1) + start;
	int start1 = start, end1 = mid;
	int start2 = mid + 1, end2 = end;
	merge_sort_recursive(arr, reg, start1, end1);
	merge_sort_recursive(arr, reg, start2, end2);
	int k = start;
	while (start1 <= end1 && start2 <= end2)
		reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
	while (start1 <= end1)
		reg[k++] = arr[start1++];
	while (start2 <= end2)
		reg[k++] = arr[start2++];
	for (k = start; k <= end; k++)
		arr[k] = reg[k];
}

java

 
 
import java.util.Arrays;
 
//归并排序:先分再合
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = {3,1,4,6,22,0,33,2,745,5,56,8};
        int[] temp = new int[arr.length];
        System.out.println("未排序数组:"+ Arrays.toString(arr));
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("已排序数组:"+ Arrays.toString(arr));
    }
 
    //mergeSort()方法:将数组分组出来
    public static void mergeSort(int[] arr,int left,int right,int[] temp){
        //将数组进行分组
        if (left < right){
            int l = left;
            int r = right;
            int middle = (l+r)/2;
            //将分组进行排序整合
            merge(arr,left,middle,right,temp);//将左边的部分继续分
            mergeSort(arr,0,middle,temp);//将右边的部分继续分
            mergeSort(arr,middle+1,r,temp);
        }
    }
 
    public static void merge(int[] arr,int left,int middle,int right,int[] temp){
        int l = left;
        int r = middle+1;
        int t = 0;//用于临时数组下标索引
 
        while(l <= middle && r <= right){
            //先将两个部分整合
            temp[t++] = arr[l] <= arr[r]?arr[l++] : arr[r++];
//            if (arr[l] <= arr[r]){
//                temp[t] = arr[l];
//                t++;l++;
//            }else{
//                temp[t] = arr[r];
//                t++;r++;
//            }
        }
        //如果左边的部分还有元素没有被合并,则接着l继续合并
        while(l <= middle){
            temp[t++] = arr[l++];
//            temp[t] = arr[l];
//            t++;l++;
        }
        //如果右边的部分还有元素没有被合并,则接着r继续合并
        while (r <= right){
            temp[t++] = arr[r++];
//            temp[t] = arr[r];
//            t++;r++;
        }
 
        //将temp临时数组中的元素顺序传到arr数组中
        t = 0;
        int tempLeft = left;
        while(tempLeft <= right){
            arr[tempLeft] = temp[t];
            tempLeft++;t++;
        }
    }
}

参考文章:csm

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luciferau

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值