使用usort()对这个数组进行排序的机制是什么?

时间:2017-09-26 14:38:39

标签: php sorting insertion-sort usort

<?php
function list_cmp($a, $b) {
    global $order;

    foreach ($order as $key => $value) {
        if ($a == $value) {
            return 0;
        }

        if ($b == $value) {
            return 1;
        }
    }
}

$order[0] = 1;
$order[1] = 3;
$order[2] = 4;
$order[3] = 2;

$array[0] = 2;
$array[1] = 1;
$array[2] = 3;
$array[3] = 4;
$array[4] = 2;
$array[5] = 1;
$array[6] = 2;

usort($array, "list_cmp");

我知道这是插入排序(不是Quicksort,因为数组大6-15个元素)。我看到$ a- $ b对与订单进行比较,如果list_cmp回调函数返回1,则当前$ b值将移向数组的开头。这就是usort()的工作原理,只有$ b被移动了。我假设它总是在这个方向,这个假设是正确的。

$ a- $ b对是这样的 - 2-1,2-3,1-3,2-4,3-4,2-2,2-1,2-1,4-1, 3-1,1-1,2-2,这些是在所有步骤中返回的值 - 1,1,0,1,0,0,1,1,1,1,0,0(如果返回1,$ b被移动,如果返回0,我猜usort()正在寻找正确的插入点,但是它是如何工作的?我没有看到它是如何工作的,这个机制是什么或在哪里?)

我知道这是1)比较2)找到插入点和3)插入,它看起来像这样:

-- [2,1],3,4,2,1,2 -> 1./2./3. compare [2,1], find and insert 1 before 2
-- 1,[2,3],4,2,1,2 -> 1./2. compare [2,3], find insert point for 3 (since order of 3 < order of 2)
-- [1,3],2,4,2,1,2 -> 3. compare [1,3], found insert point for 3 before 2
-- 1,3,[2,4],2,1,2 -> 1./2. compare [2,4], find insert point for 4 (since order of 4 < order of 2) 
-- 1,[3,4],2,2,1,2 -> 3. compare [3,4], found insert point for 4 before 2
-- 1,3,4,[2,2],1,2 -> 1. compare [2,2], skip
-- 1,3,4,2,[2,1],2 -> 1./2. compare [2,1], find insert point for 1
-- 1,3,4,[2,1],2,2 -> 2. compare [2,1], find insert point for 1
-- 1,3,[4,1],2,2,2 -> 2. compare [4,1], find insert point for 1
-- 1,[3,1],4,2,2,2 -> 2. compare [3,1], find insert point for 1
-- [1,1],3,4,2,2,2 -> 3. compare [1,1], fond insert point for 1 before 3
-- 1,1,3,4,2,[2,2] -> 1. compare [2,2], skip
-- sorted: 1,1,3,4,2,2,2

但是,我基本上没有看到找到插入点的机制。动态是 - list_cmp返回1 - 移动$ b(并朝向数组的开头),但找到正确位置的机制是什么?可以说,这是在usort()中,但我们没有产生像推杆5这样的东西1,2,3,4,x,6,7,8,9。结果是1,1,3,4,2,2,2这是基于$ order数组中的什么。

2 个答案:

答案 0 :(得分:0)

首先,您的自定义比较功能不正确。当$a必须保留在排序数组中的$b前面时,它必须返回负值,当0$a相等时,必须返回零$b} $a必须在排序数组中$b之后保留的正值。

如果您阅读&#34; $a小于$b&#34; 而不是&#34; $a之前停留$b&#34; (以及&#34;更大&#34; 而非&#34;&#34; 之后)数组按升序排序。但是没有人说数组必须按升序排序,并且没有用于降序排序的自定义数组排序功能。最终数组中元素的顺序由提供的自定义比较函数决定。

你在谈论&#34;插入点&#34;在问题中。有许多排序算法。其中一些以空列表开头并将元素插入其最终位置,其他人交换两个项目并进行就地排序。

我不知道u*sort() PHP函数实现了什么算法(对于日常使用我甚至不关心),但我认为它使用quicksort或其他快速算法。只是为了你的好奇心,quicksort不会插入任何东西,它会交换物品。

无论使用何种算法,排序使用的主要操作是两个项目的比较。算法在发现哪个项目应该保持在另一个之前时如何使用这些项目是一个不同的故事,但它并不会干扰比较本身。

答案 1 :(得分:0)

http://php.net/manual/en/function.usort.php州:

  

<强> value_compare_func   比较函数必须返回较小的整数   如果第一个参数是,则等于或大于零   被认为分别小于,等于或大于   第二

当您调用该函数时,它会接受任意两个值并决定它们是否按正确的顺序排列。

它真正做的就是在$b的数组中向上或向下移动$a变量。

为您的功能添加一些输出可以向您显示正在进行的操作:

<?php
function list_cmp($a, $b) {
    global $order;

    echo "comparing $a and $b...\n";
    foreach ($order as $key => $value) {
        echo "  checking against $value\n";
        if ($a == $value) {
            echo "    \$a ($a) == $value: returning 0\n";
            return 0;
        }

        if ($b == $value) {
            echo "    \$b  ($b) == $value: returning 1\n";
            return 1;
        }
    }
}

让我们看一下输出的第一部分:

comparing 4 and 1...
  checking against 1
    $b  (1) == 1: returning 1

在这里你可以看到它正在检查两个值4和1(我们不知道它是哪一个)。然后它会检查$order中的每个项目。第一个值是1,表示所有1都必须在任何其他值之前。

$a不匹配1但$b不匹配。所以这些项目的顺序错误 - 第一项大于第二项,所以我们返回1.即4必须在1之后。

让我们看看另一位输出:

comparing 4 and 2...
  checking against 1
  checking against 3
  checking against 4
    $a (4) == 4: returning 0

这里检查了值1和3 - 它们都没有与我们考虑的两个数字相匹配,因此它们无关紧要。然后我们到达$a(4)。这相当于下一个想要的价值。这意味着它在正确的位置,所以我们返回0.即4必须在2之前 - 它确实。

排序比较的每一对都是如此。