当前位置: 首页 > 编程日记 > 正文

【经典算法】快速排序

与归并排序一样,快速排序使用也使用了分治的思想。下面是对一个典型的子数组A[p,...,r]进行快速排序的三步分治过程:

分解:数组A[p,...,r]被划分成两个(可能为空)子数组A[P,...,q-1]和A[q+1,...,r],使得A[p,...,q-1]中每个元素都小于等于A[q],而A[q]也小于等于A[q+1,...,r]中的每个元素。其中,计算下标q也是划分过程的一部分。

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

合并:因为子数组都是原址排序的,所以不需要合并操作:数组A[P,...r]已经有序。

下面是程序实现快速排序:

1 void QuickSort(int a[], int p, int r) {
2     if (p < r) {
3         int q = Partition(a, p, r);
4         QuickSort(A, p, q - 1);
5         QuickSort(A, q + 1, r);
6     }
7 }

数组的划分:

算法的关键部分是Partition过程,它实现了对子数组A[p,...r]的原址重排。快速排序的分治partition过程有两种方法。

1) 两个下标分别从首、尾向中间扫描的方法。

假设每次总是以当前表中第一个元素作为枢纽值(基准)对表进行划分,则必须将表中比枢纽值大的元素向右移动,比枢纽值小的元素向左移动,使得一趟Partition()操作之后,表中的元素被枢纽值一分为二。

 1 int Partition(int a[], int low, int high) {
 2     int pivot = a[low];
 3     while (low < high) {
 4         while (low < high && a[high] >= pivot) --high;
 5         a[low] = a[high];
 6         while (low < high && a[low] <= pivot) ++low;
 7         a[high] = a[low];
 8     }
 9     a[low] = pivot;
10     return low;
11 }

2)两个指针索引一前一后逐步向后扫描的方法(算法导论)。

 1 int Partition(int a[], int low, int high) {
 2     int pivot = a[high];
 3     int i = low - 1;
 4     for (int j = low; j <= high - 1; j++) {
 5         if (a[low] <= pivot) {
 6             ++i;
 7             swap(a[i], a[j]);
 8         }
 9     }
10     swap(a[i + 1], a[high]);
11     return i+112 }

注意:上述算法有一个特点,即一次划分后,枢纽左边的相对位置不变。比如,原始序列:[3,8,7,1,2,5,6,4]->[3,1,2,4,7,5,6,8]。枢纽4左边的相对顺序不变,元素3,1,2保持在初始序列中的相对顺序(原序列中为3,...,1,2,...),某些应用要求序列的一部分保持相对顺序,这时可以考虑此种划分。

快速排序算法的性能分析如下:

空间效率:由于快速排序是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应与递归调用的最大深度一致。最好情况下为⌈log2(n+1)⌉;最坏情况下,因为要进行n-1次递归调用,所以栈的深度为O(n);平均情况下栈的深度为O(log2n)。因而空间复杂度在最坏情况下为O(n),平均情况下为O(log2n)。

时间效率:快速排序的运行时间与划分是否对称有关,而后者又与具体使用的划分算法有关。快速排序最坏的情况发生在两个区域分别包含n-1个元素和0个元素时,这种程度的不对称性若发生在每一层递归上,即对应于初始排序表基本有序货基本逆序时,就得到最坏情况下的时间复杂度为O(n2)。

有很多方法可以提高算法的效率。一种方法是当递归过程中划分得到的子序列的规模较小时不要再继续调用快速排序,可以直接采用直接插入排序算法进行后续的排序工作。另一种方法就是尽量选取一个可以将数据中分的枢轴元素。如从序列的头尾以及中间选取三个元素,再取这三个元素的中间值作为最终的枢轴元素(数据结构与算法分析);或者随机从当前列表中选取枢轴元素(算法导论),这样做使得最坏情况在实际安排中几乎不会发生。

在最理想状态下,也即Partition()可能做到最平衡的划分中,得到的两个子问题的大小都不可能大于n/2,这种情况下,快速排序的运行速度将大大提升,此时,时间复杂度为O(nlog2n)。好在快速排序平均情况下运行时间与其最佳情况下的运行时间很接近,而不是接近最坏情况下的运行时间。

快速排序是所有内部排序算法中平均性能最优的排序算法。

稳定性:快速排序不是稳定的排序算法。

一、快速排序一次排序的应用

