【问题标题】:Very fast way to sort array of integers?对整数数组进行排序的非常快速的方法?
【发布时间】:2015-09-08 11:37:56
【问题描述】:

我带着刚刚写的解决方案来到这里,但我绝对找不到更好的方法来尽快对数组进行排序。

我实际上需要算法在不到 1 秒的时间内在包含 100'000 个整数的数组上给我答案。

代码如下:

read N
for (( i=0; i<N; i++ )); do
    read arr[i]
done

sorted=($(printf '%s\n' "${arr[@]}"|sort -n))

min=$(( sorted[1]-sorted[0] ))

for (( i=1; i<N-1; i++ )); do
    diff=$(( sorted[i+1] - sorted[i] ))
    if [ "$diff" -lt "$min" ]; then
        min=$diff
    fi
done

echo $min

N 是元素的数量,如我所说,在我们的例子中是 100'000。

问题是,在我的数组排序后,我需要遍历它并计算两个整数之间的最小距离:

例如,对于 (3, 5, 8, 9),最小距离为 1(在 8 和 9 之间)。

我是 Bash 的新手,所以我什至不知道这是否是一种有效的方法;

事实上,速度的提升可能来自代码的第二部分,而不是排序部分......

有什么想法吗?

提前致谢,

【问题讨论】:

  • 您希望优化您当前的代码还是想要更快的不同代码?
  • 第二部分求线性时间内的最小距离。我认为您无法获得更好的(渐近)性能
  • 如果您的整数已知是固定集合,则桶排序会更快 O(N)。
  • 必须是 bash 吗?由于所有不必要的字符串解析,bash 是您可以为此类内容选择的最糟糕的语言。我敢打赌,通过用编译语言重新编码,你会轻松获得 10 倍的加速。
  • @BrentWashburne 这个问题可能是代码审查的一个好问题,但首先要问一个问题:堆栈溢出是否题外话?这是迁移最重要的要求。 Code Review 不是 Stack Overflow 的迁移目标,因此只有 自定义标志 才能将问题移到那里,如果您认为应该移动它。

标签: arrays algorithm bash sorting integer


【解决方案1】:

数字范围&lt;0,1000000) 足够小

  • 因为你的数字不是重复的(最小距离是>=40)
  • 那么您只需要每个值一个位(如果存在或不存在)
  • 因此您需要最多 1MB 的字节/值或最多 128KB 的位/值
  • (因为K,M是基于1024所以你有足够大的储备)

所以桶排序是可能的:

  1. 为每个可能的值创建标志数组

    • bool flag[1000000];
  2. 清除标志O(M)

    • for (int i=0;i&lt;1000000;i++) flag[i]=0;
  3. 通过处理您的数组 arr[N] ... O(N) 来计算标志

    • for (int i=0;i&lt;N;i++) flag[arr[i]]=1;
    • 对于重复只增加 flag[] 除非它太大而无法避免溢出
    • 如果flag[arr[i]] 已经是1,则返回distance = 0
  4. 重构数组O(M)

    • for (int i=0,j=0;i&lt;1000000;i++) if (flag[i]) { arr[j]=i; j++; } N=j;
  5. 现在计算距离O(N)

    • 您可以将这些步骤混合在一起,这样就不需要内存中的arr[N]
    • 而不是只计算flag[] 中的后续零...

[备注]

  • M=1000000
  • N&lt;=M
  • 如果NM 小得多,那么这可能不是最快的方法...

【讨论】:

  • 这似乎是一个很好的解决方案,你解释得很好,谢谢你!我将为此检查 bash 语法并尽快发布我的结果:)
【解决方案2】:

我终于想出了一个简单而优雅的解决方案:

read N

for (( i=0; i<N; i++ )); do
    read tab[i]
done

printf "%i\n" ${tab[@]} | sort -n | awk 'BEGIN{dmin=1000000;} (NR>1){d=$1-prec; if (d<dmin) dmin=d;} {prec=$1;} END{print dmin;}'

就是这样。 :) 感谢大家抽出时间来帮助我! ;)

【讨论】:

  • 看起来像codingame上的马拼图解决方案;)
【解决方案3】:

鉴于sorting algorithm complexity 上的这个很棒的页面,我将使用Radix Sorthere in Python,我没有找到 Bash 实现,但我仍在寻找):

#python2.6 <
from math import log

def getDigit(num, base, digit_num):
    # pulls the selected digit
    return (num // base ** digit_num) % base  

def makeBlanks(size):
    # create a list of empty lists to hold the split by digit
    return [ [] for i in range(size) ]  

def split(a_list, base, digit_num):
    buckets = makeBlanks(base)
    for num in a_list:
        # append the number to the list selected by the digit
        buckets[getDigit(num, base, digit_num)].append(num)  
    return buckets

# concatenate the lists back in order for the next step
def merge(a_list):
    new_list = []
    for sublist in a_list:
       new_list.extend(sublist)
    return new_list

def maxAbs(a_list):
    # largest abs value element of a list
    return max(abs(num) for num in a_list)

def split_by_sign(a_list):
    # splits values by sign - negative values go to the first bucket,
    # non-negative ones into the second
    buckets = [[], []]
    for num in a_list:
        if num < 0:
            buckets[0].append(num)
        else:
            buckets[1].append(num)
    return buckets

def radixSort(a_list, base):
    # there are as many passes as there are digits in the longest number
    passes = int(round(log(maxAbs(a_list), base)) + 1) 
    new_list = list(a_list)
    for digit_num in range(passes):
        new_list = merge(split(new_list, base, digit_num))
    return merge(split_by_sign(new_list))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 2011-01-01
    相关资源
    最近更新 更多