算法的概念:
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述:
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
算法动态图:
算法排序流程:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
算法分析:
最佳情况:T(n) = O(nlogn)
最差情况:T(n) = O(n2)
平均情况:T(n) = O(nlogn)
代码实现:
百度中:
void sort(int *a, int left, int right)
{
if(left >= right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
{
return ;
}
int i = left;
int j = right;
int key = a[left];
while(i < j) /*控制在当组内寻找一遍*/
{
while(i < j && key <= a[j])
/*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升
序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/
{
j--;/*向前寻找*/
}
a[i] = a[j];
/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
a[left],那么就是给key)*/
while(i < j && key >= a[i])
/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
{
i++;
}
a[j] = a[i];
}
a[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/
sort(a, left, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
sort(a, i + 1, right);/*用同样的方式对分出来的右边的小组进行同上的做法*/
/*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}
递归:
void Qsort(int arr[], int low, int high)
{
int temp = arr[low];
while(low < high)
{
while((low<high)&&arr[high] >= temp))
{
high--;
}
if(low == high)
{
break;
}
else
{
arr[low] = arr[high];
}
while((low<high)&& (arr[low]<=temp))
{
low++;
}
if(low == high)
{
break;
}
else
{
arr[high] = arr[low];
}
}
arr[low] = temp;
return low;
}
static void Quick(int*arr,int low, int high)
{
int par = Qsort(arr,low,high);
if(low+1 < par)
{
Quick(arr,low,par-1);
}
if(par<high-1)
{
Quick(arr,par+1,high);
}
}
void QuickSort(int *arr,int len)
{
Quick(arr,0,len-1);
}
int main()
{
int arr[] = {9,3,5,7,78,14,25,26,47,21};
QuickSort(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
非递归:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
//划分
static int partition(int *arr ,int low ,int high)
{
int tmp = arr[low];//基准
while(low<high)
{
//右边大的开始
while(low < high && arr[high] >= tmp)
{
high--;
}
if(low == high)
{
break;
}
else
{
arr[low] = arr[high];
}
while(low < high && arr[low] <= tmp)
{
low++;
}
if(low == high)
{
break;
}
else
{
arr[high] = arr[low];
}
}
arr[low] = tmp;
return low;
}
void QuickSort(int *arr ,int len)
{
int size = (int)(log10((double)len)/log10((double)2))+1;
int *stack = (int *)malloc(size*2*sizeof(int));
assert(stack != NULL);
int top = 0;//栈顶指针,当前可以存放数据的下标
int low = 0;
int high = len-1;
int par = partition(arr ,low,high);
if(low+1 < par)
{
stack[top++] = low;
stack[top++] = par-1;
}
if(par< high-1)
{
stack[top++] = par+1;
stack[top++] = high;
}
while(top > 0)
{
high = stack[--top];
low = stack[--top];
par = partition(arr,low,high);
if(low+1 < par)
{
stack[top++] = low;
stack[top++] = par-1;
}
if(par< high-1)
{
stack[top++] = par+1;
stack[top++] = high;
}
}
free(stack);
}
void Show(int *arr ,int len)
{
for(int i = 0 ;i<len;i++)
{
printf("%d",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {1,5,89,24,65,21,34,56,2,58};
QuickSort(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}