上一篇博客写了归并排序,作为一个程序员必要掌握的排序算法,有冒泡排序,选择排序,快速排序等,而这其中,快速排序几乎是最爱被涉及的,以前学习算法时,没有注重具体的方法,比如分治法,关于分治法的概念,上一篇博客已经写了,不再赘述,有一次上课,我们的算法老师,老战,问了我们大家一个问题,说大家有没有人能在15分钟内写出,冒泡排序,选择排序,快速排序,那时大家基本都沉默了,不想说中国教育的不是,主要的原因是,我自己平时没有打下很好的基础,没有多下功夫打好这些根基,所以才有了今天的冲动,来写这些博客,说实话,一方面,是写给自己看的,另一方面,是想存储下自己的所学,尽管年纪稍大,尽管还在为未来苦苦挣扎,下好每一分功夫,重头再来,终会有一点效果,废话不多说,来实惠的。
下面简介一下快速排序(当然,借用一下百度百科的智慧)
快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
为了使得说明更具体举一个例子:3,2,1,8,4,9,5,6
我们选择第一个数字3作为被比较的数字,每次默认被划分区域的第一个数字为被比较的数字
假设开始时i指向3,j指向5,各趟划分如下
(2, 1) 3 ( 8 , 4,9 , 5, 6)
/ \
(1)2 ( 5 ,4, 6) 8 ( 9 )
/
(4) 5 (6)
最终排序结果 1 2 3 4 5 6 8 9
#include <iostream>
#include <stdlib.h>
using namespace std;
void swap(int a[],int b[])
{
int temp=*a;
*a=*b;
*b=temp;
}
/*第一种分割函数写法*/
int Partition(int a[],int first,int end)
{
int i=first;
int j=end; //确定左右边界(有的人会使j=end+1,使得j成为一个哨兵结点,防止越界)
int pivot = a[first]; //与第二种分割函数不同处,这里指定了一个比较数,相当于分割的标记,这个数的左边小于等于它,数的右边大于等于它
while(i<j) //大前提是i<j,否则一趟分割结束
{
if(a[i]<=pivot) i++;
if(a[j]>=pivot) j--;
if(i<j)
swap(a[i],a[j]); //指针左右移动,并进行比较,交换
}
swap(a[first],a[j]); //一趟分割结束,给指定那个数找到了最终的位置,我们可以形象地理解为插了一面旗帜,划定了左右界限
return j;
}
/*第二种分割函数写法*/
int partition(int a[],int first,int end)//与第一种不同,第二种没有指定一个数进行比较,其实综合理解后,发现默认第一个数或最后一个数就是被比较的,而是前后比较
{
int i=first;
int j=end;
while(i<j)
{
while(i<j&&a[i]<a[j]) j--;//从右边开始扫描,当i<j,a[i]<a[j],右边指针向左移动,j--
if(i<j)
{
swap(a[i],a[j]);
i++;
} //当i<j条件满足,但出现a[i]>=a[j]情况,左边指针向右移动i++,
while(i<j&&a[i]<a[j]) i++; //从左边开始扫描 当i<j,a[i]<a[j],左边指针向左移动,i++
if(i<j)
{
swap(a[i],a[j]);
j--;
} //当i<j条件满足,但出现a[i]>=a[j]情况,右边指针向左移动,j--
}
return i; //左右指针相遇或错过,最终定位
}
int QuickSort(int a[],int first,int end)
{
if(first<end)
{
int pivot = Partition(a,first,end);
//int pivot = partition(a,first,end);
QuickSort(a,first,pivot-1);
QuickSort(a,pivot+1,end);
}
}
int main()
{
int a[8]={3,2,1,8,4,9,5,6};
for(int i=0;i<8;i++)
cout<<a[i]<<" ";
cout<<endl;
QuickSort(a,0,7);
for(int i=0;i<8;i++)
cout<<a[i]<<" ";
cout<<endl;
}