八大排序———快速排序

背景介绍:

快速排序(Quicksort)是对冒泡排序的一种改进。 

   快速排序由C.A.R.Hoare在1962年提出。

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,将整个排序过程可以递归进行,依次达到整个数据变成有序序列。

 

一:算法思想

  (基本)快速排序的三大步骤:

1.选择基准:在待排序列中,按照某种方式挑选出一个元素,作为“基准”(pivot):这个基准的选择很重要会影响到整个算法的效率
2.分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。此时,再基准左边的元素都比该基准小,在基准右边的元素都比基准大。
3.递归操作:递归地对这两个序列进行快速排序,直到序列为空或者只有一个元素

 

一趟快速排序的思想是:

  ①:设置两个遍历变量,i和j。排序开始时 i=0;j=N-1
  ②:以第一个数据元素作为关键数据,赋值给key,即:key = A【0】;
  ③:从j开始向前搜索,j--,找到第一个小于key的值A【j】,将A【j】和A【i】互换;
  ④:此时,再从i开始向后搜索,i++,找到第一个大于key的A【i】,将A【i】和A【j】互换;
  ⑤:重复第3和4步,知道i=j;

  这个过程称为一趟快速排序。它是一种不稳定的算法。

二:过程演示

  

然后此时i=j那个位置的元素置为key 15,他的位置已经确定了。

然后在对这个位置之前的元素和之后的重复该过程。

三:代码分析

#include<stack>
#include<iostream>
using namespace std;

template<typename T>
int QSF(T arr[],int left,int right)
{
		T key = arr[left];
		while(left < right)
		{
				while(arr[right] >= key && left < right)//当我们的left和right元素相同时可能汇出先死循环问题
				{
						--right;
				}
				arr[left] = arr[right];
				while(arr[left] <= key && left < right)
				{
						++left;
				}
				arr[right] = arr[left];

		}
		if(left == right)
		{
				arr[left] = key;
				return left;
		}
		else
				return -1;
}
template<typename T>
void QuickSortfun(T arr[],int left,int right)
{
		if(left>=right)
				return;

		int index = QSF(arr,left,right);
		if(index == -1)
		{
				cout<<"the index is error:!"<<endl;
				return ;
		}

		QuickSortfun(arr,left,index-1);

		QuickSortfun(arr,index+1,right);

}
template<typename T>
void QuickSort(T arr[],int len)
{
		
		QuickSortfun(arr,0,len-1);//递归实现
}
int main()
{
		int arr[]={12,16,46,89,9,99,49,16,67,34,13,16};
		int len = sizeof(arr)/sizeof(arr[0]);
		QuickSort(arr,len);
 		for(int i=0;i<len;++i)
		{
				cout<<arr[i]<<" ";
		}
		cout<<endl;
		return 0;
}

三:时间复杂度和空间复杂度

  快速排序的平均时间复杂度为O(n*log n),最坏的时间复杂度为O(2^n)。

分析:

  1.最优情况:在最优的情况下,Partion每次都划分的很均匀,如果排序n个关键字,那么递归树的深度就是[log2 n] +1,(每次都是除以2的关系。2^n = x => x =log2 n),每次Partion的循环次数(查找index)为O(n),所以总的时间复杂度为O(n*log2 n)。空间复杂度为O(log2 n)。
  2.最坏情况:当数据是正序或者逆序的时间,每次划分只得到比上一次换分少一个记录的的子序列,所以要划分n-1,也就是要递归n-1次,同时第i此划分,需要经过n-i次的比较才能得到index的位置,所以此时的时间复杂度为O(n^2)。

四:算法稳定性 

  是一种不稳定的排序算法。

五:非递归实现——循环实现

#include<stack>
#include<iostream>
using namespace std;

template<typename T>
int QSF(T arr[],int left,int right)
{
		T key = arr[left];
		while(left < right)
		{
				while(arr[right] >= key && left < right)//当我们的left和right元素相同时可能汇出先死循环问题
				{
						--right;
				}
				arr[left] = arr[right];
				while(arr[left] <= key && left < right)
				{
						++left;
				}
				arr[right] = arr[left];

		}
		if(left == right)
		{
				arr[left] = key;
				return left;
		}
		else
				return -1;
}
template<typename T>
void QuickSortfunnotR(T arr[],int left,int right)
{
		if(left >= right )return;
		stack<int> s;
		s.push(right);//入栈,先入right
		s.push(left);
		int i = 0;
		int j = 0;
		while(!s.empty())
		{
			i = s.top();//出栈先出left
			s.pop();

			j = s.top();
			s.pop();
			int index = QSF(arr,i,j);
			if(j - index > 1)
			{
					s.push(j);
					s.push(index+1);
			}
			if(index - i > 1)
			{
					s.push(index-1);
					s.push(i);
			}
		}


}
template<typename T>
void QuickSort(T arr[],int len)
{
		QuickSortfunnotR(arr,0,len-1);//循环实现
	//	QuickSortfun(arr,0,len-1);//递归实现
}
int main()
{
		int arr[]={12,16,46,89,9,99,49,16,67,34,13,16};
		int len = sizeof(arr)/sizeof(arr[0]);
		QuickSort(arr,len);
 		for(int i=0;i<len;++i)
		{
				cout<<arr[i]<<" ";
		}
		cout<<endl;
		return 0;
}

六:快排的优化

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值