step by step.
目录
2.9 线性时间选择算法5(中位数的中位数法-寻找支点元素)
一、 分治概念
分治:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。
二、 分治基本思想
👇
三、 分治常见递推方程
👇
原理可看上一篇博客的前面部分有讲到一个方法。
👇
四、 例题分析
2.4 大整数的乘法
请设计一个有效的算法,进行两个n位二进制大整数的乘法运算
XY = ac 2n + (ad+bc) 2n/2 + bd
为了降低时间复杂度,必须减少乘法的次数,即减小子问题个数。
第一个方案:XY = ac 2n + ((a-b)(d-c)+ac+bd) 2n/2 + bd √
第二个方案:XY = ac 2n + ((a+b)(c+d)-ac-bd) 2n/2 + bd
选择第一个方案:仅需做3次n/2位整数的乘法。 ac (a-b)(d-c) bd ,其他为重复计算。
2.8 快速排序
2.8.1 一般快速排序
快速排序步骤——分解;递归求解;合并
template<class Type>
void QuickSort (Type a[], int p, int r)
{
if (p<r) {
int q=Partition(a,p,r);
//对左半段排序
QuickSort (a,p,q-1);
//对右半段排序
QuickSort (a,q+1,r);
}
}
🔺👇🔺
template<class Type>
int Partition (Type a[], int p, int r)
{
int i = p, j = r + 1;
Type x=a[p];
// 将 < x的元素交换到左边区域
// 将 > x的元素交换到右边区域
while (true) {
while (a[++i] <x&&i < r);
while (a[- -j] >x&&j > p);
if (i >= j) break;
Swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j;
}
2.8.1 一般快速排序算法思想与范例详解
👇
{ 6, 7, 5, 2, 5, 8 }
2.8.1 一般快速排序分析
最坏情况👇 (每一次都是边沿数据)
最好情况👇(每一次都刚好是中位数)
2.8.2 改进的快速排序算法1——随机选取q作为x
算法思想👇
template<class Type>
int RandomizedPartition (Type a[], int p, int r)
{
int i = Random(p,r); —————— 随机选取基准元素
Swap(a[i], a[p]); ———————— 把基准元素放置原算法中的开始位
return Partition (a, p, r); ————(原算法把开始位作为基准元素)
}
代码👇
template<class Type>
int RandomizedPartition (Type a[], int p, int r)
{
int i = Random(p,r);
Swap(a[i], a[p]);
return Partition (a, p, r);
}
template<class Type>
int Partition (Type a[], int p, int r)
{
int i = p, j = r + 1;
Type x=a[p];
// 将 < x的元素交换到左边区域
// 将 > x的元素交换到右边区域
while (true) {
while (a[++i] <x&&i < r);
while (a[- -j] >x&&j > p);
if (i >= j) break;
Swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j;
}
template<class Type>
void RamdomizedQuickSort (Type a[], int p, int r)
{
if (p<r) {
int q = RandomizedPartition(a,p,r);
//对左半段排序
QuickSort (a,p,q-1);
//对右半段排序
QuickSort (a,q+1,r);
}
}
2.8.3 改进的快速排序算法2——均衡划分
T(n) = O(nlogn)
2.9 线性时间选择
一般方法👇
(1)排序法
O(nlogn)
(2)堆+部分排序
当k较小,接近线性效率,但堆的空间较大。
O(n+klogn)
(3)堆
总耗时最坏:O(k+(n-k)logk) = O(nlogk),当k较小,接近线性效率,且堆的空间很小(只有k),适合于海量数据查询第k小元素(k<<n)。此方法得益于在堆中,插入、查找等各项操作时间复杂度均为logk。
O(nlogk)
(4)快速选择
template<class Type>
Type RandomizedSelect(Type a[],int p,int r,int k)
{
if (p==r) return a[p];
int i=RandomizedPartition(a,p,r),
j=i-p+1;
if (k<=j)
return RandomizedSelect(a,p,i,k);
else
return RandomizedSelect(a,i+1,r,k-j);
}
template<class Type>
int RandomizedPartition (Type a[], int p, int r)
{
int i = Random(p,r);
Swap(a[i], a[p]);
return Partition (a, p, r);
}
int Partition (Type a[], int p, int r)
{
int i = p, j = r + 1;
Type x=a[p];
// 将 < x的元素交换到左边区域
// 将 > x的元素交换到右边区域
while (true) {
while (a[++i] <x&&i < r);
while (a[- -j] >x&&j > p);
if (i >= j) break;
Swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j;
}
2.9 线性时间选择4(快速选择)-算法思想
👇
平均时间: O(n)
2.9 线性时间选择算法5(中位数的中位数法-寻找支点元素)
最坏时间: O(n)
Type Select(Type a[], int p, int r, int k)
{
if (r-p<75) {
用某个简单排序算法对数组a[p:r]排序;
return a[p+k-1];
};
for ( int i = 0; i<=(r-p-4)/5; i++ )
将a[p+5*i]至a[p+5*i+4]的第3小元素
与a[p+i]交换位置;
//找中位数的中位数,r-p-4即上面所说的n-5
Type x = Select(a, p, p+(r-p-4)/5, (r-p-4)/10);
int i=Partition(a,p,r, x),
j=i-p+1;
if (k<=j) return Select(a,p,i,k);
else return Select(a,i+1,r,k-j);
}