如何根据中位数将列表拆分为 2 个未排序的分组

How to split a list into 2 unsorted groupings based on the median

我的目标是将列表分类为不需要分类的两个小节。

假设我有一个长度为 10 的列表,其中包含值 0-9。

arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]

我希望以索引 0 到 4 包含值 10、20、30、40 和 50 的任何顺序的方式对其进行排序。

例如:

#         SPLIT HERE V
[40, 30, 20, 50, 10,     70, 60, 80, 90, 100]

我研究了各种分而治之的排序算法,但我不确定在这种情况下使用哪种算法最好。

我目前的想法是使用快速排序,但我相信有更好的方法来完成我正在寻找的事情,因为不需要对所有内容进行精确排序,而是在所有值的“一般”意义上进行排序在任何顺序中都位于中位数的各自一侧。

statistics 程序包有一种方法可以计算一列数字的中位数。从那里,您可以使用 for 循环根据值是否大于中位数将值分成两个单独的列表:

from statistics import median

arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]
med = median(arr)

result1 = []
result2 = []

for item in arr:
    if item <= med:
        result1.append(item)
    else:
        result2.append(item)
        
print(result1)
print(result2)

这输出:

[50, 30, 20, 10, 40]
[90, 100, 70, 60, 80]

您可以使用 numpy 执行此操作(如果 arr 很大,它会明显更快):

import numpy as np
arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]
arr = np.array(arr)
median = np.median(arr)
result1 = arr[arr <= median]
result2 = arr[arr > median]

输出:

array([50, 30, 20, 10, 40])
array([ 90, 100,  70,  60,  80])

如果你想要一个列表作为输出,你可以这样做:

[*result1, *result2]

输出:

[50, 30, 20, 10, 40, 90, 100, 70, 60, 80]

如果您想从头开始解决问题,您可以实现 Median of Medians algorithm 以在线性时间内找到未排序数组的中位数。那要看你的目标是什么了。

如果您想就地重新排序,您可以使用中位数中位数算法的结果 select 分区算法的枢轴(快速排序的一部分)。

另一方面,使用 python 您可以遍历数组并将值分别附加到左侧或右侧数组。

其他当前的其他答案将列表分成两个列表,根据您的示例,我的印象是有两个分组,但输出是一个列表。

import numpy as np

# setup
arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]
# output array
unsorted_grouping = []
# get median
median = np.median(arr)

# loop over array, if greater than median, append. Append always assigns
# values at the end of array
# else insert it at position 0, the beginning / left side
for val in arr:
    if val >= median:
        unsorted_grouping.append(val)
    else:
        unsorted_grouping.insert(0, val)

# output
unsorted_grouping

[40, 10, 20, 30, 50, 90, 100, 70, 60, 80]

您可以使用 statistics 模块计算中位数,然后使用它将每个值添加到一组或另一组:

import statistics

arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]

median = statistics.median(arr)
bins = [], []  # smaller and bigger values
for value in arr:
    bins[value > median].append(value)

print(bins[0])  # -> [50, 30, 20, 10, 40]
print(bins[1])  # -> [90, 100, 70, 60, 80]

对我来说,这似乎可以解决问题,除非您确实需要无序输出:

arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]

sorted_arr = sorted(arr)
median_index = len(arr)//2
sub_list1, sub_list2 = sorted_arr[:median_index],sorted_arr[median_index:]

这输出:

[10, 20, 30, 40, 50] [60, 70, 80, 90, 100]

我的第一个Python节目,还请多多包涵。

基本上按照您的建议进行快速排序,但仅 sub-sorts 包含中值索引的分区。

arr = [50, 30, 20, 10, 90, 40, 100, 70, 60, 80]

def partition(a, left, right):

    pivot = (left + right)//2
    a[left],a[pivot] = a[pivot], a[left] # swap
    pivot = left
    left += 1

    while right >= left :
        while left <= right and a[left] <= a[pivot] :
            left += 1
        while left <= right and a[right] > a[pivot] :
            right -= 1

        if left <= right:
            a[left] , a[right] = a[right], a[left]
            left += 1
            right -= 1
        else:
            break

    a[pivot], a[right] = a[right] , a[pivot]

    return right


def medianSplit(array):
    left = 0;
    right = len(array) - 1;
    med = len(array) // 2;
    while (left < right):
      pivot = partition(array, left, right)
      if pivot > med:
        right = pivot - 1;
      else:
        left = pivot + 1;

def main():
    medianSplit(arr)   
    print(arr)

main()