快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C.A.R.Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,将整个排序过程可以递归进行,依次达到整个数据变成有序序列。
一:算法思想
假设要排序的数组是A[0]......A[N-1],首先任意选取一个数据(通常情况下都是选择数组的第一个元素)作为关键数据,然后将所有比它小的数都放在它前面,所有比他大的数都放在后面,这个过程称为一趟快速排序。它是一种不稳定的算法。
一趟快速排序的思想是:
①:设置两个遍历变量,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;
}
六:快排的优化
待更新。