线性时间选择算法

合集下载

线性时间选择

线性时间选择

应用7:线性时间选择(续)
设所有元素互不相同。在这种情况下, 找出的基准x至少比 3(n-5)/10个元 素大,因为在每一组中有2个元素小 于本组的中位数,而n/5个中位数 中又有(n-5)/10个小于基准x。
同理,基准x也至少比3 (n-5)/10个 元素小。而当n≥75时, 3(n-5)/10 ≥n/4,所以按此基准划分所得的2个 子数组的长度都至少缩短1/4。
T
(n)
C2
n
T
(n
C1 / 5)
T
(3n
/
4)
n 75 n 75
根据定理有:
f (n)
பைடு நூலகம்
c2n 1 1
3
20c2n
(n)
54
因此,T(n)=O(n)。
补充:定理
• 定理:令b, d和c1,c2是大于0的常数,则如下递归
方程
• 的解是:
f
(n
)
b f (floor
(c1n))
f
n 1 (floor(c2n))
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); }

算法导论-顺序统计-快速求第i小的元素

算法导论-顺序统计-快速求第i小的元素

算法导论-顺序统计-快速求第i⼩的元素⽬录1、问题的引出-求第i个顺序统计量2、⽅法⼀:以期望线性时间做选择3、⽅法⼆(改进):最坏情况线性时间的选择4、完整测试代码(c++)5、参考资料内容1、问题的引出-求第i个顺序统计量什么是顺序统计量?及中位数概念在⼀个由元素组成的集合⾥,第i个顺序统计量(order statistic)是该集合第i⼩的元素。

例如,最⼩值是第1个顺序统计量(i=1),最⼤值是第n个顺序统计量(i=n)。

⼀个中位数(median)是它所在集合的“中点元素”。

当n为奇数时,中位数是唯⼀的;当n为偶数时,中位数有两个。

问题简单的说就是:求数组中第i⼩的元素。

那么问题来了:如何求⼀个数组⾥第i⼩的元素呢?常规⽅法:可以⾸先进⾏排序,然后取出中位数。

由于排序算法(快排,堆排序,归并排序)效率能做到Θ(nlogn),所以,效率达不到线性;在本⽂中将介绍两种线性的算法,第⼀种期望效率是线性的,第⼆种效率较好,是在最坏情况下能做到线性效率。

见下⾯两个⼩节;2、⽅法⼀:以期望线性时间做选择这是⼀种分治算法:以为模型:随机选取⼀个主元,把数组划分为两部分,A[p...q-1]的元素⽐A[q]⼩,A[q+1...r]的元素⽐A[q]⼤。

与快速排序不同,如果i=q,则A[q]就是要找的第i⼩的元素,返回这个值;如果i < q,则说明第i⼩的元素在A[p...q-1]⾥;如果i > q,则说明第i⼩的元素在A[q+1...r]⾥;然后在上⾯得到的⾼区间或者低区间⾥进⾏递归求取,直到找到第i⼩的元素。

下⾯是在A[p...q]中找到第i⼩元素的伪码:1 RandomSelect(A,p, q,k)//随机选择统计,以期望线性时间做选择2 {3if (p==q) return A[p];4int pivot=Random_Partition(A,p,q);//随机选择主元,把数组进⾏划分为两部分5int i=pivot-p+1;6if (i==k )return A[pivot];7else if (i<k) return RandomSelect(A,pivot+1,q,k-i);//第k⼩的数不在主元左边,则在右边递归选择8else return RandomSelect(A,p,pivot-1,k);//第k⼩的数不在主元右边,则在左边递归选择9 }在最坏情况下,数组被划分为n-1和0两部分,⽽第i个元素总是落在n-1的那部分⾥,运⾏时间为Ө(n^2);但是,除了上述很⼩的概率情况,其他情况都能达到线性;在平均情况下,任何顺序统计量都可以在线性时间Θ(n)内得到。

线性时间选择中位数

线性时间选择中位数

湖南涉外经济学院计算机科学与技术专业《算法设计与分析》课程线性时间选择(中位数)实验报告班级:学号:姓名:教师:成绩:2012年5月【实验目的】1 掌握线性时间选择的基本算法及其应用2 利用线性时间选择算法找出数组的第k小的数3 分析实验结果,总结算法的时间和空间复杂度【系统环境】Windows7 旗舰版平台【实验工具】VC++6.0英文企业版【问题描述】描述:随机生成一个长度为n的数组。

