常用排序算法之快速排序

快速排序最坏情况运行时间为O(n2),但实际中通常都是用于排序的最佳的实用选择,因为其平均性能相当好:期望的运行时间为O(nlgn),且O(nlgn)记号中隐含的常数因子很小。

快速排序是一种就地排序。同时,是一种不稳定的排序。本文内容主要参照算法导论。

快速排序主要利用了分治的思想。一般分为三步进行:

分解:数组A[p..r]被划分为两个子数组A[p..q-1]和A[q+1..r],其中A[p..q-1]的元素都小于等于A[q],A[q+1..r]都大于等于A[q]。

解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序。

合并:因为两个子数组是就地排序的,将它们合并不需要额外操作,整个数组已经是排好序的。

下面是快速排序的C语言代码:

 1 int QuickSort(int *A,int p, int r)
 2 {
 3     if(p<r)
 4     {
 5         int q;
 6         q=Partition(A,p,r);
 7         QuickSort(A,p,q-1);
 8         QuickSort(A,q+1,r);
 9     }
10 }

快速排序的关键是Partition过程,它对子数组A[p..r]进行就地排序,代码如下:

 1 int Partition(int *A,int p, int r)
 2 {
 3     int i,j,x;
 4     x=A[p];                       //选取第一个元素作为主元
 5     i=p;
 6     for(j=p;j<r;j++)
 7     {
 8         if(x>=A[j+1])              //若小于等于主元则交换元素j+1和i+1
 9         {
10          int temp;
11          temp=A[i+1];
12          A[i+1]=A[j+1];
13          A[j+1]=temp;
14          i++;
15         }
16     }
17     int temp;                     //最后一步,将主元放到合适的位置,因为此处选取的主元的第一个元素,而i所指向的是最后一个小于等于主元的元素,因此交换主元和i元素,                                       使得A[p..q-1]的元素都小于等于A[q],A[q+1..r]都大于等于A[q]
18     temp=A[p];
19     A[p]=A[i];
20     A[i]=temp;
21     return i;
22 }

下图左边描述了快排的Partition过程,图中主元选取的是最后一个元素跟上述代码不一样,不过这没关系。右边是快速排序的动态演示。

始终记住,i是小于和大于主元的分界线,二j是已处理和未处理的分界线,即i前面的元素都是小于等于主元,而i+1到j都是大于等于主元的元素,j之后的元素是还没比较的元素。

 

最后,贴上我在devc++里写的完整代码:

 1 #include <iostream>
 2 #include <stdlib.h>
 3 using namespace std;
 4
 5 int QuickSort(int *A,int p, int r);
 6 int Partition(int *A,int p, int r);
 7
 8 int main()
 9 {
10     int i,n;
11     cout<<"Please input the size of your array"<<endl;
12     cin>>n;
13     int *A = new int[n];
14     cout<<"Please input your array"<<endl;
15     for(i=0;i<n;i++)
16     {
17         cin>>A[i];
18     }
19     QuickSort(A,0,n-1);
20     for(i=0;i<n;i++)
21     {
22         cout<<A[i]<<" ";
23
24     }
25     cout<<endl;
26     delete A;
27     system("pause");
28     return 0;
29 }
30
31 int QuickSort(int *A,int p, int r)
32 {
33     if(p<r)
34     {
35         int q;
36         q=Partition(A,p,r);
37         QuickSort(A,p,q-1);
38         QuickSort(A,q+1,r);
39     }
40 }
41
42 int Partition(int *A,int p, int r)
43 {
44     int i,j,x;
45     x=A[p];
46     i=p;
47     for(j=p;j<r;j++)
48     {
49         if(x>A[j+1])
50         {
51          int temp;
52          temp=A[i+1];
53          A[i+1]=A[j+1];
54          A[j+1]=temp;
55          i++;
56         }
57     }
58     int temp;
59     temp=A[p];
60     A[p]=A[i];
61     A[i]=temp;
62     return i;
63 }

另外,快排还有一种典型的实现方法,就是霍尔快排,维基百科上介绍的快速排序就是这种实现。下面贴上维基百科的霍尔快排:

 1 void swap(int *x, int *y) {
 2     int t = *x;
 3     *x = *y;
 4     *y = t;
 5 }
 6 void quick_sort_recursive(int arr[], int start, int end) {
 7     if (start >= end)
 8         return;//這是為了防止宣告堆疊陣列時當機
 9     int mid = arr[end];
10     int left = start, right = end - 1;
11     while (left < right) {
12         while (arr[left] < mid && left < right)
13             left++;
14         while (arr[right] >= mid && left < right)
15             right--;
16         swap(&arr[left], &arr[right]);
17     }
18     if (arr[left] >= arr[end])
19         swap(&arr[left], &arr[end]);
20     else
21         left++;
22     quick_sort_recursive(arr, start, left - 1);
23     quick_sort_recursive(arr, left + 1, end);
24 }
25 void quick_sort(int arr[], int len) {
26     quick_sort_recursive(arr, 0, len - 1);
27 }

