快速排序[平均时间复杂度O(NlogN)]

基本思想:

假设我们现在对“6 1 2 7 9 3 4 5 10 8”这10个数进行排序。首先在这个序列中随便找一个数作为基准数。为了方便,就让第一个数6作为基准数。分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换它们,用两个变量i和j分别指向最左边和最右边,直到i=j,将基准数与a[i]交换,再继续递归对两测进行一样的方式。

快速排序的每一轮处理其实就是将这一轮的基准数归位,直到所有的数都归位为止,排序就结束了。

#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用

void quicksort(int left,int right)
{
	int i,j,t,temp;
	if(left>right)
		return; 

	temp=a[left]; //temp中存的就是基准数
	i=left;
	j=right; 

	while(i!=j)
	{
		//顺序很重要,要先从右往左找
		while(a[j]>=temp && i<j)
			j--;
		//再从左往右找
		while(a[i]<=temp && i<j)
			i++; 

		//交换两个数在数组中的位置
		if(i<j)//当哨兵i和哨兵j没有相遇时
		{
			t=a[i];
			a[i]=a[j];
			a[j]=t;
		}
	} 

	//最终将基准数归位
	a[left]=a[i];
	a[i]=temp; 

	quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
	quicksort(i+1,right);//继续处理右边的,这里是一个递归的过程
}

int main()
{
	int i;
	//读入数据
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]); 

	quicksort(1,n); //快速排序调用

	//输出排序后的结果
	for(i=1;i<=n;i++)
		printf("%d ",a[i]); 

	return 0;
} 

下面是程序执行过程中数组a的变化过程:

快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的,都是O(N^2),它的平均时间复杂度为O(NlogN)。其实快速排序是基于一种叫做“二分”的思想。

时间: 2024-10-08 19:36:12

快速排序[平均时间复杂度O(NlogN)]的相关文章

平均时间复杂度为O(nlogn)的排序算法

本文包括 1.快速排序 2.归并排序 3.堆排序 1.快速排序 快速排序的基本思想是:采取分而治之的思想,把大的拆分为小的,每一趟排序,把比选定值小的数字放在它的左边,比它大的值放在右边:重复以上步骤,直到每个区间只有一个数.此时数组已经排序完成. 快速排序最重要的是partition函数功能的实现,也就是将比选定基数小的值放在他的左边,比选定基数大的值放在它的右边的功能函数. 熟悉快速排序的人也许都会有自己的partition函数的写法.此处,提供两种不同的partition函数写法. 例1:

各种排序方法与其相对应的最好、最坏、平均时间复杂度

排序方法 最坏时间复杂度 最好时间复杂度 平均时间复杂度直接插入 O(n2) O(n) O(n2)简单选择 O(n2) O(n2) O(n2)起泡排序 O(n2) O(n) O(n2)快速排序 O(n2) O(nlog2n) O(nlog2n)堆排序 O(nlog2n) O(nlog2n) O(nlog2n)归并排序 O(nlog2n) O(nlog2n) O(nlog2n) 原文地址:https://www.cnblogs.com/Akatsuki-Sanjou/p/9690810.html

你知道为什么快速排序的时间复杂度是n*lg(n)吗?

//你知道为什么快速排序的时间复杂度是nlgn吗? //我们将数组当作完全二叉数来看的话,放在小堆中, //每个节点排序需要o(h),也就是h次,h是完全相应节点的二叉树高度, //N为总共节点数,排好一个节点需要o(h)次,那么排好N个节点呢?下面: //且2^h=N-1(完全二叉树性质); //->h=log2(N);当有N个节点需要排序是就是N*lg(N), //得到快速排序的时间复杂度是N*log2(N),这里的2我们当作e,所以 //得到快排的时间复杂度是N*lg(N),其实从堆开始想

从顺序查找来看平均时间复杂度分析的一般化方法

顺序查找是在n 个元素的列表中查找一个给定项(或者说查找键)的一个简单的算法.它会检查列表中的连续元素,直到发现了匹配查找键的元素或者到达了列表的终点. 我们假设对输入规模为n 的数据做若干次查找,为了分析该算法的平均时间复杂度,还需要对规模为n 的输入做一些假设. 标准的假设是: 成功查找的概率是P(0 ≤ P ≤ 1) 对于任意的正整数i(1 ≤ i ≤ n),第一次匹配发生在列表第i 个位置的概率是相同的 基于这种假设,容易得出,在成功查找的情况下,对于任意的i,第一次匹配发生在列表的第i

各种排序算法的比较(最好、最差、平均时间复杂度,空间复杂度,稳定性)

对比表格 分类 算法 时间复杂度 空间复杂度       稳定性           关联性        最好          最差        平均       插入排序        直接插入排序      O(n)(优化后)     O(n2)           O(n2)           O(1) 稳定   希尔排序 O(n) O(n2) 不确定 O(1) 不稳定 基于直接插入排序     选择排序 直接选择排序 O(n2) O(n2) O(n2) O(1) 不稳定   堆排

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已经做了实现,但是这种方法时间复杂度太高,查阅相关资料后我发现有人提出的算法可以将时间复杂度降低为O(nlogn),这种算法的核心思想就是替换(二分法替换),以下为我对这中算法的理解: 假设随机生成的一个具有10个元素的数组arrayIn[1-10]如[2, 3, 3, 4, 7, 3, 1, 6,

数据结构拾遗——排序(时间复杂度O(nlogn)

之前几个排序时间复杂度是n方,接下来这几个速度就要比较快了 ShellSort.h 1 #pragma once 2 #include "swap.h" 3 #include <vector> 4 template <typename T> 5 void ShellSort(vector<T> &v) { 6 increment = v.size(); 7 do 8 { 9 increment = increment / 3 + 1; 10

【难】求数组中最长递增子序列,时间复杂度O(nlogn)

题目:<编程之美> P194 写一个时间复杂度尽可能低的程序,求一个数组(length个元素)中最长递增子序列的长度. 注意,本题认为最长递增子序列可以有相等的元素,如 (1,2,2,3,3,4,5,6). 时间复杂度为O(n^2)的程序思路很简单,参考书上的解法一.针对O(n^2)的解法进行改进,利用有序数组的二分查找,可以使得时间复杂度降低.本题的难点在于,建立一个长度为length+1的数组MinV,MinV[i]代表着长度为i的递增子序列最大元素的最小值.而且数组MinV是升序的,理解

稳定排序nlogn之归并排序_一维,二维

稳定排序:排序时间稳定的排序 稳定排序包括:归并排序(nlogn),基数排序[设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)) ],冒泡排序(n^2),插入排序(n^2),交换排序(n^2),计数排序[n为数字个数,k为数字范围,O(n+k)]等. Problem:对n个数进行排序,n<=100000,1s以内 正常来说我们都用qsort(c),sort(c++),但快速排序平均时间复杂度为nlogn,最坏时间复杂度为n^