算法学习 1.2 归并排序

1.2 归并排序

"""
递归:每次选择数组中点,左右两边都已排好序,只需将有序的两边合并
"""


def merge_sort(arr, left, right):
    """
    归并排序
    :param arr: 待排序数组
    :param left: 需排序的元素范围的左下标,对整个数组排序时,初始为0
    :param right: 需排序的元素范围的右下标,对整个数组排序时,初始为数组长度减1
    :return:
    """
    if right - left <= 0:
        # 当排序范围内元素数量不超过1时已经是有序
        return
    # 获取元素范围的中点
    mid = int((left + right) / 2)
    # 递归排数组左边的元素
    merge_sort(arr, left, mid)
    # 递归排数组右边的元素
    merge_sort(arr, mid + 1, right)
    # 对上述已经排好序的左右两边进行合并
    merge(arr, left, mid, right)


def merge(arr, left, mid, right):
    temp_list = []
    i = left
    j = mid + 1
    while i <= mid and j <= right:
        if arr[i] <= arr[j]:
            # 合并左边
            temp_list.append(arr[i])
            i += 1
        else:
            # 合并右边
            temp_list.append(arr[j])
            j += 1
    if i > mid:
        # 合并右边剩余元素
        temp_list.extend(arr[j:right + 1])
    else:
        # 合并左边剩余元素
        temp_list.extend(arr[i:mid + 1])
    for k in range(left, right + 1):
        arr[k] = temp_list[k - left]


if __name__ == '__main__':
    import random

    def get_list(n=10, min_num=0, max_num=10):
        return [random.randint(min_num, max_num) for _ in range(n)]

    arr_list = get_list()
    print(arr_list)
    merge_sort(arr_list, 0, len(arr_list) - 1)
    print(arr_list)
小和问题
"""
小和:当前元素前面比该元素值小的元素值求和,对每个元素进行这么处理后的累计和

示例:
1 3 2 4
数组0位置前面小的数 + 数组1位置前面小的数 + ...
0 + 1 + 1 + (1+3+2) = 8

该问题相当于:对当前元素来说,求后边有多少个元素值比自己大,然后用自身值乘上数量,再对每个元素依次操作累计求和
"""


def get_min_sum(arr, left, right):
    if right - left < 1:
        return 0

    mid = int((left + right) / 2)
    count_left = get_min_sum(arr, left, mid)
    count_right = get_min_sum(arr, mid + 1, right)
    count_merge = merge(arr, left, mid, right)
    return count_left + count_right + count_merge


def merge(arr, left, mid, right):
    i = left
    j = mid + 1
    temp_list = []
    count_merge = 0

    while i <= mid and j <= right:
        if arr[i] < arr[j]:
            temp_list.append(arr[i])
            # 当前值乘以右边大于该值的元素数量
            count_merge += arr[i] * (right - j + 1)
            i += 1
        else:
            # 重要:当左右相等时,需要先把右边的添加。
            temp_list.append(arr[j])
            j += 1

    if i > mid:
        temp_list.extend(arr[j:right + 1])
    else:
        temp_list.extend(arr[i:mid + 1])

    for i in range(left, right + 1):
        arr[i] = temp_list[i - left]

    return count_merge


if __name__ == '__main__':
    import random


    def get_list(n=10, min_num=0, max_num=10):
        return [random.randint(min_num, max_num) for _ in range(n)]

    arr_list = get_list(5)
    print(arr_list)
    count = get_min_sum(arr_list, 0, len(arr_list) - 1)
    print(arr_list)
    print(count)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值