1.一个数组中存储有且仅有大写和小写字母,编写一个函数对数组内的字母重新排列,让小写字母在所有大写字母之前。

 1 void Partition(char a[], int length) {
 2     if (a == NULL || length <= 0)
 3         return;
 4     
 5     int i = 0;
 6     for (int j = 0; j <= length - 1; ++j) {
 7         if (a[j] >= 'a' && a[j] <= 'z') {
 8             i++;
 9             char temp = a[i];
10             a[i] = a[j];
11             a[j] = temp;
12         }
13     }
14 }

2. 给定含有n个元素的整形数组a, 其中包括0元素和非0元素,对数组进行排序,要求:

1)排序后所有0元素在前,所有非零元素在后,且非零元素排序前后相对位置不变。

2)不能使用额外存储空间。、

例如:

输入 0、3、0、2、1、0、0

输出 0、0、0、0、3、2、1

解答:此处要求非零元素排序前后相对位置不变,可以利用快排一次排序的第二种情况。

void Partition(int A[], int p, int r) {int i = r + 1;for (int j = r; j >= p; --j) {if (A[j] != 0) {--i;int temp = A[i];A[i] = A[j];A[j] = temp;}}
}

3. 荷兰国旗问题

将乱序的红白蓝三色小球排列成同颜色在一起的小球组(按照红白蓝排序),这个问题称为荷兰国旗问题。这是因为我们可以将红白蓝小球想象成为条状物,有序排列后正好组成荷兰国旗,用0表示红球,2为篮球,1为白球。

解答:这个问题,类似于快排中partition过程。不过,要用三个指针,一个begin,一中current,一后end,begin与current都初始化指向数组首部,end初始化指向数组尾部。

1. current遍历整个数组序列,current指1时,不交换,current++;

2. current指0时,与begin交换,而后current++,begin++;

3. current指2时,与end交换,而后,current不动,end--。

 1 while (current <= end) {
 2     if (array[current] == 0) {
 3         swap(array[current], array[begin]);
 4         current++;
 5         begin++;
 6     } else if (array[current] == 1) {
 7         current++;
 8     } else {
 9         swap(array[current], array[end]);
10         end--;
11     }
12 }

二、最小的k个数

输入n个整数,输出其中最小的k个。

例如输入1,2,3,4,5,6,7,8这8个数字,则最小的4个数字为1,2,3,4

解答:分析:这到底最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数就是最小的k个数。只是这种思路的时间复杂度为O(nlgn)。我们试着寻找更快的解题思路。

我们设最小的k个数中最大的数为A。在快速排序算法中,我们现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小的数字都排在他的左边,比选中的数字大的数字都排在它的右边(即快排一次排序)。如果这个选中的数字的下标刚好是k-1(下标从0)开始,那么这个数字(就是A)加上左侧的k-1个数字就是最小的k个数。

如果它的下标大于k-1,那么A应该位于它的左边,我们可以接着在它的右边部分的数组中寻找。可见这是一个递归问题,但是注意我们找到的k个数不一定是有序的。

 1 int Partition(int a[], int p, int r) {
 2     int pivot = a[r];
 3     int i = p - 1;
 4     for (int j = p; j <= r - 1; ++j) {
 5         if (a[j] <= pivot) {
 6             ++i;
 7             swap(a[i], a[j]);
 8         }
 9     }
10     swap(a[i + 1], a[r]);
11     return i + 1;
12 }
13 void GetLeastKNum(int *input, int n, int k) {
14     if (input == NULL || n <= 0 || k > n || k <= 0)
15         return;
16 
17     int start = 0;
18     int end = n - 1;
19     int index = Partition(input, start, end);
20     while (index != k - 1) {
21         if (index < k - 1) {
22         start = index + 1;
23         index = Partition(input, start, end);
24         } else {
25             end = index - 1;
26             index = Partition(input, start, end);
27         }
28     }
29 
30     for (int i = 0; i <= k - 1; ++i) {
31         cout << input[i];
32     }
33     cout << endl;
34 }

上述方法的时间复杂度是O(n)。

转载于:https://www.cnblogs.com/vincently/p/4522957.html

相关文章:

.Net 中如何测试静态方法

大部分Mokc框架是不支持mock静态方法的&#xff0c;那我们如何测试静态方法呢&#xff1f; 下面这个类包含了一个静态方法&#xff1a; public class MyHelper {public static string GetHelp(){return "This is help";} } 这个类调用了上面的Helper类中的静态方法 p…

计组--习题--总线

计算机使用总线结构的主要优点是便于实现积木化&#xff0c;缺点是______ A、 地址信息、数据信息和控制信息不能同时出现 B、 地址信息与数据信息不能同时出现 C、 两种信息源的代码在总线中不能同时传送 这里是引用 总线中地址线的作用是_______ A、 只用于选择存储器单元 B…