数组为随机生成,k由用户输入。

在随机生成的自然数数组元素找出这n个数的第k小的元素。

例:A[5]={3,20,50,10,21} k=3,则在数组A中第3小的元素为20【实验原理】原理:将所有的数(n个),以每5个划分为一组,共[n/5]组(将不足五个的那组忽略);然后用任意一种排序算法(因为只对五个数进行排序,所以任取一种排序法就可以了,这里我选用冒泡排序),将每组中的元素排好序再分别取每组的中位数,得到[n/5]个中位数;再取这[n/5]个中位数的中位数(如果n/5是偶数,就找它的2个中位数中较大的一个)作为划分基准,将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。

在这种情况下,找出的基准x至少比3(n-5)/10个元素大,因为在每一组中有2个元素小于本组的中位数,中位数处于1/2*[n/5-1],即n/5 个中位数中又有(n-5)/10个小于基准x。

同理,基准x也至少比3(n-5)/10个元素小。

而当n≥75时,3(n-5)/10≥n/4所以按此基准划分所得的2个子数组的长度都至少缩短1/4。

思路:如果能在线性时间内找到一个划分基准,使得按这个基准所划分出的2个子数组的长度都至少为原数组长度的ε倍(0<ε<1是某个正常数),那么就可以在最坏情况下用O(n)时间完成选择任务。

例如:若ε=9/10,算法递归调用所产生的子数组的长度至少缩短1/10。

所以,在最坏情况下,算法所需的计算时间T(n)满足递归式T(n)≤T(9n/10)+O(n) 。

线性时间选择算法实现

线性时间选择算法实现
void swap(int *a,int *b);
//主函数
int main()
{
int *a,cnt,i,k,result;
FILE *fp;
//clrscr();
printf("Input the count of elements:");
scanf("%d",&cnt);
printf("Choose the element :");
{
int i=p,j=r+1;
while(1)
{
while(a[++i]<x&&i<r);
while(a[--j]>x);
if(i>=j)
break;
swap(&a[i],&a[j]);
}
a[p]=a[j];
a[j]=x;
return j;
}
void sort(int *a,int p,int r)
}
for(i=0;i<cnt;i++)
{
a[i]=rand()%cnt+100;
fprintf(fp,"%4d\n",a[i]);
}
result=select(a,0,cnt-1,k);
printf("The result is:%d",result);
fclose(fp);
free(a);
return 0;
if(k<=j) //比较k和j来确定在数组哪一部分继续选择
return select(a,p,i,k);
else

算法设计与分析课件--分治法-线性时间选择

算法设计与分析课件--分治法-线性时间选择
9
2.5 线性时间选择
这样找到的m*划分是否能达到O(n)的时间复杂度? |A| = |D| = 2r, |B| = |C| = 3r +2,n = 10r +5. |A| + |D| + |C| = 7r + 2 = 7(n-5)/10 +2 = 7n/10 -1.5 < 7n/10 表明子问题的规模不超过原问题的7/10(d)。
T(n) = T(cn) + T(dn) + tn
6
2.5 线性时间选择
Select(S, k) Input: n个数的数组S,正整数k
T(n) = T(cn) + T(dn) + tn
Output: S中的第k个小元素
1. 将S划分成5个元素一组,共[n/5]个组;
2. 每组寻找一个中位数,把这些中位数放到集合M中;
寻找一个分割点m*, 使得左边子表S1中的元素都小于m*, 右子表 S2中的元素都大于m*。 如果寻找m*的时间复杂度达到O(nlogn), 那就不如直接使用排序 算法了。 如果直接寻找m*, 时间复杂度是O(n). 假设选择算法的时间复杂度为T(n), 递归调用这个算法在S的一 个真子集M上寻找m*,应该使用T(cn)时间,这里c是小于1的常数, 反映了M的规模与S相比缩小许多。
✓ 不妨假设n是5的倍数,且n/5是奇数,即n/5 = 2r+1. 于是: |A| = |D| = 2r, |B| = |C| = 3r +2,n = 10r +5.
✓ 如果A和D中的元素都小于m*,那么把它们的元素都加入到S1, S1对应规约后子问题的上限。 类似的,若A和D中的元素都 大于m*, 则把他们的元素都加 入到S2,S2对应规约后子问题 的上限。

快速选择算法线性时间选择第k小的元素

快速选择算法线性时间选择第k小的元素

