排序——快速排序

原创 2016年08月31日 11:20:24

终于有时间可以把快速排序,仔细的梳理一遍了。

快排 在实际中最常用的一种排序算法,速度快,效率高。就像名字一样,快速排序是最优秀的一种排序算法。

什么是快速排序?

快排的基本思想:快排采用的是分治(PS:分开治理)的思想。

过程是这样的:1、在一组数中找到一个基准值(key)

 2、把这一组数分为小于key的一小组数,和大于key的另一小组数(按升序排列)

把小于key的一小组数放在key的左边 ,大于key的另一小组数放在key的右边

 3、重复 1、 2步骤,直到各区间只有一个数。

下面用一组数来说明:

  1 ,  3  , 5 , 6  , 4  ,  2

  

下面我们就用代码实现,通过代码在继续理解

<span style="font-family:Microsoft YaHei;font-size:14px;">//快速排序             
int Partion(int *arr, size_t left,size_t right)//单次划分区间的左右索引
{
	assert(arr);
	if (left < right)
	{
		int key = arr[right];
		int begin = left;
		int end = right ;
		while (begin != end)
		{
			while (begin < end && arr[begin] <= key)
				begin++;
			while (begin < end && arr[end] >= key)
				end--;
			if (begin < end)
				std::swap(arr[begin], arr[end]);
		}
		//把key的位置放到中间(实现划分区间)
		std::swap(arr[begin ], arr[right]);
		return begin ;
	}
	return  -1;
}
void QuickSort(int arr[], size_t left , size_t right) //left right 是索引
{
	assert(arr );
	if (left < right)
	{
		int boundary = Partion(arr, left, right);
		QuickSort(arr, left, boundary - 1);  //boundary-1 是左区间的上限
		QuickSort(arr, boundary + 1, right); //boundary+1 是右区间的下限
	}
}</span>
下面我将主要讲述,代码的单次划分区间流程



其实,还有一种方法:挖坑法

具体是这样的:

<span style="font-size:14px;">//快排 -- 挖坑法
int Partion1(int arr[],  int left,  int right)
{
	assert(arr);
	if (left < right)
	{
		int key = arr[right];
		while (left != right)
		{
			while (left < right && arr[left] <= key)
				left++;
			if (left < right)
				arr[right--] = arr[left];//right--

			while (left < right && arr[right] >= key)
				right--;
			if (left < right)
				arr[left++] = arr[right];  // left++
		}
		//最后一个坑
		arr[right] = key;
	}
	return right;
}
void QuickSort1(int arr[], const size_t left , const size_t right)
{
	assert(arr);
	if (left < right)
	{
		int Boundary = Partion1(arr, left, right);
		QuickSort1(arr, left, Boundary - 1);
		QuickSort1(arr, Boundary + 1, right);
	}
}
</span>

这个挖坑法相比于第一种方法其实就是提前把数据搬移过去了。


用递归的方法就是使用了栈的思想, 那么我们来也自己创建议一个栈实现递归的思想。同时,就实现了递归和循环之间的转换

<span style="font-size:14px;">//快排---非递归--挖坑法
int Partltion_4(int arr[], int left, int right)
{
	assert(arr);
	if (left < right)
	{
	                 //	int mid = GetMid(arr, left, right);  后面怎么给值???
		int Key = arr[right];
		while (left != right)
		{
			while (left < right && arr[left] <= Key)
				left++;
			if (left < right)
			{
				arr[right--] = arr[left]; //填坑,right向前移动
			}
			while (left < right && arr[right] >= Key)
				right--;
			if (left < right)
			{
				arr[left++] = arr[right]; //填坑,left向后移动
			}
		}
		 arr[right] = Key;  //////////////////////////////////!!!
		 return right;
	}
	
}
void QuickSort_4(int arr[], int left, int right)
{
	assert(arr);
	stack<int> s;
	if (left < right)
	{
		int boundary = Partltion_4(arr, left, right);
		if (boundary - 1 > left )
		{
			s.push(left);
			s.push(boundary - 1);
		}
		if (boundary + 1 < right)
		{
			s.push(boundary + 1);
			s.push(right);
		}
		while (!s.empty())
		{
			int end = s.top();//结束位置
			s.pop();
			int begin = s.top();// 起始位置
			s.pop();

			int Boundary = Partltion_4(arr, begin, end); //多次划分

			if (Boundary - 1 > begin) //起始边界 由left-->begin
			{
				s.push(left);
				s.push(Boundary - 1);
			}
			if (Boundary + 1 < end)  //结束边界 right -->end
			{
				s.push(Boundary + 1);
				s.push(right);
			}
		}
	}
	
}</span>