时间: 2024-12-30 13:42:32

常用排序算法之快速排序的相关文章

常用排序算法之——快速排序

快速排序的原理: 首先找一个标兵值,等于某一个元素值:遍历数组,将数组分为小于标兵值和大于标兵值的两部分:然后分别对两个部分采用快速排序,递归. 分开数组时,维持一个指针,指向已找到小部分的最后一个元素:一个指针用于遍历. 不稳定排序算法.当数组已经有序时,时间复杂度最差,为O(N2),平均.最优情况下都为O(N lgN). 代码如下: 1 #include <iostream> 2 using namespace std; 3 4 template<typename T> 5 v

常用排序算法之——快速排序(C语言+VC6.0平台)

经典排序算法中快速排序具有较好的效率,但其实现思路相对较难理解. #include<stdio.h> int partition(int num[],int low,int high) //以key为基准 将待排数列“高”.“低 ”两部分,“高”部分的所有数据比key大,“低”部分的数据都比key小 { int left,right,key; left=low;right=high;key=num[low]; while(left<right) { while(left<right

常用排序算法之--快速排序

个人认为,数据结构与算法是部分程序员的软肋,而对于非科班出身的程序员来说,更是软肋中的软肋. 纠其原因,大部分是因为作为应用层面的程序开发,算法(尤其是查找算法)并不是影响程序性能的最关键的因素.同时作为一个完整的系统,从数据存储到获取都提供了 相应的调用接口,如果要获取数据,我们只需要调用外部接口就可以了.模块化.工厂化导致了我们对算法的依赖降低了.依赖降低了,就导致这部分知识的退化.只是在找工作的时候,又得重拾这部分代码.唉,不说了,要不然又该挨广大园友们喷了. 欢迎与广大朋友交流学习,qq

视觉直观感受7种常用排序算法

视觉直观感受若干常用排序算法 1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: 从数列中挑出一个元素,称为 "基准"(pivo

常用排序算法实现[交换排序之冒泡排序、快速排序]

相关知识 1. 稳定排序和非稳定排序: 稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序. 如果排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前. 2. 内排序和外排序 在排序过程中,所有需要排序的数都在内存,并在内存中调整它们的存储顺序,称为内排序: 在排序过程中,只有部分数被调入内存,并借助内存调整数在外存中的存放顺序排序方法称为外排序. 3.算法分类 排序算法从理论上分为如下几类: (1) 交换排序法:

DotNet常用排序算法总结

数据结构和算法对一个程序来说是至关重要的,现在介绍一下几种算法,在项目中较为常用的算法有:冒泡排序,简单选择排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序等7中算法. 现在介绍选择排序算法,希尔排序算法,快速排序算法. (1).选择排序算法:通过n-i次关键字间的比较,从n-i+1个记录中选择出关键字最小的记录,并和第i(1大于等于i小于等于n)个记录交换. (2).希尔排序:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组.所有距离为d1的倍数的记录放在同一个组中.先在各

Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空间最多:归并排序 所需辅助空间最少:堆排序 平均速度最快:快速排序 不稳定:快速排序,希尔排序,堆排序. 先来看看 8种排序之间的关系: 1.直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2]

常用排序算法比较与分析

一.常用排序算法简述 下面主要从排序算法的基本概念.原理出发,分别从算法的时间复杂度.空间复杂度.算法的稳定性和速度等方面进行分析比较.依据待排序的问题大小(记录数量 n)的不同,排序过程中需要的存储器空间也不同,由此将排序算法分为两大类:[内排序].[外排序]. 内排序:指排序时数据元素全部存放在计算机的随机存储器RAM中. 外排序:待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中还需要对外存进行访问的排序过程. 先了解一下常见排序算法的分类关系(见图1-1) 图1-1 常见排

七种常用排序算法

七种常用排序算法 一.常见排序算法一览: 时间复杂度: 是一个函数,它定量描述了该算法的运行时间. 空间复杂度:一个算法在运行过程中临时占用存储空间大小的量度. 稳定性:保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同就稳定,反之不稳定. 视觉直观感受 7 种常用的排序算法 二.算法C#实现: 1. 直接插入排序: using System; using System.Collections.Generic; using System.Linq; using Sys