归并排序(python实现)

在这里插入图片描述

class MergeSort:
    # 归并排序,本质上是递归,先左边有序,右边有序,然后merge一下
    def merge_sort(self, arr):
        if arr == None or len(arr) < 2:
            return
        self.process(arr, 0, len(arr)-1)

    def process(self, arr, l, r):
        if l == r:
            return
        mid = l + ((r-l) >> 2)
        self.process(arr, l, mid)
        self.process(arr, mid+1, r)
        self.merge(arr, l, mid, r)

    def merge(self, arr, l, mid, r):
        help_ = [0 for i in range(r-l+1)]
        i = 0
        p1 = l
        p2 = mid+1
        # p1和p2都不越界的情况下,如果相等,先拷贝左边
        while p1 <= mid and p2 <= r:
            if arr[p1] <= arr[p2]:
                help_[i] = arr[p1]
                i += 1
                p1 += 1
            else:
                help_[i] = arr[p2]
                i += 1
                p2 += 1

        while p1 <= mid:
            help_[i] = arr[p1]
            i += 1
            p1 += 1

        while p2 <= r:
            help_[i] = arr[p2]
            i += 1
            p2 += 1

        for i in range(len(help_)):
            arr[l+i] = help_[i]

    # 非递归方法
    def merge_sort2(self, arr):
        if arr == None or len(arr) < 2:
            return
        n = len(arr)
        mergeSize = 1  # 当前有序的左组长度
        while mergeSize < n:
            l = 0
            while l < n:
                # l...m 左组 大小为mergeSize
                m = l + mergeSize -1
                if m >= n:
                    break
                r = min(m+mergeSize, n-1)
                self.merge(arr, l, m, r)
                l = r+1
            # 防止溢出,如果mergeSize > n/2,下一句mergeSize = mergeSize << 1,则mergeSize一定>n
            # 所以先判断mergeSize > n/2,如果成立,就不用再去乘2if mergeSize > n/2:
                break
            mergeSize = mergeSize << 1  # 位运算就是快

在这里插入图片描述
关于小和问题,你求一个属左边比它小的数的总和,等同于:当前数,右边有几个数比它大,那么就要加几次这个数。举例,比1大的右边的数有4个,那个求数组小和的时候,一定有4个1相加。
求数组小和实际上就是一个merge的过程

class SmallSum:
 
    def small_sum(self, arr):
        if arr == None or len(arr) < 2:
            return 0
        self.process(arr, 0, len(arr)-1)

    def process(self, arr, l, r):
        if l == r:
            return
        # l < r
        mid = l + ((r-l) >> 2)
        # 左侧小和+右侧小和+整体小和
        return self.process(arr, l, mid) + self.process(arr, mid+1, r) + self.merge(arr, l, mid, r)

    def merge(self, arr, l, mid, r):
        help_ = [0 for i in range(r-l+1)]
        i = 0
        p1 = l
        p2 = mid+1
        res = 0
        while p1 <= mid and p2 <= r:
            if arr[p1] < arr[p2]:
                res += (r-p2+1)*arr[p1]
                help_[i] = arr[p1]
                i += 1
                p1 += 1
            else:
                res += 0
                help_[i] = arr[p2]
                i += 1
                p2 += 1

        while p1 <= mid:
            help_[i] = arr[p1]
            i += 1
            p1 += 1

        while p2 <= r:
            help_[i] = arr[p2]
            i += 1
            p2 += 1

        for i in range(len(help_)):
            arr[l+i] = help_[i]

        return res

求解降序对也可以用到归并排序

归并排序的应用场景

1.每一个数,右边有多少个数比你大,整体数量
2.每一个数,右边有多少个数比你小,整体数量
3.每一个数,左边有多少个数比你大,整体数量
4.每一个数,左边有多少个数比你小,整体数量

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值