另外,在找key值的时候,可能找的不好,从而使快排的不稳定型体现出来了,我们使用三数取中法获得取得key的下标:

int GetMid(int arr[], int left, int right)  //返回的数组下标
{
	assert(arr);
	int mid = left + ((right - left) >> 1);
	if (arr[left] < arr[right])
	{
		if (arr[mid] < arr[left])
		{
			return left;
		}
		else if (arr[mid] > arr[right])
		{
			return right;
		}
		else
		{
			return mid;
		}
	}
	else
	{
		if (arr[mid] < arr[right])
		{
			return right;
		}
		else if (arr[mid] > arr[left])
		{
			return left;
		}
		else
		{
			return mid;
		}
	}
}


快排的时间复杂度

最坏情况下,即数组已经有序或大致有序的情况下,每次划分只能减少一个元素,快速排序将不幸退化为冒泡排序,所以快速排序时间复杂度下界为O(nlogn),最坏情况为O(n^2)。

在实际应用中,快速排序的平均时间复杂度为O(nlogn)

快排的空间复杂度

速排序空间复杂度为logn(因为递归调用了) 

稳定性
不稳定






版权声明:本文为博主原创文章,转载需标明出处。

二分查找、快速排序对比和详解

**二分查找和快速排序(binarySearch)&&(quickSort)** 这两个都是用到分治的思想很容易搞混。而且即使binarySearch是用到分治到不一定意味着递归可以通过循环实现。而且...
  • qhrqhrqhr
  • qhrqhrqhr
  • 2016年03月24日 22:19
  • 2568

顺序表上实现快速排序

快速排序 (1)定义顺序表的存储结构; (2)在顺序表上实现快速排序; (3)用大量的数据测试最好、最坏和平均情况下的排序速度。 #include #include #include using...
  • migu77777
  • migu77777
  • 2016年12月17日 21:40
  • 832

多线程排序+快速排序

多线程排序,主要是将整个排序的序列分成若干份,每一个线程排序一份,所以线程排序完成之后,就进行归并,相当于多个有序序列合并成一个有序序列。 这里就需要用到线程屏障,也就是 pthread_b...
  • qq_25425023
  • qq_25425023
  • 2017年05月24日 20:07
  • 1450

[算法学习笔记]又一个采用分治法的排序算法----快速排序算法

快速排序算法快速排序算法是当前在实际排序应用中最好的选择,虽然排序算法最坏情况下的时间复杂度为O(n^2), 但是可以通过随机化的方式避免最坏情况的发生, 而快速算法的平均复杂度为O(n lgn), ...
  • u014235934
  • u014235934
  • 2016年07月24日 15:45
  • 1779

c语言指针实现快速排序

#include #include int Partition(int *Array,int i,int j) { int t = *(Array + i); while(i
  • u012421976
  • u012421976
  • 2016年11月19日 16:56
  • 1110

GPU快速排序笔记

利用CUDA 5.0最新推出的 Dynamic Parallelism,以往很难使用的分治法现在可以轻易的在GK110上利用这一新特性实现,非常方便: 算法思想: 随机选取一个枢纽元(pivot),对...
  • niexiao2008
  • niexiao2008
  • 2013年07月29日 21:57
  • 1734

(高效率排序算法二)快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。 快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另...
  • h348592532
  • h348592532
  • 2015年05月04日 19:02
  • 954

排序算法(五)快速排序多种版本

快速排序 ,就像它的名称一样,是时间复杂度比较低的一种排序算法。      我们知道,快速排序是通过分治的方法,将一个大的区间划分成小区间(找一个枢纽,将大的数放置在枢纽的右边,小的数放置在枢纽左...
  • peiyao456
  • peiyao456
  • 2016年11月22日 21:23
  • 1640

Linux多线程实践(7) --多线程排序对比

屏障int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthre...
  • hanqing280441589
  • hanqing280441589
  • 2015年02月19日 17:51
  • 3282

双向链表的快速排序

#include #include #include //定义类型 所有的排序例子中都是用的int作为data typedef int elemType; //返回值 #define ...
  • chary8088
  • chary8088
  • 2012年07月05日 19:32
  • 8246
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:排序——快速排序
举报原因:
原因补充:

(最多只允许输入30个字)