快速选择算法线性时间选择第k小的元素快速选择算法:线性时间选择第k小的元素快速选择算法是一种高效的算法,用于在未排序的数组中选择第k 小的元素。

该算法的时间复杂度为O(n),在大规模数据处理和排序任务中具有广泛的应用。

1. 算法原理快速选择算法基于快速排序算法的分治思想,通过每次选择一个枢纽元素,并将数组中的元素分为左右两部分,来实现快速查找排序后的第k小元素。

具体步骤如下:- 选择枢纽元素:从未排序数组中选择一个元素作为枢纽元素,可以随机选择或选择固定位置的元素,比如选取数组的第一个元素。

- 划分数组:将数组分为两部分,左边的元素小于枢纽元素,右边的元素大于等于枢纽元素。

- 判断位置:比较枢纽元素的位置与k的大小关系,如果位置小于k,则递归在右半部分查找第k小元素;如果位置大于k,则递归在左半部分查找第k小元素;否则,返回该位置的元素即为第k小元素。

2. 算法步骤下面给出一种实现快速选择算法的伪代码:```function quickSelect(A, k, left, right):if left == right:return A[left]pivotIndex = partition(A, left, right)if k == pivotIndex:return A[k]else if k < pivotIndex:return quickSelect(A, k, left, pivotIndex - 1) else:return quickSelect(A, k, pivotIndex + 1, right) function partition(A, left, right):pivot = A[left]i = left + 1j = rightwhile i <= j:if A[i] < pivot and A[j] > pivot:swap A[i] and A[j]i = i + 1j = j - 1if A[i] >= pivot:i = i + 1if A[j] <= pivot:j = j - 1swap A[left] and A[j]return j```3. 算法性能分析快速选择算法通过每次划分数组来减小搜索范围,因此平均时间复杂度为O(n),其中n为数组的长度。

线性时间的排序算法

线性时间的排序算法

线性时间的排序算法前⾯已经介绍了⼏种排序算法,像插⼊排序(直接插⼊排序,折半插⼊排序,希尔排序)、交换排序(冒泡排序,快速排序)、选择排序(简单选择排序,堆排序)、2-路归并排序(见我的另⼀篇⽂章:)等,这些排序算法都有⼀个共同的特点,就是基于⽐较。

本⽂将介绍三种⾮⽐较的排序算法:计数排序,基数排序,桶排序。

它们将突破⽐较排序的Ω(nlgn)下界,以线性时间运⾏。

⼀、⽐较排序算法的时间下界所谓的⽐较排序是指通过⽐较来决定元素间的相对次序。

“定理:对于含n个元素的⼀个输⼊序列,任何⽐较排序算法在最坏情况下,都需要做Ω(nlgn)次⽐较。

”也就是说,⽐较排序算法的运⾏速度不会快于nlgn,这就是基于⽐较的排序算法的时间下界。

通过决策树(Decision-Tree)可以证明这个定理,关于决策树的定义以及证明过程在这⾥就不赘述了。

你可以⾃⼰去查找资料,推荐观看《》。

根据上⾯的定理,我们知道任何⽐较排序算法的运⾏时间不会快于nlgn。

那么我们是否可以突破这个限制呢?当然可以,接下来我们将介绍三种线性时间的排序算法,它们都不是通过⽐较来排序的,因此,下界Ω(nlgn)对它们不适⽤。

⼆、计数排序(Counting Sort)计数排序的基本思想就是对每⼀个输⼊元素x,确定⼩于x的元素的个数,这样就可以把x直接放在它在最终输出数组的位置上,例如:算法的步骤⼤致如下:找出待排序的数组中最⼤和最⼩的元素统计数组中每个值为i的元素出现的次数,存⼊数组C的第i项对所有的计数累加(从C中的第⼀个元素开始,每⼀项和前⼀项相加)反向填充⽬标数组:将每个元素i放在新数组的第C(i)项,每放⼀个元素就将C(i)减去1C++代码:/*************************************************************************> File Name: CountingSort.cpp> Author: SongLee> E-mail: lisong.shine@> Created Time: 2014年06⽉11⽇星期三 00时08分55秒> Personal Blog: http://songlee24.github.io************************************************************************/#include<iostream>using namespace std;/**计数排序:A和B为待排和⽬标数组,k为数组中最⼤值,len为数组长度*/void CountingSort(int A[], int B[], int k, int len){int C[k+1];for(int i=0; i<k+1; ++i)C[i] = 0;for(int i=0; i<len; ++i)C[A[i]] += 1;for(int i=1; i<k+1; ++i)C[i] = C[i] + C[i-1];for(int i=len-1; i>=0; --i){B[C[A[i]]-1] = A[i];C[A[i]] -= 1;}}/* 输出数组 */void print(int arr[], int len){for(int i=0; i<len; ++i)cout << arr[i] << " ";cout << endl;}/* 测试 */int main(){int origin[8] = {4,5,3,0,2,1,15,6};int result[8];print(origin, 8);CountingSort(origin, result, 15, 8);print(result, 8);return 0;}当输⼊的元素是0到k之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k)。