dispatch_queue_create(com.biostime.xxx, DISPATCH_QUEUE_SERIAL)的陷阱

代码 for(int i 0;i<10;i) { NSLog("i%d",i); dispatch_queue_t mySerialQueue dispatch_queue_create("com.biostime.xxx", DISPATCH_QUEUE_SERIAL); __block int d i; dispatch_async(mySerialQueue, ^{ …

详解Oracle安装与配置.

标签&#xff1a;Oracle 安装 配置 原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://enetq.blog.51cto.com/479739/316532 一.Oracle 简介. Oracle oracle是殷墟&#xff08;Yin Xu&#…

今天起,在广东可以用百度App一键报警!

今天&#xff0c;百度联合广东省公安厅上线了一款智能小程序&#xff1a;只要打开你手机里的百度 App 就能用了 &#xff01;在110实际接警的过程中&#xff0c;经常会遇到电话并不能很好地表达发生事件的地点等信息的情况&#xff0c;会耽误救援时间。因此&#xff0c;“广东1…

Spring 注解

1. Configuration Configuration用于定义配置类&#xff0c;可替换xml配置文件&#xff0c;被注解的类内部包含有一个或多个被Bean注解的方法&#xff0c;这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描&#xff0c;并用…

Junit的安装与使用

一、简介&#xff1a; JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立&#xff0c;逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。Junit测试是程…

安装 ssh 的公开密匙到 iPhone 上

1). 在Mac的终端上产生密匙 ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/xxxx/.ssh/id_rsa): Created directory /home/xxxx/.ssh. Enter passphrase (empty for no passphrase): xxx Enter same passphrase again…

浏览器关闭事件处理

//有确认退出var msg_unload"您的文章内容还没有进行保存&#xff01;";var unloadConfirm {};unloadConfirm.SetConfirmMsg function(confirmMsg){ window.onBeforeUnload function(event) { event event || window.event; event.returnval…

spring注解--@Bean

Configuration public class KnightConfig {Beanpublic Knight knight(){return new BraveKnight(quest () );}}spring的Bean注解用于告诉方法&#xff0c;产生一个Bean对象&#xff0c;然后把这个Bean对象交给spring管理。注意&#xff1a;产生这个Bean对象的方法Spring只会调…

如何用 Windows Live Writer 和 Word 2013 分别发表博客到Cnblog 和CSDN

ps CSDN 老是505错误&#xff0c;放弃了 为什么会写这篇 最近写博客在 Cnblog 上面写博客&#xff0c; 发现图片不能复制了直接粘贴上&#xff0c;这对于把博客当随手笔记的人来说无疑非常痛苦。求助于博客园&#xff0c;他们让我用 Windows Live Writer 试试。我查了下大家推荐…

JavaScript 事件冒泡简介及应用(转)

http://www.jb51.net/article/21801.htm 一、什么是事件冒泡在一个对象上触发某类事件&#xff08;比如单击onclick事件&#xff09;&#xff0c;如果此对象定义了此事件的处理程序&#xff0c;那么此事件就会调用这个处理程序&#xff0c;如果没有定义此事件处理程序或者事件返…

不改文件名的情况下上传突破

方法不错&#xff0c;首先就是不强制改上传文件名。还有就是上传目录没有执行的权限。 然后用这方法貌似就可以上传到上级可写目录了。 比如抓这是抓的上传数据包: POST /upload/upfile.asp HTTP/1.1Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image…

static interface method calls are not supported at language level 1.6

报错解决&#xff08;导入项目时&#xff09; 点击那个红色的小灯泡 下面的那行&#xff1a; set language to … 等待 即可

Objetive-C +load方法研究

load方法的执行时机Objetive-C 的runtime会在一个类的所有方法加载到内存中时调用这个类的load() 方法&#xff0c;因为每个类的方法只是加载一次&#xff0c;所以每个load&#xff08;&#xff09;方法只调用一次。加载一个类的方法会在一个进程启动开始的时候&#xff0c;这个…

HDU3434数学题

纯粹的数学题&#xff0c;题目的意思是给你一组序列&#xff0c;让你能同时改变它的一个子序列&#xff0c;让其子序列的值增加1&#xff0c;或者减少1. 思路的话&#xff0c;就是找其中的数学规律&#xff0c;给你的序列例如是&#xff1a;3,5,1,4,7。先求出其序列的正差和5-3…

python的基本知识点

一.数据类型 1.整数2.浮点数3.字符串4.布尔值:True/False5.空值:None 二.变量 变量名必须是大小写英文、数字和_的组合&#xff0c;且不能以数字开头 三.常量 全部大写的变量名表示常量,python没有一种机制保证常量不能被修改.PI 3.14156 四.特殊的地板除 // // 除法只取结果的…

上传代码到git上的分支(协同开发)

任意位置右键单击 git bash,输入命令如下&#xff1a; git config --global user.name "用户名" &#xff08;用户名就是gitlab上的用户名&#xff0c;我的是名字拼音&#xff09;git config --global user.email "邮箱" &#xff08;注册gitlab时的邮箱&…

Android网络编程系列 一 Socket抽象层

在《Android网络编程》系列文章中&#xff0c;前面已经将Java的通信底层大致的描述了&#xff0c;在我们了解了TCP/IP通信族架构及其原理&#xff0c;接下来我们就开始来了解基于tcp/ip协议层的Socket抽象层。本篇文章将会让我们清楚的了解和学会使用Socket。什么是Socket&…

HDFS的shell和API操作

1. HDFS的shell操作 hadoop version //查看版本 hadoop fs -appendToFile src(Linux中的文件) dest(hdfs目录下的文件) //追加 hadoop fs -cat file(hdfs目录下的文件) //查看文件内容 Hadoop fs -tail file(hdfs目录下的文件) //查看文件末尾1kb的数据…

C#中的问号用法

在看一些国外牛人写的C#代码时&#xff0c;总是看到会有Boolean?、DateTime?这样的类型&#xff0c;以为是一些新的类型&#xff08;该类型变量有一些新的属性和方法&#xff09;&#xff0c;后来经过查找相关的资料&#xff0c;发现原来另有微妙。以下是MSDN中对这个问号的解…

L1-006 连续因子

题目&#xff1a; 一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3567&#xff0c;其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N&#xff0c;要求编写程序求出最长连续因子的个数&#xff0c;并输出最小的连续因子序列。 输入格式&#xff1a; 输…

Python Data Structures

1. list 2. stack 3. queue 4. tuple 5. sequence 6. set 7. dict #-*- coding: utf-8 -*-# 添加中文注释Created on 2011-4-29test for python data structureauthor: xuqiang###################list##################print("test for list");a [66.25, 333, 333…

【转】 ubuntu12.04更新源

原文网址&#xff1a;http://blog.chinaunix.net/uid-26404477-id-3382633.html 摘 要&#xff1a;本文列出ubuntu 12.04 LTS更新源列表&#xff0c;内容为网友整理&#xff0c;此处为转载。因为我还在重庆读书&#xff0c;所以在设置自己的源列表的时候选择了电子科技大学的更…

Ubuntu 上创建常用磁盘阵列

RAID(Redundant Array of Independent Disk 独立冗余磁盘阵列)技术是加州大学伯克利分校1987年提出&#xff0c;最初是为了组合小的廉价磁盘来代替大的昂贵磁盘&#xff0c;同时希望磁盘失效时不会使对数据的访问受损 失而开发出一定水平的数据保护技术。RAID就是一种由多块廉价…

L1-009 N个数求和

题目 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出一个正整数N&#xff08;≤100&#xff09;。随后一行按格式a1/b1 a2/…

我的理解:box-sizing

下面是我在博客园找到的&#xff0c;和我遇见的情况很相似&#xff0c;所以摘抄下来&#xff0c;原文见:http://www.cnblogs.com/charling/p/3635031.html box-sizing语法&#xff1a; box-sizing &#xff1a; content-box || border-box || inherit 参数取值&#xff1a; con…

世界最大规模3D打印混凝土步行桥在上海 落成启用

1月12日&#xff0c;世界最大规模3D打印混凝土步行桥在沪落成启用&#xff0c;人们站在桥体上欢庆该新兴建筑体的诞生。 中新网上海1月13日电 (记者 于俊)一座体态优雅、形似飘带的水泥桥12日横跨于上海宝山智慧湾的小河之上&#xff0c;宣告全球最大规模混凝土3D打印步行桥落成…

idea打开web项目之后一直闪烁

解决办法&#xff1a; 点击&#xff0c; 选择第一个&#xff08;清除缓存并重启&#xff09; 这时Idea会自动重新启动&#xff0c;之后就没有闪烁的状态了。 一开始我选择是第二个&#xff0c;清除无效的缓存&#xff0c;但是并没有起作用。

第十章:控制文件

控制文件管理[大纲] 控制文件的结构  控制文件的复用  控制文件的重建  控制文件的管理一、数据库控制文件控制文件中记载了数据库的物理结构等重要的数据库信息&#xff0c;如数据文件和日志文件信息。控制文件是用 于维护数据库完整性的重要文件。Oracle 正是使用…