如何创建多个堆栈?

时间:2016-02-23 21:58:36

标签: perl stack singly-linked-list

Perl帮助

我有一个复杂的实用程序(让我们简称为KIP) 我是从AWK转换为perl。 AWK有一个双重联系的设施 我用过的清单。这很有效,但我无法弄清楚该怎么做 这在perl中。我知道FIFO链表是一个很好的解决方案。

KIP功能(如果您有兴趣) KIP从文档中删除重复的项目。 AWK计划的方式 工作是它扫描文档寻找重复的项目和 构建一个数组,显示" real"项目及其所有重复项。一世 需要一个FIFO链表到重复项,如下所示:

                 PICTORIAL OF THE FUNCTION
REAL
ITEM    ARRAY OF $POINTER[]                   LINKED LIST
NUMBER
      +-------------+---------+   +---------------+   +---------------+
 1    | real item 1 | ------> |   |dup_1_of_item_1|-->|dup_n_of_item_1|
      +-------------+---------+   +---------------+   +---------------+

      +-------------+---------+   +---------------+   +---------------+
 2    | real item 2 | ------> |   |dup_1_of_item_2|-->|dup_n_of_item_2|
      +-------------+---------+   +---------------+   +---------------+

      +-------------+---------+   +---------------+   +---------------+
 3    | real item 3 | ------> |   |dup_1_of_item_3|-->|dup_n_of_item_3|
      +-------------+---------+   +---------------+   +---------------+
               ...                             ...

KIP将运行"真实项目n"数组来处理每个真实项目。去做 所以,KIP将运行链表链以删除重复的项目 从文件。推送重复的东西会很好 "真实项目1"到堆栈并保存堆栈地址以供日后使用。然后, 之后,KIP可以访问保存的堆栈地址并关闭项目。

我知道这是我对perl缺乏了解,但我很难过 实现这样的指针数组结构。我认为推和流行 应该工作,但要么语法错误,要么它只是不起作用 我

这是我发现的难点 -

  1. 我需要创建可以将信息推送到的动态堆栈。

  2. 堆栈将在KIP的不同部分访问,所以我需要 将堆栈地址保存在数组中以供日后使用。

  3. 堆栈是动态构建的(不是使用QW构建的数组 所有文件似乎都在描述。)

  4. 我需要大量的堆栈(每个real_item都有一个堆栈 复制)。

  5. 有人能指点我吗?任何相关信息都将是 赞赏。

    TIA

    在这'我做了什么;

    ADD ITEMS TO STACK
       # $IDX_ori_iSub - subscript for the real item
       # $IDX_dup_iSub - subscript for each duplicate item that is
       #                 found
    
       # populate the fields for the stack
        $MsgID      =  $IDXMsgID[$IDX_dup_iSub];
        $LineNumber =  $IDXLineNumber[$IDX_dup_iSub];
        $Offset     =  $IDXOffset[$IDX_dup_iSub];
        $LineCount  =  $IDXLineCount[$IDX_dup_iSub];
        $KCount     =  $IDXKCount[$IDX_dup_iSub];
    
       # set up stack
        my @stackOfDuplicates;
    
       # Save the address of the stack for later access
        if ( $IDXChain[$IDX_ori_iSub] == 0)
        {
            $IDXChain[$IDX_ori_iSub] = \@stackOfDuplicates;
        }
    
       # Push items onto list.
        push @stackOfDuplicates, $MsgID      ;
        push @stackOfDuplicates, $LineNumber ;
        push @stackOfDuplicates, $Offset     ;
        push @stackOfDuplicates, $LineCount  ;
        push @stackOfDuplicates, $KCount     ;
    

    从堆栈中删除物品

        my @stackOfDuplicates = $IDXChain[$IDX_iSub];
        if ( @stackOfDuplicates )
        {
           # Remove first items from list.
            my $MsgID      = shift @stackOfDuplicates;
            my $LineNumber = shift @stackOfDuplicates;
            my $Offset     = shift @stackOfDuplicates;
            my $LineCount  = shift @stackOfDuplicates;
            my $KCount     = shift @stackOfDuplicates;
    
    print "  \$MsgID = $MsgID";
    print "  \$LineNumber = $LineNumber";
    print "  \$Offset = $Offset";
    print "  \$LineCount = $LineCount";
    print "  \$KCount = $KCount";
        }
    

    结果的典型结果我很快就看到了

      $MsgID = ARRAY(0x2b786c0)
    Use of uninitialized value $LineNumber in concatenation (.) or string
      $LineNumber =
    Use of uninitialized value $Offset in concatenation (.) or string at
      $Offset =
    Use of uninitialized value $LineCount in concatenation (.) or string
      $LineCount =
    Use of uninitialized value $KCount in concatenation (.) or string at
      $KCount =
    

2 个答案:

答案 0 :(得分:1)

不是恢复重复堆栈以准备删除,而是将地址作为第一个元素输入。然后最后的打印得到第一个变量是数组引用,因为这是@stackOfDuplicates下唯一的事情,其他变量没有得到任何结果(最终undef),{{{ 1}}已打印。

在Perl中分配对数组的引用不会恢复数组(与该引用相关联),它不是像在C中那样指向第一个数组地址的指针。相反,此时新数组是已创建并且该引用成为其第一个元素。

要从引用中获取数组,我们需要取消引用它

Use of unitialized ...

或者,可能更清楚

my @stackOfDuplicates = @{ $IDXChain[$IDX_iSub] };

我认为您的数据结构没有任何问题。在Perl my $ref_stackOfDuplicates = $IDXChain[$IDX_iSub]; my @stackOfDuplicates = @$ref_stackOfDuplicates; 确实由数组实现,而FIFO + push(或shift + push用于堆栈)。

答案 1 :(得分:0)

你的重复堆栈实际上是一堆"有关重复的详细信息"。这使事情变得非常复杂。我怀疑你宁愿做一个小小的调整来修复你已经拥有的东西,但你会更好地退一步,做一些研究,然后再进行一次。

整个操作的关键是收集描述一个"重复项目的属性"或"原始项目"成为一个关联数组 - 即一个事实上的对象。更好的是,Mo.pm是一个极简主义的Perl模块,可以为您提供基本对象。

如果您无法安装模块,或者如果您没有正式安装模块的管理员权限,则可以复制these three lines并将其放入名为 Mo的文件中。 pm 与您的脚本位于同一目录,然后您就可以了。

您还需要在同一目录中创建另一个名为 DocItem.pm 的文件,该文件将定义您的DocItem类。将以下内容放入其中:

package DocItem;
use Mo;

has MsgID      =>  ();
has LineNumber =>  ();
has Offset     =>  ();
has LineCount  =>  ();
has KCount     =>  ();

现在你有一个课程,你可以"拉入"你的脚本。您的代码应如下所示:

#!/usr/bin/env perl
use DocItem;

my @stack ;
my @problem ;

# Have to create an "original" and some duplicates by making
# up the attributes that define each item

my $original = DocItem->new(
                  MsgID        =>  "id14" ,
                  LineNumber   =>  126    ,  # All these made up
                  Offset       =>  17     ,
                  LineCount    =>  64     ,
                  KCount       =>  1237   ,
              );

print "MsgID: ",     $original->MsgID, "\n";    #  How you access an attribute
print "LineCount: ", $original->LineCount;
print " ==> ";
$original->LineCount(8600);   #  How you set an attribute after object creation
print $original->LineCount, "\n";

$problem[0] = $original ;     # NOTE: make the DocItem called "$original" the
                              # first item of the array @problem.

# Using a loop to make-up 4 DocItem objects representing 4 duplicates
for (1 .. 4) {
    my $id   = "id" . $_ ;   # All these attributes made up
    my $line = 12 * $_   ;   # values based on the loop variable
    my $off  = 18 + $_   ;
    my $Lcnt = 126 + $_  ;
    my $KC   = 1000 - $_ ;

    # Create a new DocItem representing one duplicate
    my $duplicate = DocItem->new(
                    MsgID        =>  $id   ,
                    LineNumber   =>  $line ,
                    Offset       =>  $off  ,
                    LineCount    =>  $Lcnt ,
                    KCount       =>  $KC   ,
                );

    # NOTE: push the DocItem called "$duplicate" onto the problem array
    # This builds up a structure representing one "horizontal line" of your pic
    push @problem, $duplicate;
}

# The four "pushes" (one for each loop iteration) leaves @problem looking like:

#  $problem[0]     $problem[1]     $problem[2]    $problem[3]    $problem[4]
#  ===========     ===========     ===========    ===========    ===========
#    MsgID:  id14    MsgID:  id1     MsgID:  id2    MsgID:  id3    MsgID:  id4
#    Offset: 17      Offset: 19      Offset: 20     Offset: 21     Offset: 22
#    KCount: 1237    KCount: 999     KCount: 998    KCount: 997    KCount: 996
#    (etc for LineNumber and LineCount)

# Now, push the whole problem array into slot 0 of @stack
push @stack, \@problem;   # Or, $stack[0] = \@problem ;

# In a similar way, build up more arrays representing "problems" each
# with the "original" DocItem in slot 0 and the duplicate DocItems in
# successive slots of the array, and again, push the whole lot onto @stack

# and then....

my $first_problem = shift @stack;
my $first_original = shift @$first_problem;  # Note, this access is required because
                                             # $first_problem holds a reference to an
while (my $dup = shift @$first_problem)  {   # array, not an array;

    # $dup holds one DocItem object representing
    # a duplicate and $first_original holds the
    # DocItem representing the orignal.

    # Do what you need to do

 }

每个@problem代表上图中的一条水平线。第一个插槽 - $problem[0] - 保存您的原始和后续重复项被推送到阵列上。然后通过引用问题数组@stack

,可以将整个数组推到\@problem

然后你可以遍历你的堆栈,转移一个完整的问题,移开原来的,然后迭代处理它们的重复项。

Gabor Szabo的优秀教程

Read this帮助保持"推动"," pop"," shift"并且"未移位"直。