关于计算数组逆序数的Python分治代码的疑问咨询
让我逐个帮你拆解这段Python代码,解答你的三个疑问:
疑问1:左右子数组长度为1时的处理逻辑与逆序数统计
你的推测大体是对的——代码采用类似归并排序的分治思路,不断拆分数组直到子数组长度为1。但长度为1的子数组本身不会触发逆序数统计,因为单个元素不存在逆序对,此时函数会直接返回该子数组(不进入if len(x) > 1的分支)。
逆序数的统计发生在回溯合并两个长度为1的子数组的时候:
比如左子数组是[3],右子数组是[2],合并时会进入elif a[i] > b[j]的分支:
- 把
b[j](也就是2)放到结果数组x中 - 执行
count += (len(a)-i),这里len(a)是1,i是0,所以count加1,正好统计了(3,2)这个逆序对 - 之后处理剩余的左子数组元素,完成合并。
疑问2:midsection元素的去向
你这里是对Python切片规则产生了误解:
代码中leftArray = x[:midsection]是取数组x中从开头到索引midsection-1的元素,而rightArray = x[midsection:]是取从索引midsection到数组末尾的元素。也就是说,midsection对应的元素是rightArray的第一个元素,并没有被遗漏。
举个例子:如果原数组是[5,2,7,1],midsection = 4//2 = 2,那么leftArray = [5,2],rightArray = [7,1],所有元素都被分到了左或右子数组中,不存在“无主”元素。
疑问3:排序逻辑的位置
你说的没错——count += (len(a)-i)的正确性确实依赖左右子数组已经排序,而这段代码的排序逻辑就藏在递归回溯的合并过程中:
当递归调用inversionsCount(leftArray)和inversionsCount(rightArray)时,这两个调用会分别把leftArray和rightArray排序好(函数返回的就是排序后的数组,而且因为列表是可变对象,递归中对leftArray/rightArray的修改会直接作用于原列表)。
当进入合并步骤时,a = leftArray和b = rightArray已经是两个有序的子数组了,这时候如果a[i] > b[j],说明a中从i到末尾的所有元素都比b[j]大,这些元素和b[j]都构成逆序对,所以用len(a)-i来统计这部分逆序数是完全正确的。
内容的提问来源于stack exchange,提问作者n.y

