算法分析与设计——分治策略求逆序对(归并排序)
企业开发
2023-12-17 20:24:22
阅读次数: 0
1、算法讲解
- 利用分治策略求逆序对主要是利用归并排序,即合并两个有序数组。
- 假设有两个有序的数组,我们对其进行归并排序。
- 从两数组开头开始比较。
- 由于2>1,1先入队,并且知道1比前面数组的所有元素都小(数组有序),所以记录逆序个数=4。
- 继续比较2和4,由于2<4,2先入队,并且2比后面数组的所有元素都小,所以没有逆序对。
- 继续比较3和4,由于3<4,3先入队,并且3比后面数组的所有元素都小,所以没有逆序对。
- 继续比较5和4,由于5>4,4先入队,并且知道4比前面数组的所有元素都小(数组有序),所以记录逆序个数=4+2。
- 继续比较5和6,由于5<6,5先入队,并且5比后面数组的所有元素都小,所以没有逆序对。
- 继续比较7和6,由于7>6,6先入队,并且知道6比前面数组的所有元素都小(数组有序),所以记录逆序个数=4+2+1。
- 继续比较7和8,由于7<8,7先入队,并且7比后面数组的所有元素都小,所以没有逆序对。
- 此时前面数组的所有元素都已合并,最后把8合并即可。最后计算出逆序对个数为7。
- 上述算法的前提是两个子数组是有序的,那如何将上述算法的思想运用到普通的数组中呢?
- 可以先将数组进行拆分,单个元素的数组一定是有序的。
- 然后再依次合并两个有序数组,并且在合并的过程中计算逆序对的个数。
- 最后的逆序对个数=1+1+1+1+4+4+16=28。
- 这就是分治的思想。
2、实例
- 采用分治策略完成下述数组的逆序对计数:[12, 14, 53, 8, 74, 23, 17, 66, 70, 9, 34, 75, 90, 34, 98, 50, 86, 94, 3, 67, 73, 79, 43, 66, 19, 20, 57,43, 28, 83]
- python代码:
-
# 计算逆序对
def reverser_pairs(nums):
length = len(nums)
if length < 2: # 数组只有一个元素,没有逆序对
return 0
copy = nums.copy() # 需要对数组进行排序,故拷贝原数组
temp = [] # 辅助数组
return count_pairs(copy, 0, length - 1, temp) # 递归计算逆序对
# 划分数组,归并排序,计算逆序对个数
def count_pairs(nums, left, right, temp):
if left == right: # 划分到只剩一个元素
return 0
mid = left + (right - left) // 2 # 与(left+right)/2效果一致,防止溢出,向下取整
# 划分数组,记录每个子数组的逆序对
left_pairs = count_pairs(nums, left, mid, temp)
right_pairs = count_pairs(nums, mid + 1, right, temp)
# 前面数组已经小于后边数组
if nums[mid] <= nums[mid + 1]:
return left_pairs + right_pairs
# 对子区间内的元素进行归并排序并计算逆序对个数
cross_pairs = merge_and_count(nums, left, mid, right, temp)
return left_pairs + right_pairs + cross_pairs # 累加
# 归并排序,计算逆序对个数
def merge_and_count(nums, left, mid, right, temp):
temp = nums[left:right + 1].copy() # 将区间元素复制出来进行归并排序
i = left
j = mid + 1
count = 0
for k in range(left, right + 1):
if i == mid + 1: # 前面数组都已入队,将后面数组全部入队
nums[k] = temp[j - left]
j += 1
elif j == right + 1: # 后面数组都已入队,将前面数组全部入队
nums[k] = temp[i - left]
i += 1
elif temp[i - left] <= temp[j - left]:
nums[k] = temp[i - left]
i += 1
else:
nums[k] = temp[j - left]
j += 1
count += mid - i + 1 # 小于前面所有的元素
return count
if __name__ == '__main__':
nums = input("请输入整数数组,用空格分隔: ")
nums = [int(i) for i in nums.split(' ')] # 将每个数转换为整型后输出
print("该数组的逆序对个数为:", reverser_pairs(nums))
- 运行结果:
- 输入:12 14 53 8 74 23 17 66 70 9 34 75 90 34 98 50 86 94 3 67 73 79 43 66 19 20 57 43 28 83
转载自blog.csdn.net/weixin_45100742/article/details/134545772