快速排序深入分析,包含win快排源码,V8快排源码

 
一种好理解的快速排序的代码:

function quickSort(arr){
console.log('arr=>'+arr);
if(arr.length<=1){
return arr;
}
var pivotindex=Math.floor(arr.length/2);
var pivot = arr.splice(pivotindex,1)[0];
console.log('pivot=>'.concat(pivot));
var left=[],right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot],quickSort(right));
}
console.time('start');
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(quickSort(arr));
console.timeEnd('start');

执行循序如下:

arr=>3,44,38,5,47,15,36,26,27,2,46,4,19,50,48
VM439:8 pivot=>26
VM439:2 arr=>3,5,15,2,4,19
VM439:8 pivot=>2
VM439:2 arr=>
VM439:2 arr=>3,5,15,4,19
VM439:8 pivot=>15
VM439:2 arr=>3,5,4
VM439:8 pivot=>5
VM439:2 arr=>3,4
VM439:8 pivot=>4
VM439:2 arr=>3
VM439:2 arr=>
VM439:2 arr=>
VM439:2 arr=>19
VM439:2 arr=>44,38,47,36,27,46,50,48
VM439:8 pivot=>27
VM439:2 arr=>
VM439:2 arr=>44,38,47,36,46,50,48
VM439:8 pivot=>36
VM439:2 arr=>
VM439:2 arr=>44,38,47,46,50,48
VM439:8 pivot=>46
VM439:2 arr=>44,38
VM439:8 pivot=>38
VM439:2 arr=>
VM439:2 arr=>44
VM439:2 arr=>47,50,48
VM439:8 pivot=>50
VM439:2 arr=>47,48
VM439:8 pivot=>48
VM439:2 arr=>47
VM439:2 arr=>
VM439:2 arr=>
VM439:21 [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
VM439:22 start: 9.407ms

这是win7 32位,vs2010的快速排序的代码。
int FindPos(double *p,int low,int high)
{
    double val = p[low];
    while (low<high)
    {
        while(low<high&&p[high]>=val)
            high--;
        p[low]=p[high];
        while(low<high&&p[low]<val)
            low++;
        p[high]=p[low];
    }
    p[low]=val;
    return low;
}
void QuickSort(double *a,int low,int high)
{
    if (!a||high<low)
        return;
 
    if (low<high)
    {
        int pos=FindPos(a,low,high);
        QuickSort(a,low,pos-1);
        QuickSort(a,pos+1,high);
    }
}
 
 
下面是快速排序用插入排序做优化代码。
template <typename T>
void QuickSort(T arr[], int n)   //快速排序
{
    QSpartition(arr, 0, n - 1);
    InsertSort(arr, n);          //最后用插入排序对整个数组排序
}
 
template <typename T>
void QSpartition(T arr[], int low, int high)     //快速排序递归函数
{
     
//    if (low >= high)     //有插入排序,不需要这句
//        continue;
     
    const int min_insert = 128;
    if (high - low < min_insert)  //数据小于一定数量的时候用直接插入排序
    {
        return;  //最后用插入排序对整个数组排序
    }
 
    int i, j;
    T temp;
     
    //下面一段是前中后3个数据进行插入排序
    i = (low + high) / 2;
    if (arr[i] < arr[low])
    {
        temp = arr[i];
        arr[i] = arr[low];
        arr[low] = temp;
    }
    if (arr[high] < arr[i])
    {
        temp = arr[high];
        arr[high] = arr[i];
        arr[i] = temp;
        if (arr[i] < arr[low])
        {
            temp = arr[i];
            arr[i] = arr[low];
            arr[low] = temp;
        }
    }
//    if (high - low < 3)   //小区间用插入排序,这里就不需要判断了
//        return;           //不用插入排序,只有2个数据的时候排序错误
     
    temp = arr[i];           
    arr[i] = arr[low + 1];  //中值放在最左边
    i = low + 1;            //左右边界缩小1
    j = high - 1;           //边界2个数字插入排序排过,满足左<=中<=右
 
    while (i < j)
    {
        while (temp < arr[j] && i < j)   //从右往左扫描小于目标的值,应该放在左半部分
            j--;
        if (i < j)                        //找到后放在左边
            arr[i++] = arr[j];
        else
            break;
        while (temp > arr[i] && i < j)   //从左往右扫描大于目标的值,要放在右边
            i++;
        if (i< j)
            arr[j--] = arr[i];
        else
            break;
    }
    arr[i] = temp;                       // i = j,正好是分界线,回填目标值
    if ((i - low) > 1) 
        QSpartition(arr, low, i - 1);     //递归左边
    if ((high - i) > 1)
        QSpartition(arr, i + 1, high);     //递归右边
}
 
template <typename T>
void InsertSort(T arr[], int n)   //直接插入排序
{
    int i, j;
    T temp;
 
    for (i = 1; i < n; i++)
    {
        temp = arr[i];
        for (j = i - 1; j >= 0; j--)
        {
            if (temp < arr[j])            //逐个往前比较,碰到大于目标的,拉过来
                arr[j + 1] = arr[j];
            else
                break;
        }
        arr[j + 1] = temp;               //把目标值填入空位
    }
}
 
v8快速排序源码:

function ArraySort(comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.

var custom_compare = IS_FUNCTION(comparefn);

function Compare(x,y) {
// Assume the comparefn, if any, is a consistent comparison function.
// If it isn't, we are allowed arbitrary behavior by ECMA 15.4.4.11.
if (x === y) return 0;
if (custom_compare) {
// Don't call directly to avoid exposing the builtin's global object.
return comparefn.call(null, x, y);
}
if (%_IsSmi(x) && %_IsSmi(y)) {
return %SmiLexicographicCompare(x, y);
}
x = ToString(x);
y = ToString(y);
if (x == y) return 0;
else return x < y ? -1 : 1;
};

function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
var element = a[i];
// Pre-convert the element to a string for comparison if we know
// it will happen on each compare anyway.
var key =
(custom_compare || %_IsSmi(element)) ? element : ToString(element);
// place element in a[from..i[
// binary search
var min = from;
var max = i;
// The search interval is a[min..max[
while (min < max) {
var mid = min + ((max - min) >> 1);
var order = Compare(a[mid], key);
if (order == 0) {
min = max = mid;
break;
}
if (order < 0) {
min = mid + 1;
} else {
max = mid;
}
}
// place element at position min==max.
for (var j = i; j > min; j--) {
a[j] = a[j - 1];
}
a[min] = element;
}
}

