转---有关快速排序-2

 

 

1.    基本思想
    首先选取一个记录作为枢轴(不失一般性,可选第一个记录),依它的关键字为基准重排其余记录,将所有关键字比它大的记录都排在它之后,而将所有关键字比它小的记录都排在它之前,由此完成一趟快速排序。之后,分别对由一趟排序分割而成的两个子序列进行快速排序。
   快速排序是一个递归的算法


2.性能分析:

   □最坏情况
当待排序记录已经"有序"的情况下,排序时间最长。这时,第一次划分经过n-1次比较,将第一个记录定在原位置上;第二次递归调用,经过n-2次比较,将第二个记录定在它原来的位置上,......,这样,总的比较次数为:
    C[[no]] = n (n-1) / 2 =O(n*n);

       □最好情况:
      每次划分所取的枢轴都是当前无序子序列中的"中值"记录,划分的结果是枢轴的左右两个子区的长度大致相等,这时总的比较次数为: C[[no]] ≤ n + 2C(n/2) ≤ n + 2[n /2+2C(n/22)] = 2n+4 (n/ 22) ≤ 2n + 4[n/4+2C(n/23 )] = 3n+8 (n / 23) ≤ ...... ≤ kn+2k C(n/2k) = nlog2n + nC(1) = O(nlog2n) 可以证明,快速排序的平均 时间复杂度是O(nlog2n),它是目前基于比较的内部排序方法中速度最快的一种,快速排序也因此而得名。

 
//* * * * * * * * * * * * * * * * * * * * * * * *
//*PROGRAM :快速排序 *
//*CONTENT :快速排序 *
//* * * * * * * * * * * * * * * * * * * * * * * *
#include <dos.h>
#include <conio.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20 //排序表的最大容量
typedef struct //定义排序表的结构
{int elemword[MAXSIZE]; //数据元素关键字
int count; //表中当前元素的个数
}SqList;
void InitialSqList(SqList&); //初始化排序表
void QuickSort(SqList &); //快速排序
void QSort(SqList &,int,int); //子序列快速排序
int Partition(SqList &,int,int); //一趟快速排序
void PrintSqList(SqList); //显示表中的所有元素
void main()
{SqList L; //声明表L
char j='y';

//-------------------------程序说明-------------------------------
printf("本程序将演示快速排序的操作。/n");
//----------------------------------------------------------------
while(j!='n'&&j!='N')
{InitialSqList(L); //待排序列初始化
QuickSort(L); //快速排序
PrintSqList(L); //显示排序结果
printf("继续进行下一次排序吗?(Y/N)");
scanf(" %c",&j);
}
printf("程序运行结束!/n按任意键关闭窗口!/n");
getchar();getchar();
}
void InitialSqList(SqList &L)
{//表初始化
int i;
printf("请输入待排序的记录的个数:");
scanf("%d",&L.count);
printf("请输入待排序的记录的关键字(整型数):/n");
for(i=1;i<=L.count;i++)
scanf("%d",&L.elemword[i]);
}
void QuickSort(SqList &L)
{//对顺序表L做快速排序。
QSort(L,1,L.count);
}
void QSort(SqList &L,int low,int high)
{//对顺序表中的子序列L.r[low..high]作快速排序
int pivotloc;
if(low<high) //长度大于1
{pivotloc=Partition(L,low,high); //将L.elemword[low..high]一分为二
QSort(L,low,pivotloc-1); //对低子表递归排序,pivotloc是枢轴位置
QSort(L,pivotloc+1,high); //对高子表递归排序
}
}
int Partition(SqList &L,int low,int high)
{//交换顺序表L中子表r[low..high]的记录,枢轴记录到位,并返回其所在位置,此时
//在它之前(后)的记录均不大(小)于它
int pivotkey;
pivotkey=L.elemword[low]; //用子表的第一个记录作枢轴记录
while(low<high) //从表的两端交替地向中间扫描
{while(low<high&&L.elemword[high]>=pivotkey)
--high;
L.elemword[low]=L.elemword[high];//将比枢轴记录小的记录移到低端
while(low<high&&L.elemword[low]<=pivotkey)
++low;
L.elemword[high]=L.elemword[low]; //将比枢轴记录大的记录移到高端
}
L.elemword[low]=pivotkey; //枢轴记录到位
return low; //返回枢轴记录
}
void PrintSqList(SqList L)
{//显示表中所有元素
int i;
printf("已排好序的序列如下:/n");
for(i=1;i<=L.count;i++)
printf("%4d",L.elemword[i]);
printf("/n");
}

快速排序
快速排序 Quick Sort

我们已经知道,在决策树计算模型下,任何一个基于比较来确定两个元素相对位置的排序算法需要Ω(nlogn)计算时间。如果我们能设计一个需要O(n1ogn)时间的排序算法,则在渐近的意义上,这个排序算法就是最优的。许多排序算法都是追求这个目标。

下面介绍快速排序算法,它在平均情况下需要O(nlogn)时间。这个算法是由C.A.R.Hoare发明的。

算法的基本思想

快速排序的基本思想是基于分治策略的。对于输入的子序列L[p..r],如果规模足够小则直接进行排序(比如用前述的冒泡、选择、插入排序均可),否则分三步处理:

分 解(Divide):将待排序列L[p..r]划分为两个非空子序列L[p..q]和L[q+1..r],使L[p..q]中任一元素的值不大于 L[q+1..r]中任一元素的值。具体可通过这样的途径实现:在序列L[p..r]中选择数据元素L[q],经比较和移动后,L[q]将处于 L[p..r]中间的适当位置,使得数据元素L[q]的值小于L[q+1..r]中任一元素的值。

递归求解(Conquer):通过递归调用快速排序算法,分别对L[p..q]和L[q+1..r]进行排序。

合并(Merge):由于对分解出的两个子序列的排序是就地进行的,所以在L[p..q]和L[q+1..r]都排好序后不需要执行任何计算L[p..r]就已排好序,即自然合并。

这个解决流程是符合分治法的基本步骤的。因此,快速排序法是分治法的经典应用实例之一。


快速排序法是对冒泡排序法的一种改进,也是基于交换排序的一种算法。因此,被称为"分区交换排序"。
   在待排序序列中按某种方法选取一个元素K,以它为分界点,用交换的方法将序列分为两个部分:比该值小的放在左边,否则在右边。形成"{左子序列}K{右子序列}"。再分别对左、右两部分实施上述分解过程,直到各子序列长度为1,即有序为止。
   分界点元素值K的选取方法不同,将构成不同的排序法,也将影响排序的效率:例如,可取左边第1个元素为分界点、取中点A[(left+right)/2]为分界点、或选取最大和最小值的平均值为分界点等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值