首先快速排序有三种方式下面我来一一介绍
1.最基本的方式,基准值法
算法描述:取第一个或最后一个元素为基准值(我在这里取第一个元素),然后定义两个标记left和right分别指向数组的起始位置和最后一个位置,然后right从后往前走找到小于基准值的时候停下来,left开始往后走,找到大于基准值的元素的停下来,然后交换arr[left]和array[right]的值,重复上述步骤直到left>=right然后将基准值和当前停下来的位置交换,这个时候数组就以基准值为基础被分为两部分,如果基准值左边的元素全部小于基准值,基准右边的元素全部大于基准值。然后递归处理每个组就可以了。
下面给出算法代码:
int postion(int *array, int left, int right)
{
int key = left;//要更换当前位置上面的值,所以只能取下标,如果取array[left]的话则left位置的元素无法更换
while (left < right)
{
while (left<right&&array[key]<=array[right])//这里要取到等号
{
--right;
}
while (left<right&&array[key]>=array[left])
{
++left;
}
if (left<right)//会有相遇的时候这个时候不交换避免重复交换
swap(array[left], array[right]);
}
swap(array[key], array[left]);
return left;
}
void QuickSort(int *arr, int left, int right)//这里的right不会变得
{
if (left < right)
{
int n = postion(arr, left, right);
QuickSort(arr, left, n - 1);//key之前的分组
QuickSort(arr, n + 1, right);//key之后的分组
}
}
注意取等号和让key取下标!这是必须的!
方法2:挖坑法
算法描述:这个也是在基准值得基础上演变的,首先取首元素为基准值(尾元素也可以),让key=array[0],这个时候相当于第一个元素被挖走了,这里就成了一个坑,然后此时right从后往前找比key小的元素就填到array[0]的位置这个时候array[0]的这个坑被填了,那么array[right]这里又是一个坑了,所以再让left从前往后找比key大的元素(注意这里只能是大或者小不能取等于),然后将array[right]的坑填了,然后让right继续从后面找填上一个坑,依此类推,直到left==right此时此处必定为一个坑,然后将key值填进去就好了,这个时候数组也被分成了两组和上述情况一样,然后递归调用就可以了。
下面给出算法代码
int postion(int *array, int left, int right)
{
int key = array[left];//因为最后是用值来替换所以就记录他的下标就可以了
while (left<right)
{
while(left<right&&array[right] >= key)
{
--right;
}
if (left < right)
array[left] = array[right];
while (left<right&&array[left] <= key)
{
left++;
}
if (left < right)
array[right] = array[left];
}
array[left] = key;
return left;
}
void QuickSort(int *array, int left, int right)
{
if (left < right)
{
int n = postion(array, left, right);
QuickSort(array, left, n - 1);
QuickSort(array, n + 1, right);
}
}
方法3:双指针法
算法描述:同样取最后一个元素为基准值,然后定义两个指针(指向下标的所以这里说得是指针),fast指向left,slow指向left-1,然后fast开始走,找到比array[right]小的元素则slow开始走,当slow走完以后判断fast是否等于slow,如果不等于交换arr[slow]和arr[fast],相等的话不交换,然后fast继续走,如果所指的数都大于arr[right]则slow不动,当fast==right的时候循环结束,此时slow++然后交换arr[slow]和arr[right],此时数组也被分成了两组,同上进行递归调用
算法代码如下:
int postion(int *array, int left, int right)
{
Keydata(array, left, right);
int fast = left;//先走
int slow = left - 1;//后走
while (fast<right)
{
if (array[fast] < array[right])
{
++slow;
if (slow != fast)
swap(array[slow], array[fast]);
}
fast++;
}
++slow;
swap(array[slow], array[right]);
return slow;
}
void QuickSort(int *arr, int left, int right)
{
if (left < right)
{
int n = postion(arr, left, right);
QuickSort(arr, left, n - 1);
QuickSort(arr, n+1, right);
}
}
对于快排的优化,这里我只说一个其余的感兴趣自己查阅相关资料,就是三数取中间值得方法,即其数组首尾和中间元素的值,找出三个中中间大小的值作为基准值,这样效率会比较高,下面给出找中间值得代码
void KeyMiddata(int *array, int left,int right)//优化取三个元素的中间值的元素
{
int mid = (right - left) / 2 + left;
if (array[mid] > array[left] && array[mid] < array[right])
{
swap(array[mid], array[right]);
return;
}
if (array[left]>array[mid] && array[left] < array[right])
{
swap(array[left], array[right]);
return;
}
if (array[right]>array[mid] && array[right] < array[left])
return;
}
优化后的快排
void KeyMiddata(int *array, int left,int right)//优化取三个元素的中间值的元素
{
int mid = (right - left) / 2 + left;
if (array[mid] > array[left] && array[mid] < array[right])
{
swap(array[mid], array[right]);
return;
}
if (array[left]>array[mid] && array[left] < array[right])
{
swap(array[left], array[right]);
return;
}
if (array[right]>array[mid] && array[right] < array[left])
return;
}
int postion(int *array, int left, int right)
{
KeyMiddata(array, left, right);
int fast = left;//先走
int slow = left - 1;//后走
while (fast<right)
{
if (array[fast] < array[right])
{
++slow;
if (slow != fast)
swap(array[slow], array[fast]);
}
fast++;
}
++slow;
swap(array[slow], array[right]);
return slow;
}
void QuickSort(int *arr, int left, int right)
{
if (left < right)
{
int n = postion(arr, left, right);
QuickSort(arr, left, n - 1);
QuickSort(arr, n+1, right);
}
}
最后实现以下双指针的非递归版本,借助栈来控制每个分组代码如下:
void QuickSort(int *array, int left, int right)
{
stack<int> s;
s.push(right);
s.push(left);
while (!s.empty())
{
int begin=s.top();
s.pop();
int end = s.top();
s.pop();
int n = postion(array, begin, end);
if (begin < n - 1)
{
s.push(n - 1);
s.push(begin);
}
if (end>n + 1)
{
s.push(end);
s.push(n+1);
}
}
}
最后给出测试代码和测试结果:
void test()
{
int array[] = { 4,2,6,4,9,5,3,2,1,0};
int size = sizeof(array) / sizeof(*array);
QuickSort(array, 0, size - 1);
for (int i = 0; i<size; i++)
cout << array[i] << " ";
}
测试结果