Sort排序类-2 希尔、归并、快速&小结

希尔排序

  希尔排序的基本思想:
    如果一个序列基本有序,那么插入排序会很高效
    将待排序列划分为若干组,在每一组内进行插入排序,使得子序基本有序
    再对整个序列进行插入排序

  希尔排序示例:
    例如:将n个数据元素分成d个子序列:
     { R[1] , R[1+d] , R[1+2d] , … , R[1+kd]}
     { R[2] , R[2+d] , R[2+2d] , … , R[2+kd]}
     { R[d] , R[2d] , R[3d] , … , R[kd] , R[(k+1)d] }
     其中,d称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后—次排序减为1。

	/*				希尔排序 O(n3/2)
	不稳定排序
	不是标准定义上的希尔排序,只对每次分组的第一组进行了排序
	*/
	template < typename T >
	static void Shell(T arr[],int len,bool ASC = true)
	{
		int d = len;
		do
        {
            d = d/3 + 1; //实践证明/3是最快的,记住即可
			for(int i=d;i<len;i+=d)//分组进行插入排序
			{
				int spe = i;
				T e = arr[i];

				for(int j=i-d;(j>=0)&&(ASC ? (e < arr[j]) : (e > arr[j]) );j-=d)
				{
					arr[j+d] =  arr[j];
					spe = j;
				}
				if(spe != i)
				{
					arr[spe] = e;
				}
			}
		}while(d > 1);
	}

归并排序

  归并排序的基本思想:
    将两个或两个以上的有序序列合并成—个新的有序序列
    有序序列V[0]…V[m]和V[m+1]…V[n-1] ⇢ V[0]…V[n-1]
    这种归并方法称为归并(2个有序序列为2路归并,3个为3路归并)

二路归并示例
    /*			二路归并
    归并排序:将两个以上的有序序列合并成一个新的有序序列
    */
    template < typename T >
    static void Merga(T arr[],T helper[],int begin,int mid,int end,bool ASC = true)
    {
        int i = begin;
        int j = mid + 1;
        int k = begin;

        while( (i <= mid)&&(j <= end) )
        {
            if(ASC ? (arr[i]<arr[j]):(arr[i]>arr[j]) )
            {
                helper[k++] = arr[i++];
            }
            else
            {
                helper[k++] = arr[j++];
            }
        }

        while(i <= mid)//一路全部进去,将另一路遗留的也录入
        {
            helper[k++] = arr[i++];
        }
        while(j <= end)
        {
            helper[k++] = arr[j++];
        }

        for(i=begin;i<=end;i++)//排好序后的序列替代原序列
        {
            arr[i] = helper[i];
        }
    }

	// 归并 的 递归分解
    template < typename T >
    static void Merga(T arr[],T helper[],int begin,int end,bool ASC = true)
    {
        if(begin < end)//只有一个元素时,为有序序列
        {
            int mid = (begin + end) / 2;

            Merga(arr,helper,begin,mid,ASC);//左路分解
            Merga(arr,helper,mid+1,end,ASC);//右路分解
            Merga(arr,helper,begin,mid,end,ASC);//将两个有序序列归并
            //上式不用mid-1,因为begin 0 end 1时,求出的mid仍为0,右路永远分解不到头
        }
    }

	/*                  归并排序 O(nlogn)
    稳定排序,需要辅助空间
    利用递归调用将序列分解为有序序列,再进行二路归并
    */
    template < typename T >
    static void Merga(T arr[],int len,bool ASC = true)
    {
        T* helper = new T[len];

        if(helper)
        {
                Merga(arr,helper,0,len-1,ASC);
        }
        else
        {
                THROW_EXCEPTION(NoEnoughMemoryException,"No memory to creat helper arr ...");
        }
        delete[] helper;
	}

快速排序

  快速排序的基本思想 :
    任取序列中的某个数据元素作为基准将整个序列划分为左右两个子序列
      左侧子序列中所有元素都小于或等于基准元素
      右侧子序列中所有元素都大于基准元素
      基准元素排在这两个子序列中间
    分别对这两个子序列重复进行划分,直到所有的数据元素都排在相应位置上为止

快速排序示例
    //返回基准在数组中的下标(只遍历一次)
    template < typename T >
    static int Partition(T arr[],int begin,int end,bool ASC = true)
    {
        T pv = arr[begin];

        while(begin < end)
        {
            while( (begin < end)&&(ASC ? pv < arr[end] : pv > arr[end]) )
            {
                end--;
            }

            swap(arr[begin],arr[end]);

            while( (begin < end)&&(ASC ? pv >= arr[begin] : pv <= arr[begin]) )
            {
                begin++;
            }

            swap(arr[begin],arr[end]);
        }
        arr[begin] = pv;
        return begin;
    }
    // 快速排序 的 递归分解
    template < typename T >
    static void Quick(T arr[],int begin,int end,bool ASC = true)
    {
        if(begin < end)
        {
            int pivot = Partition(arr,begin,end,ASC);//找基准
            Quick(arr,begin,pivot-1,ASC);//左分路递归找基准
            Quick(arr,pivot+1,end,ASC);//右分路递归找基准
        }
    }
    /*                  快速排序 O(nlogn)
    不稳定排序
    利用递归调用将序列依据基准分开
    */
    template < typename T >
    static void Quick(T arr[],int len,bool ASC = true)
    {
        Quick(arr,0,len-1,ASC);
    }

小结

名称稳定性时间复杂度空间复杂度补充
选择排序不稳定O(N2)O(1)
冒泡排序稳定O(N2)O(1)
插入排序稳定O(N2)O(1)
希尔排序不稳定O(N3/2)O(1)
归并排序稳定O(NlogN)O(N)需要辅助空间O(N)
快速排序不稳定O(NlogN)O(1)最坏情况下为O(N2)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值