快速排序,从字面意思就可以看出这是一种效率比较高的排序算法,现在对该算法做一下总结:
快速排序是由冒泡排序改进而得的,它的基本思想是:在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。之后对所有的两部分分别重复上述过程,直至每个部分内只有一个记录或为空为止。简单的说,每趟使表的第一个元素放入适当位置,将表一分为二,对子表按递归方法继续这种划分,直至划分的子表长为1或0.
1、挖坑法找基准值
基本思路:
1、寻找pos位,然后将其分为两段数组,然后对这两段数组递归排序;
2、指定一个基数key(三数取中法),定义两个下标begin指向起始位置,end指向最后一个元素的位置。begin寻找比基数(key)大的数字,找到 后将begin的数据赋给end,begin成为一个坑,然后end寻找比基数(key)小的数字,找到将end的数据赋给begin,end成为一个新坑,循环这个过程,直到begin指针与end指针相遇,然后将key的数据返回给那个坑,然后进行递归操作。
int Pation1(int *array, int left, int right)
{
int begin = left;
int end = right;
int key = array[left];
while (begin < end)
{
while (begin < end &&array[end] >= key)
end--;
if (begin < end)
{
array[begin++] = array[end];
}
while (begin < end&&array[begin] < key)
begin++;
if (begin< end)
{
array[end] = array[begin];
end--;
}
}
array[begin] = key;
return begin;
}
2、前后指针法找基准值
基本思路:
定义两个指针:pPre和pCur,pPre指针找比基准值大的数,pCur指针找比基准值小的数,pPre找到后,将pPre和pCur指针所指向的数据交换,当pPre指针遍历完整个数组时,将基数值与pCur指针的后一个位置的数据进行交换,然后以pCur指针的后一个位置作为分界,然后将数组分开,进行递归排序。
代码实现:
int Pation2(int*array, int left, int right)
{
int pCur = left;//找大数
int prev = pCur - 1;//找小数
int key = array[right];
while (pCur <= right)
{
if (array[pCur] <= key&&++prev != pCur)
swap(array[prev], array[pCur]);
pCur++;
}
return prev;
}
3、分而治之法
基本思路:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
代码实现:
int Pation3(int *array, int left, int right)
{
int begin = left;
int end = right;
int key = array[end];
while (begin < end)
{
while (begin < end&&array[begin] <= key)
begin++;
while (begin<end&&array[end]>key)
end--;
if (begin < end)
{
swap(array[begin], array[end]);
begin++;
end--;
}
}
if (begin != right&&array[begin]>array[right])
{
swap(array[begin], array[end]);
return begin;
}
return right;
}
4、整体代码
//递归写法
void QuickSort(int *array, int left,int right)
{
if (left < right)
{
int div = Pation1(array, left, right);
QuickSort(array, left, div-1);
QuickSort(array, div + 1, right);
}
}
//非递归写法
//快排的非递归写法
void QuickSort_O(int *array, int size)
{
int left = 0;
int right = size;
stack<int> s;
s.push(right);
s.push(left);
while (!s.empty())
{
left = s.top();
s.pop();
right = s.top();
s.pop();
if (left < right)
{
int div = Pation3(array, left, right);
//保存右半部分区间
s.push(right);
s.push(div+1);
//保存左半部分区间
s.push(div);
s.push(left);
}
}
}
void show(int*array,int size)
{
for (int i = 0; i < size; i++)
cout << array[i] << " ";
cout << endl;
}
void SortTest()
{
int arr[10] = { 6, 5, 1, 3, 8, 9, 7, 2, 0, 4 };
int sz = sizeof(arr) / sizeof(arr[0]);
QuickSort(arr, 0, sz - 1);
show(arr, sz);
}
int main()
{
SortTest();
system("pause");
return 0;
}
5、快排优化
在选择基准值的时候,我们可能会因为选取的数太大或者太小,造成左右区间不均匀,这样就会影响程序的效率和性能,这时候呢,我们可以采取三数取中法来决定基准值:
代码实现:
int GetKeyIdx(int arr[], int left, int right)
{
int mid = right - ((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;
}
}
6、算法性能分析
时间复杂度:
最优情况:O( nlogn)(即区间分配比较均匀)
最差情况:O( n^2 ) ( 最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序))
平均时间复杂度:O( nlogn)
空间复杂度:
最优的情况下空间复杂度为:O(logn) ,每一次都平分数组的情况
最差的情况下空间复杂度为:O( n ) ,退化为冒泡排序的情况
稳定性:
是不稳定排序
以上就是对快排的简单总结啦,希望对你有帮助。