function QuickSort(a, from, to) {
// Insertion sort is faster for short arrays.
if (to - from <= 22) {
InsertionSort(a, from, to);
return;
}
var pivot_index = $floor($random() * (to - from)) + from;
var pivot = a[pivot_index];
// Pre-convert the element to a string for comparison if we know
// it will happen on each compare anyway.
var pivot_key =
(custom_compare || %_IsSmi(pivot)) ? pivot : ToString(pivot);
// Issue 95: Keep the pivot element out of the comparisons to avoid
// infinite recursion if comparefn(pivot, pivot) != 0.
a[pivot_index] = a[from];
a[from] = pivot;
var low_end = from; // Upper bound of the elements lower than pivot.
var high_start = to; // Lower bound of the elements greater than pivot.
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
for (var i = from + 1; i < high_start; ) {
var element = a[i];
var order = Compare(element, pivot_key);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
i++;
low_end++;
} else if (order > 0) {
high_start--;
a[i] = a[high_start];
a[high_start] = element;
} else { // order == 0
i++;
}
}
QuickSort(a, from, low_end);
QuickSort(a, high_start, to);
}

var old_length = ToUint32(this.length);
if (old_length < 2) return this;

%RemoveArrayHoles(this);

var length = ToUint32(this.length);

// Move undefined elements to the end of the array.
for (var i = 0; i < length; ) {
if (IS_UNDEFINED(this[i])) {
length--;
this[i] = this[length];
this[length] = void 0;
} else {
i++;
}
}

QuickSort(this, 0, length);

// We only changed the length of the this object (in
// RemoveArrayHoles) if it was an array. We are not allowed to set
// the length of the this object if it is not an array because this
// might introduce a new length property.
if (IS_ARRAY(this)) {
this.length = old_length;
}

return this;
}

 
posted @ 2017-03-02 09:27  程序员大V  阅读(301)  评论(0)    收藏  举报