排序整数数组的快速方法?

时间:2015-06-22 21:04:12

标签: arrays algorithm bash sorting integer

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

我实际上需要算法在不到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的新手,所以我甚至不知道这是否是一种有效的方式;

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

有什么想法吗?

提前致谢,

3 个答案:

答案 0 :(得分:2)

数字范围<0,1000000)足够小

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

所以Bucket排序是可能的:

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

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

    • for (int i=0;i<1000000;i++) flag[i]=0;
  3. 通过处理数组arr[N] ... O(N)

    来计算标记
    • for (int i=0;i<N;i++) flag[arr[i]]=1;
    • 重复只是递增flag [],除非它太大而不能避免溢出
    • 如果flag[arr[i]]已经1,则返回distance = 0
  4. 重建数组O(M)

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

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

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

答案 1 :(得分: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;}'

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

答案 2 :(得分:1)

鉴于sorting algorithm complexity上的这个精彩页面,我会使用Radix Sorthere in Python,我没有找到Bash实现,但我还在寻找):< / p>

#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))