AKever

导航

算法 -- (1)快速排序(交换)

数据结构 -- (1)快速排序(交换)

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

百度百科演示图

--- cpp 1 !!!----

int QuickSort::partition(int a[],int p,int r)
{
    int x = a[r];     //通常,拿最后一个值,作为预期的中间值a[r], 其他值与此值比较,大小分开
    int middle = p;   //记录“较小的一段数据”的最大下标。通常这个值在p和r的中间,故起名middle,
    for (int j = p ; j < r ; j++){ //遍历数组中的值
        if (a[j] < x){ //将此值与“中间值”比较,计算出中间值在数组的第几个位置(middle) ---middle--
            int temp  = a[middle];
            a[middle] = a[j];
            a[j] = temp;
            middle++;  //以上四句是将比a[r]小的依次从第一个排下去(middle++,下一个)
        }
    }
    int temp = a[r];  //得到中间值的位置后,与之前的位置坐交换(a[r])
    a[r]     = a[middle];
    a[middle] = temp;
    return middle; //返回中间位置(middle)
}

void QuickSort::doQuickSort(int a[],int p,int r)
{
    if (p<r){
        int q=partition(a,p,r);  //获取中间值,将数组一分为二,并分开递归
        doQuickSort(a,p,q-1);
        doQuickSort(a,q+1,r);
    }
}

测试

    //-----QuickSort--------
    QuickSort* qs = new QuickSort();
    int array[]={0, -2, 11, -4, 13, -5, 14, -43, 17, 78, 90, 91, 92, 48};
    qs->doQuickSort(array,0,13);
    for(int i = 0 ; i <= 13 ; i++)
        cout<<array[i]<<" ";
    cout<<endl;

 

----cpp 2!!!----

#pragma once

#include <stdio.h>

class QuickSort
{
public:
    QuickSort(void);
    ~QuickSort(void);
public:
    void quickSort(int s[], int l, int r);
    void print(int arr[], int len);
};


QuickSort::QuickSort(void)
{
}
QuickSort::~QuickSort(void)
{
}


void QuickSort::quickSort(int s[], int l, int r)
{
    if (l < r)
    {
        //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
            {
                j--;
            }
            std::cout << endl;
            if(i < j) 
                s[i++] = s[j];
            
            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;  
            if(i < j) 
                s[j--] = s[i];
        }
        s[i] = x;
        quickSort(s, l, i - 1); // 递归调用 
        quickSort(s, i + 1, r);
    }
}

void QuickSort::print(int arr[], int len)
{
    for (int i=0; i<len; i++)
        cout << i << ":" << arr[i] << " ";
    cout << endl;
}

 调用:

int _tmain(int argc, _TCHAR* argv[])
{
        QuickSort* qsort = new QuickSort();
    int a[] = {10, 40, 30, 60, 90, 75, 70, 20, 50, 80};
    int len=(sizeof(a)) / (sizeof(a[0])) ;
    qsort->print(a, len);
    qsort->quickSort( a, 0, 9);
    qsort->print(a, len);

    system("pause");
    return 0;
}

 

C C++内置快排的使用

头文件 #include<stdlib.h>

函数形式 qsort(s,n,sizeof(s[0]),cmp);

第一个参数s是参与排序的数组名(或者也可以理解成开始排序的地址,因为可以写成&s[i]这样的表达式,这个问题下面有说明); 

第二个参数n是参与排序的元素个数

第三个参数是单个元素的大小,必须 sizeof(s[0])这样的表达式

第四个参数cmp其实是个函数名字,它是为指导qsort如何进行排序而专门写的一个函数,我们称之为比较函数,其目的是为了告诉qsort要以什么样的方式进行排序(降序?升序?或者按照某个关键字进行排序等)(Ps:写成cmp只是一个名字,可以随便怎么写),cmp这个函数有形参,和返回值(int型),但是在调用时却不需要给它传递实参进去,直接调用其名字即可,这个函数是专门为qsort开发的一种函数形式,这个函数的典型定义是:

  int cmp(const void *a,const void *b);(名字a和b可以随便换)(其函数体详见后面),并且规定这个函数只能返回int型值。

int cmp(const void *a, const void *b)
{
  return(*(int *)a-*(int *)b); // 升序
  /*这里的(int *)a定义了一个指向int型的指针,注意int *两边的括号不能少,然后(int *)a前面加上*就表示取其指向的值。这里返回的是*(int *)a-*(int *)b,两个数相减的顺序跟函数形参顺序一样这样就会将数组按升序排序,反之如果是return(*(int *)b-*(int *)a),就会将数组按降序排列*/
}

 

 

=============快排的小问题==========================

关于快排的一些小问题 
     1.快排的复杂度,当元素个数比较少时(10^2的数量级左右),快排的速度跟冒泡相比并没有快很多,还有如果要排序的元素大部分都已经是排好顺序了时,快排效率会下降,但是其最坏情况是N^2(当元素全部是已经排好的顺序时),一般情况(也即平均效率)是N*Log2(N),最好情况是N(当元素全部是逆序时),快排的特点是元素越乱排序速度越快,所以可以看出,虽然元素少时使用快排并没有很大优势,但是在快排的最坏情况跟冒泡、选择排序(冒泡、选择排序其复杂度不受元素顺序影响,永远为N^2)一样,所以快排永远是最快的。
     2.快排是不稳定的,这里的稳定性是指对于相同元素的处理上,快排会打乱相同元素的先后顺序(原因就在于快排排序原理,其排序过程是不断把元素分组打乱进行的),当然如果单纯排序一列数字是没什么区别的,假设我们有这样一列数字3,3,3,但是三个3是有区别的,我们标记为3a,3b,3c,快排后的结果不一定就是3a,3b,3c这样的排列,所以在某些特定场合我们要用结构体来使其稳定(No.5的例子就是说明这个问题的)
     3.快排的比较函数cmp的两个参数必须都是const void *的,这个要特别注意,写a和b只是个人喜好,写成cmp也只是个人喜好. 
     4.快排qsort的第三个参数,sizeof,推荐是使用sizeof(s[0])这样,特别是对结构体,往往自己定义2*sizeof(int)这样的会出问题,用sizeof(s[0)既方便又保险
     5.如果要对数组进行部分排序,比如对一个s[n]的数组,要对其从s[i]开始的m个元素进行排序,只需要在第一个和第二个参数上进行一些修改:qsort(&s[i],m,sizeof(s[i]),cmp);

----end!!!----

posted on 2014-02-17 16:53  AKever  阅读(833)  评论(0)    收藏  举报