unique函数源码的分析(2)

上面就是是array_flip函数的源码。点击链接查看原始代码。这个函数主要的做的事情就是创建一个新的数组,遍历原数组。在26行开始将原数组的值赋值为新数组的键,然后在37行开始将原数组的键赋值为新数组的值,如果有重复的,则使用新值覆盖旧值。整个函数的时间复杂度也是O(n)。因此,使用了array_flip之后再使用array_keys的时间复杂度是O(n)。

接下来,我们看看array_unique函数的源码。点击链接查看原始代码。

/* {{{ proto array array_unique(array input [, int sort_flags]) Removes duplicate values from array */ PHP_FUNCTION(array_unique) { // 定义变量 zval *array, *tmp; Bucket *p; struct bucketindex { Bucket *b; unsigned int i; }; struct bucketindex *arTmp, *cmpdata, *lastkept; unsigned int i; long sort_type = PHP_SORT_STRING; // 解析参数 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) { return; } // 设置比较函数 php_set_compare_func(sort_type TSRMLS_CC); // 初始化返回数组 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array))); // 将值拷贝到新数组 zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array), (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*)); if (Z_ARRVAL_P(array)->nNumOfElements <= 1) { /* 什么都不做 */ return; } /* 根据target_hash buckets的指针创建数组并排序 */ arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->persistent); if (!arTmp) { zval_dtor(return_value); RETURN_FALSE; } for (i = 0, p = Z_ARRVAL_P(array)->pListHead; p; i++, p = p->pListNext) { arTmp[i].b = p; arTmp[i].i = i; } arTmp[i].b = NULL; // 排序 zend_qsort((void *) arTmp, i, sizeof(struct bucketindex), php_array_data_compare TSRMLS_CC); /* 遍历排序好的数组,然后删除重复的元素 */ lastkept = arTmp; for (cmpdata = arTmp + 1; cmpdata->b; cmpdata++) { if (php_array_data_compare(lastkept, cmpdata TSRMLS_CC)) { lastkept = cmpdata; } else { if (lastkept->i > cmpdata->i) { p = lastkept->b; lastkept = cmpdata; } else { p = cmpdata->b; } if (p->nKeyLength == 0) { zend_hash_index_del(Z_ARRVAL_P(return_value), p->h); } else { if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) { zend_delete_global_variable(p->arKey, p->nKeyLength - 1 TSRMLS_CC); } else { zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h); } } } } pefree(arTmp, Z_ARRVAL_P(array)->persistent); } /* }}} */

可以看到,这个函数初始化一个新的数组,然后将值拷贝到新数组,然后在45行调用排序函数对数组进行排序,排序的算法是zend引擎的块树排序算法。接着遍历排序好的数组,删除重复的元素。整个函数开销最大的地方就在调用排序函数上,而快排的时间复杂度是O(nlogn),因此,该函数的时间复杂度是O(nlogn)。

结论

因为array_unique底层调用了快排算法,加大了函数运行的时间开销,导致整个函数的运行较慢。这就是为什么array_keys比array_unique函数更快的原因。

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1cefc42ab31f309d18211dffb43d1827.html