算法导论 第八章 线性时间排序

算法导论 第八章 线性时间排序

Decision-tree example
• Sort <a1,a2, a3>=<9,4,6>
1:2
• A decision tree can model the execution of any comparison sort: --One tree for each input size n. --View the algorithm as splitting whenever it compares two elements. -- The tree contains the comparisons along all possible instruction traces. --The running time of the algorithm = the length of the path taken. -- Worst-case running time = height of tree.
Decision-tree example
• Sort <a1,a2, a3>=<9,4,6>
1:2
2:3
1:3
123
1:3
213
2:3 4≤6
132
312
231
321
• Each internal node is labelled i:j for i,j∈{1,2,…,n} --The left subtree shows subsequent comparisons if ai≤aj --The right subtree show subsequent comparisons if ai>aj
A: B:
4 1
1 2
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

福州大学数学与计算机科学学院
《计算机算法设计与分析》上机实验报告(1)
图中箭头指向表示大的数值指向小的数值,所以根据图
可以看出,在x的右边,每一个包含5个元素的组中至少有3
个元素大于x,在x的左边,每一组中至少有3个元素小于x (保证x分割一边必定有元素存在)。

图中显示的中位数的中位数x的位置,每次选取x作为划
分的好处是能够保证必定有一部分在x的一边。

所以算法最坏
情况的递归公式可以写成:
,使用替换法可以得出)
(。

T
n
cn
4、算法代码:
#include <iostream>
#include <ctime>
using namespace std;
template <class Type>
void Swap(Type &x,Type &y);
inline int Random(int x, int y);
template <class Type>
int Partition(Type a[],int p,int r);
template<class Type>
int RandomizedPartition(Type a[],int p,int r);
template <class Type>
Type RandomizedSelect(Type a[],int p,int r,int k);
int main()
{
void SelectionSort(int a[]);
int s;
int a[2000];
int b[2000];
for(int i=0; i<2000; i++)
{
a[i]=b[i]=rand()%10000;
cout<<a[i]<<" ";
}
cout<<endl;
SelectionSort(b);
for(int j=0;j<2000;j++)
{
printf("a[%d]:%d ",j+1,b[j]);
}
cout<<endl;
printf("请输入要求的第几最小数:");
scanf("%d",&s);
cout<<RandomizedSelect(a,0,1999,s)<<endl; }
template <class Type>
void Swap(Type &x,Type &y)
{
Type temp = x;
x = y;
y = temp;
}
inline int Random(int x, int y)
{
srand((unsigned)time(0));
int ran_num = rand() % (y - x) + x;
return ran_num;
}
template <class Type>
int Partition(Type a[],int p,int r)
{
int i = p,j = r + 1;
Type x = a[p];
while(true)
{
while(a[++i]<x && i<r);
while(a[--j]>x);
if(i>=j)
{
break;
}
Swap(a[i],a[j]);
}
a[p] = a[j];
a[j] = x;
return 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);
}
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);
int j = i - p + 1;
if(k <= j)
{
return RandomizedSelect(a,p,i,k);
}
else
{
//由于已知道子数组a[p:i]中的元素均小于要
找的第k小元素
//因此,要找的a[p:r]中第k小元素是a[i+1:r]
中第k-j小元素。

return RandomizedSelect(a,i+1,r,k-j);
}
}
void SelectionSort(int a[])
{
int min;
for (int i = 0; i < 2000 - 1; i++)
{
min = i;
for (int j = i + 1; j < 2000; j++)
{
if (a[j] < a[min])
min = j;
}
int t = a[min];
a[min] = a[i];
a[i] = t;
}
return ;
}
实验结果截图:
实验结果。

相关文档
最新文档