簡體   English   中英

減少Perl陣列中的時間復雜度

[英]Reducing time complexity in Perl arrays

我有一個數組

[3, 1, 2, 5, 4, 6]

我想排序(更改sort ,以arranging in a certain pattern )這是:移動到右,與右側的下一個最大的整數更換指標。 在這個數組中說35替換,1被2替換,依此類推。

我希望輸出為

[5, 2, 5, 6, 6, 6]

算法:

  1. 啟動一個forloop。 它將迭代直到最后一個元素
  2. 從第一個索引開始,它將與下一個索引匹配並比較值
  3. 如果第二個索引小於第一個索引,則移至第三個索引
  4. 如果沒有,請用第二個索引更改第一個索引
  5. 嘗試所有索引

這是一個正常的算法。 但是時間復雜度是n * n。 (不完全是n * n)。

有沒有辦法降低復雜度。 因為在大型陣列的情況下,它會非常慢。 有人可以為我提供時間復雜度n算法嗎?

添加代碼

use strict;
use warnings;

my @arr1 = qw/3 1 2 5 4 6/;
my @arr2;
my ($j, $i);
for($i = 0; $i <= $#arr1; $i++) {
    $j = $i;
    while ( $j < $#arr1) {
        if ( $arr1[$i] < $arr1[$j+1]) {
            push @arr2,$arr1[$j+1];
            last;
        } 
        if ($i == $#arr1) {
            push @arr2,$arr1[$j];
        }
        $j++;
    }

}
push @arr2, $arr1[$#arr1];   ## Pushing the last array index

print @arr2;

輸出:

525666

您當前的算法可以多次觸摸一個位置,效率低下。 通過遞歸的力量,我們可以做得更好。 想象一個函數執行您的排序,直到發現一個大於$n

[3, 1, 2, 5, 4, 6] # start here
#^
[3, 1, 2, 5, 4, 6] # look at next number. It's smaller, so we recurse
#^--^
[3, 1, 2, 5, 4, 6] # in recursion: look at next number, replace
#^  ^--^
#|__|
[3, 2, 2, 5, 4, 6] # return new index. It's smaller, so we recurse
#^     ^
#|_____|
[3, 2, 2, 5, 4, 6] # in recursion: look at next number, replace
#^     ^--^
#|_____|
[3, 2, 5, 5, 4, 6] # return new index
#^        ^
#|________|
[3, 2, 5, 5, 4, 6] # It's larger, so we replace and go to new index
#^--------^
[5, 2, 5, 5, 4, 6] # Look at next number. It's smaller, so we recurse
#         ^--^
[5, 2, 5, 5, 4, 6] # In recursion: replace
#         ^  ^--^
#         |__|
[5, 2, 5, 5, 6, 6] # return new index
#         ^     ^
#         |_____|
[5, 2, 5, 5, 6, 6] # It's larger, so we replace. Go to new index
#         ^-----^
[5, 2, 5, 6, 6, 6] # Done!

困難的部分是編寫執行此操作的函數。 當我們想編寫一個遞歸函數時,我們必須回想一下:

  • [] –空數組(無索引)對自身進行排序
  • [6] –帶有單個元素的數組將對該元素進行排序
  • [4, 6] → [6, 6] –如果下一個索引處的元素較大,則將其復制過來,新索引位於下一個元素處
  • [5, 4, ...] –如果下一個元素較小,則從該索引處遞歸。

示例實現:

sub weird_sort {
  my ($array, $start, $return) = @_;
  $start //= 0;
  my $next = $start + 1;

  while ($next <= $#$array) {
    # check if one is larger
    if ($array->[$start] < $array->[$next]) {
      $array->[$start] = $array->[$next];
      return $next if $return;  # return index to higher levels so that they
                                # can check whether the $next elem is larger.
      $start = $next;
      $next  = $start + 1;
    }
    else {
      $next = weird_sort($array, $next, 1);
    }
  }

  return $next;
}

# called in-place like
weird_sort(\@array);

下一步將是刪除遞歸:

sub weird_sort {
  my ($array) = @_;
  my ($start, $next) = (0, 1);

  my @stack;

  while ($next <= $#$array) {
    # check if one is larger
    if ($array->[$start] < $array->[$next]) {
      $array->[$start] = $array->[$next];
      ($start, $next) = @stack ? (pop(@stack), $next) : ($next, $next + 1);
    }
    else {
      push @stack, $start;
      ($start, $next) = ($next, $next + 1);
    }
  }
}

這似乎適用於簡單的情況,但我不能完全確定這是一個通用的解決方案。

我認為這不是N * N的復雜性。 到更大值的平均距離不會隨着數組的增長而增加,因此您的復雜度會以N而不是N * N的比率增加。 你為什么不發布一些代碼? 如果評估需要很長時間,則可能是您的實現中存在錯誤。

通過不對重新排序的數據使用新數組,您現有的算法將更快。 在我的筆記本電腦上,使用下面的測試程序,速度大約提高了60%,其中100萬個元素被輕度隨機

use strict;
use warnings;

#my @arr1 = qw/3 1 2 5 4 6/;
my @arr1= ( 1 .. 1000000 );
for (@arr1) { my $r1=rand($#arr1); my $r2=rand($#arr1); @arr1[$r1,$r2]=@arr1[$r2,$r1] }
my @arr2;
my ($j, $i);
for($i = 0; $i <= $#arr1; $i++) {
    $j = $i;
    while ( $j < $#arr1) {
        if ( $arr1[$i] < $arr1[$j+1]) {
            $arr1[$i] = $arr1[$j+1];
            last;
        } 
        $j++;
    }

}

#print @arr1;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM