Perl 5脚本解析:@_与$_的作用及快速排序脚本工作原理
Hey there! Let's break down this Perl quicksort line by line, focusing on the parts you're stuck on—@_, $_, that tricky splice call, and the recursion logic. Since you have Shell experience, I'll draw small parallels where it helps too.
First: Clearing Up @_ vs $_
These are two of Perl's most used special variables, but they do totally different things:
@_: This is the parameter list for the current subroutine. Think of it like Shell's$@, but per-subroutine—every time you callquick_sort(...), the arguments you pass get stored in@_only inside that call of the subroutine. It's not global; each recursive call has its own separate@_.$_: This is Perl's default variable. Many built-in functions (likegrep,map,foreachwithout a loop variable) automatically use$_to refer to the current element they're processing. It's overwritten constantly by these functions as they iterate through data.
Let's Walk Through the Script Step by Step
1. The Exit Condition
return @_ if @_ < 2;
This is the base case for recursion. If the current subset (stored in @_) has 0 or 1 elements, it's already sorted—so we just return it as-is. Super straightforward!
2. Picking the Pivot Element
my $p = splice @_, int rand @_, 1;
Let's unpack this splice call, since you were confused about the final 1:
splicemodifies an array by removing elements from it (and can replace them, but we don't do that here). Its syntax issplice(ARRAY, OFFSET, LENGTH).@_: The array we're modifying (the current subset we're sorting).int rand @_:rand @_generates a random floating-point number between 0 and the length of@_minus 1.intconverts that to an integer, giving us a random index in the array.1: This is the number of elements to remove from@_at that offset. We only need one pivot element, so we pass1.
So this line:
- Picks a random element from the current
@_subset. - Removes that element from
@_(so@_now contains all elements except the pivot). - Assigns the removed element to
$p(our pivot).
3. The Recursive Sorting Logic
quick_sort(grep $_ < $p, @_), $p, quick_sort(grep $_ >= $p, @_);
This is the core of the quicksort, and it's using Perl's list context to work its magic. Let's break it down:
- First part:
quick_sort(grep $_ < $p, @_)grep $_ < $p, @_usesgrepto filter the remaining elements in@_(remember, we removed the pivot already).grepiterates over each element in@_, puts the current element into$_, and keeps it only if$_ < $pis true. This gives us all elements smaller than the pivot.- We pass this filtered list to
quick_sort, which recursively sorts it.
- Middle part:
$p— our pivot element, which belongs right between the sorted smaller elements and sorted larger elements. - Last part:
quick_sort(grep $_ >= $p, @_)- Similar to the first part, but
grepkeeps elements where$_ >= $p(elements equal to or larger than the pivot). We pass this toquick_sortto recursively sort.
- Similar to the first part, but
In Perl, when you separate expressions with commas in a list context (like the return value of a subroutine), it combines them into a single list. Since the subroutine doesn't have an explicit return, it automatically returns the value of this final expression—so it returns the sorted small elements, followed by the pivot, followed by the sorted large elements. That's how we build up the fully sorted array!
4. Running the Script
my @a = (4, 65, 2, -31, 0, 99, 83, 782, 1); @a = quick_sort @a; print "@a\n";
This is just setting up our initial unsorted array, passing it to quick_sort (which replaces @a with the sorted result), and printing the sorted array. No surprises here, like you guessed.
A Quick Recap of the Flow
- Call
quick_sortwith the full array. - If the array is small, return it.
- Otherwise, pick a random pivot, remove it from the array.
- Recursively sort all elements smaller than the pivot.
- Recursively sort all elements larger than/equal to the pivot.
- Combine the sorted small list + pivot + sorted large list, return that as the sorted result.
内容的提问来源于stack exchange,提问作者nimda

