目录
1.快速排序的原理
快速排序算法是基于分治策略的一个排序算法。其基本思想是,对于输入的子数组nums[left:right]按下3个步骤进行排序:
(1)分解(divide) :以nums[left]为基准元素将nums[left:right]划分成3段nums[left: mid-1],nums[mid]和nums[mid+1:right],使得nums[left:mid-1]中任何元素小于等于nums[mid], nums[mid+1:right]中任何元素大于等于nums[right]。下标mid在划分过程中确定。
(2)递归求解(conquer) :通过递归调用快速排序算法,分别对nums[left:mid-1]和nums[mid+1:right]进行排序。
(3)合并(merge):由于对nums[left:mid-1]和nums[mid+1:right]的排序是就地进行的,所以在nums[left:mid-1]和nums[mid+1:right]都已排好的序后不需要执行任何计算,nums[left:right]就已排好序。
2.划分过程
3.划分函数的实现
代码:
int Partition(int* nums, int left, int right)
{
int i = left, j = right;
int tmp = nums[i];
while (i < j)
{
while (i<j && nums[j]>tmp) --j;
if (i < j)nums[i] = nums[j];
while (i < j && nums[i] <= tmp) ++i;
if (i < j)nums[j] = nums[i];
}
nums[i] = tmp;
return i;
}
事实上,算法Partition的主要功能就是将小于tmp的元素放到数组的左半部分。而将大于tmp的元素放在数组的右半部分。其中有一些细节需要注意。算法中的下标i和j不会超出nums[left:right]的下标届。while循环中的“i<j”就是防止越界。
代码实现:
void PrintInt(const int* nums, int n)
{
for (int i = 0; i < n; i++)
{
cout << nums[i] << " ";
}
cout << endl;
}
int Partition(int* nums, int left, int right)
{
int i = left, j = right;
int tmp = nums[i];
while (i < j)
{
while (i<j && nums[j]>tmp) --j;
if (i < j)nums[i] = nums[j];
while (i < j && nums[i] <= tmp) ++i;
if (i < j)nums[j] = nums[i];
}
nums[i] = tmp;
return i;
}
void QuickSort(int* nums, int left, int right)
{
if (left < right)
{
int mid = Partition(nums, left, right);
QuickSort(nums, left, mid - 1);
QuickSort(nums, mid + 1, right);
}
}
int main()
{
int arr[] = { 56,23,78,45,90,89,12,34,67,89,100 };
int n = sizeof(arr) / sizeof(arr[0]);
PrintInt(arr, n);
QuickSort(arr, 0, n - 1);
PrintInt(arr, n);
return 0;
}
4.快速排序的退化
当数组有序:
{12,23,34,45,56,67,78,89,90,100}
{100, 90, 89, 78, 67, 56, 45, 34, 23, 12}
分析:
快速排序的运行时间与划分是否对称有关,其最坏情况发生在划分过程产生的两个区域分别包含n-1个元素和1个元素的时候。由于算法Partition的计算时间为O(n),如果算法Partition的每一步都出现这种不对称划分:
在最好情况下,每次划分所取的基准都恰好为中值,即每次划分都产生两个大小为n/2的区域:
5.随机选择策略
快速排序算法的性能取决于划分的对称性。通过修改算法 partition,可以设计出采用随机选择策略的快速排序算法。在快速排序算法的每一步中,当数组还没有被划分时,可以在nums[left:right]中随机选出一个元素作为划分基准,这样可以使划分基准的选择是随机的,从而可以期望划分是比较对称的。
随机化的划分算法代码实现:
int RandomPartition(int* nums, int left, int right)
{
srand(time(nullptr));
int rapos = (rand() % (right - left + 1)) + left;
std::swap(nums[left], nums[rapos]);
return Partition(nums, left, right);
}
代码实现:
void PrintInt(const int* nums, int n)
{
for (int i = 0; i < n; i++)
{
cout << nums[i] << " ";
}
cout << endl;
}
int Partition(int* nums, int left, int right)
{
int i = left, j = right;
int tmp = nums[i];
while (i < j)
{
while (i<j && nums[j]>tmp) --j;
if (i < j)nums[i] = nums[j];
while (i < j && nums[i] <= tmp) ++i;
if (i < j)nums[j] = nums[i];
}
nums[i] = tmp;
return i;
}
int RandomPartition(int* nums, int left, int right)
{
srand(time(nullptr));
int rapos = (rand() % (right - left + 1)) + left;
std::swap(nums[left], nums[rapos]);
return Partition(nums, left, right);
}
void QuickSort(int* nums, int left, int right)
{
if (left < right)
{
int mid = RandomPartition(nums, left, right);
QuickSort(nums, left, mid - 1);
QuickSort(nums, mid + 1, right);
}
}
int main()
{
int arr[] = { 56,23,78,45,90,89,12,34,67,89,100 };
int n = sizeof(arr) / sizeof(arr[0]);
PrintInt(arr, n);
QuickSort(arr, 0, n - 1);
PrintInt(arr, n);
return 0;
}
6.用队列实现快排
void QuickSort1(int* nums, int left, int right)//队列实现
{
std::queue<int>qu;
qu.push(left);
qu.push(right);
while (!qu.empty())
{
int sleft = qu.front();
qu.pop();
int sright = qu.front();
qu.pop();
int mid = Partition(nums, sleft, sright);
if (sleft < sright)
{
qu.push(sleft);
qu.push(mid - 1);
}
if (mid + 1 < sright)
{
qu.push(mid + 1);
qu.push(sright);
}
}
}