Algorithm 高效排序置换

Algorithm 高效排序置换,algorithm,sorting,iterator,permutation,quicksort,Algorithm,Sorting,Iterator,Permutation,Quicksort,给定[n]的未排序排列,我想通过从左到右迭代来收集数字,以便对预排列(1…n)进行排序。 为了达到这个目标,我必须进行多少次迭代? 例如: 给定“3、7、4、2、10、8、9、1、6、5”,迭代次数为6。 在第一次迭代中,我将收集数字1 在第二次迭代中,我将收集数字2 在第三次迭代中,我将收集数字3,4,5 在第四次迭代中,我将收集数字6 在第五次迭代中,我将收集数字7,8,9 在第六次迭代中,我将收集数字10 我构建了一个简单的代码,用O(n^2)完成任务,但我需要它更高效,所以我认为这里缺少

给定[n]的未排序排列,我想通过从左到右迭代来收集数字,以便对预排列(1…n)进行排序。
为了达到这个目标,我必须进行多少次迭代?
例如:
给定“3、7、4、2、10、8、9、1、6、5”,迭代次数为6。
在第一次迭代中,我将收集数字1
在第二次迭代中,我将收集数字2
在第三次迭代中,我将收集数字3,4,5
在第四次迭代中,我将收集数字6
在第五次迭代中,我将收集数字7,8,9
在第六次迭代中,我将收集数字10

我构建了一个简单的代码,用O(n^2)完成任务,但我需要它更高效,所以我认为这里缺少一个技巧。

有什么建议吗?

如果您知道在假设中给定了一个数组,其中肯定存在[n]排列的所有元素,那么我认为:

  • 分配一个数组
    y[1..n]

  • 在从
    1
    n
    的一个循环中,搜索每个迭代中收集项目的未排序元素的初始数组
    x
    y[x[i]]:=x[i]

  • 在循环之后,all in
    y
    是一个带有O(n)的排序排列

  • --编辑时间:2014年12月20日22:54 CET:

    上述解决方案仅适用于以下情况:从
    1
    n
    n-element整数表以任何给定方式无序排列

    我想根据您的示例详细解释如何通过输入阵列只进行一次迭代就可以实现目标

    让我们看一下初始数组:

    x[] = { 3, 7, 4, 2, 10, 8, 9, 1, 6, 5 }
    
    因此,让我们从零开始填充以下数组:

    y[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    
    现在,让以下有序列表中的每一项都是排序算法的迭代:

  • 我们取
    x[1]
    ,它等于
    3
    ——让我们把它写在结果表
    y
    的第三位下:

    y[3]:=3
    (实际上是:
    y[x[1]:=x[1]

    结果表现在如下所示

    y[]={0,0,3,0,0,0,0,0,0}

  • 在第二步中,我们取
    x[2]
    ,它等于
    7
    ,并重复以下步骤:

    y[7]:=7
    (实际上是:
    y[x[2]:=x[2]

    结果表现在如下所示

    y[]={0,0,3,0,0,0,7,0,0,0}

  • 第三步:
    x[3]
    等于
    4

    y[4]:=4
    (实际上是:
    y[x[3]:=x[3]

    结果表:

    y[]={0,0,3,4,0,0,7,0,0,0}

  • x[4]
    等于
    2

    y[2]:=2
    (实际上是:
    y[x[4]:=x[4]

    结果表:

    y[]={0,2,3,4,0,0,0,7,0,0,0}

  • x[5]
    等于
    10

    y[10]:=10
    (实际上是:
    y[x[5]:=x[5]

    结果表:

    y[]={0,2,3,4,0,0,7,0,0,10}

  • x[6]
    等于
    8

    y[8]:=8
    (实际上是:
    y[x[6]:=x[6]

    结果表:

    y[]={0,2,3,4,0,0,7,8,0,10}

  • x[7]
    等于
    9

    y[9]:=9
    (实际上是:
    y[x[7]:=x[7]

    结果表:

    y[]={0,2,3,4,0,0,7,8,9,10}

  • x[8]
    等于
    1

    y[1]:=1
    (实际上是:
    y[x[8]:=x[8]

    结果表:

    y[]={1,2,3,4,0,0,7,8,9,10}

  • x[9]
    等于
    6

    y[6]:=6
    (实际上是:
    y[x[9]:=x[9]

    结果表:

    y[]={1,2,3,4,0,6,7,8,9,10}

  • 最后一次迭代

    x[10]
    等于
    5

    y[5]:=5
    (实际上是:
    y[x[10]:=x[10]

    结果表:

    y[]={1,2,3,4,5,6,7,8,9,10}

  • 正如我们所见,表
    y
    是输入表
    x
    的完全排序版本,它是通过10次迭代生成的(所以O(n)成本水平)。 无论
    n
    有多大,给定的输入表有多无序,在采用这些特定假设的情况下,成本是恒定的,等于
    n


    我希望我没有误解你的问题。

    既然你已经知道结果,我不清楚你在“整理”什么。你在寻找什么样的结果——关于在每次迭代中“收集”哪些数字的信息,如你在Q中所示?在本例中,下面是一个简单的Python 2实现示例:

    target = 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
    
    def do_permut(targ):
        look_for = 1
        iter_num = 1
        while look_for != len(targ) + 1:
            print 'Iteration', iter_num, ':',
            for item in targ:
                if item == look_for:
                    print item,
                    look_for += 1
            print
            iter_num += 1
    
    do_permut(target)
    
    然而,任务不可避免地是O(N平方)——记住,大O代表最坏的情况!对于N个数字,您最多可以进行N次迭代(当
    targ
    从开始就进行反向排序时,最坏的情况就是实现了这一点),因此,N个平方。您可以通过收集以前在迭代过程中看到的一组数字,并在
    look_for
    位于该组时中断,来稍微
    优化每个迭代,但这只(大致)使每个迭代的工作量减半,因此仍然是O(N平方)

    如果你能更好地解释你期望从你的工作中得到什么样的结果和产出,我们可能会提供更多帮助

    出于好奇,这里有一个具有上述“改进”的版本,并且还有一个健全性检查,以确保如果传递的序列不是
    [1:n)
    的排列,它会引发异常,而不是永远循环

    target = 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
    
    def do_permut(targ):
        look_for = 1
        iter_num = 1
        while look_for != len(targ) + 1:
            print 'iteration', iter_num, ':',
            seen = set()
            found_in_iter = 0
            for item in targ:
                seen.add(item)
                if item == look_for:
                    print item,
                    found_in_iter += 1
                    look_for += 1
                    if look_for in seen:
                        break
            print
            if not found_in_iter:
                raise ValueError('missing: %s' % look_for)
            iter_num += 1
    
    do_permut(target)
    
    反转p
    def iterations(perm):
        invperm = [None] * len(perm)
        for i in range(len(perm)):  # yes, we could use enumerate
            invperm[perm[i] - 1] = i
        count = 1
        for i in range(1, len(perm)):
            count += invperm[i - 1] > invperm[i]
        return count
    
         Given          : 3, 7, 4, 2, 10, 8, 9, 1, 6, 5
    
                     x  : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    
    #!/usr/bin/perl
    if ($#ARGV < 0) {   # with no arguments
        @data = (3, 7, 4, 2, 10, 8, 9, 1, 6, 5);
    }
    else {
        @tmp = (1..$ARGV[0]);
        while(@tmp) {
            push(@data, splice(@tmp, rand($#tmp), 1));
        }
    }
    $key = 1;
    while (@data) {
        @remove = (); @remain = ();
        printf "key = $key\t(@data) --> ";
        foreach $i (@data) {
            if ($i == $key) {   # found
                push(@remove, $i);
                $key++;
            }
            else {
                push(@remain, $i);
            }
        }
        @data = @remain;
        print "(@remove) & (@data)\n";
        $count++;
    }
    print "Iteration = $count\n";
    
    $ ./a.pl  
    key = 1 (3 7 4 2 10 8 9 1 6 5) --> (1) & (3 7 4 2 10 8 9 6 5)
    key = 2 (3 7 4 2 10 8 9 6 5) --> (2) & (3 7 4 10 8 9 6 5)
    key = 3 (3 7 4 10 8 9 6 5) --> (3 4 5) & (7 10 8 9 6)
    key = 6 (7 10 8 9 6) --> (6) & (7 10 8 9)
    key = 7 (7 10 8 9) --> (7 8 9) & (10)
    key = 10    (10) --> (10) & ()
    Iteration = 6
    $ ./a.pl  10
    key = 1 (2 1 4 8 5 9 3 6 7 10) --> (1) & (2 4 8 5 9 3 6 7 10)
    key = 2 (2 4 8 5 9 3 6 7 10) --> (2 3) & (4 8 5 9 6 7 10)
    key = 4 (4 8 5 9 6 7 10) --> (4 5 6 7) & (8 9 10)
    key = 8 (8 9 10) --> (8 9 10) & ()
    Iteration = 4
    $ ./a.pl  10
    key = 1 (3 1 7 8 6 2 9 5 4 10) --> (1 2) & (3 7 8 6 9 5 4 10)
    key = 3 (3 7 8 6 9 5 4 10) --> (3 4) & (7 8 6 9 5 10)
    key = 5 (7 8 6 9 5 10) --> (5) & (7 8 6 9 10)
    key = 6 (7 8 6 9 10) --> (6) & (7 8 9 10)
    key = 7 (7 8 9 10) --> (7 8 9 10) & ()
    Iteration = 5