《算法导论》学习总结——第二部分6中位数和顺序统计学

        本章首先提出了中位数的概念,虽然有上和下中位数,简单起见,这里都是下中位数。

        然后我们来看看最大最小值的问题:如果找最大值或最小值,需要n-1次比较,伪代码如下:

MINIMUM(A)
1  min ← A[1]
2  for i ← 2 to length[A]
3         do if min > A[i]
4                then min ← A[i]
5  return min
            而如果同时找出数组中的最大值和最小值,需要多少次比较呢?最简单的方法就是独立的使用n-1次循环,然后分别得到最大值和最小值,这样,总共会比较2n-2次。而事实上,我们只需要最简单的方法就是独立的使用n-1次循环,然后分别得到最小值和最大值,如是这样的,共用了2n-2次比较。而事实上,我们只需要3(n/2)次比较久足够找到了。方法如下:先将一对元素互相进行比较,然后把最小值和当前最小值比较,把较大值和当前最大值进行比较。因此每个元素进行3次比较。如果n为奇数,那么比较次数是3(n/2),如果n为偶数,那比较为3(n/2)-2次。因此,不论n为奇还是偶,比较次数之多是3(n/2)。代码太简单,测试代码就不贴了,用vector进行排序后输出最大最小的验证,可行,比较次数基本符合理论。

       习题9.1-1,查找第二小的元素,可参考:  http://www.cnblogs.com/phishine/articles/1205351.html  。最初没反应过来,第二小必然是跟最小的比较当中,如同锦标赛那种。

       下面是以线性期望时间做选择。

        一般选择问题看起来比找最小值的简单选择问题难,不过两种问题的渐进运行时间都是一样Θ(n),神奇的一米啊!下面进入高级的分治选择算法RANDOM-SELECT,伪代码如下:

RANDOMIZED-SELECT(A, p, r, i)
1  if p = r
2      then return A[p]
3  q ← RANDOMIZED-PARTITION(A, p, r)
4  k ← q - p + 1
5  if i = k          ▹ the pivot value is the answer
6      then return A[q]
7  elseif i < k
8      then return RANDOMIZED-SELECT(A, p, q - 1, i)
9  else return RANDOMIZED-SELECT(A, q + 1, r, i - k)

一个测试程序如下:

//==============================================================  
// Name        : RandomSelect.cpp  
// Author      : xia  
// Copyright   : NUAA  
// Description : RANDOMIZED-SELECT的实现,以期望线性时间做选择  
//==============================================================
#include <iostream>
#include <ctime>
using namespace std;
const int arraysize = 40;

int Partion(int A[],int p ,int r)
{//数组划分
	int x=A[r];
	int i=p-1;
	for (int j=p ; j<r ;j++)
	{
		if ( A[j] <= x )
		{
			i++;
			swap(A[i],A[j]);
		}
	}
	swap(A[i+1],A[r]);
	return i+1;
}
int RandomPartion(int A[],int p ,int r)
{//在A[p]到A[r]中随机划分
	int i= p + rand()%(r-p+1); //i<-RANDOM(p,r)
	swap(A[r],A[i]);
	return Partion(A,p,r);
}
int RandomSelect(int A[],int p,int r,int i)
{//返回数组A[p...r]中第i小的元素
	if (p==r)
		return A[p];
	int q = RandomPartion(A,p,r);
	int k= q-p+1;
	if (i==k)
		return A[q];
	else if (i<k)
		return RandomSelect(A,p,q-1,i);
	else
		return RandomSelect(A,q+1, r ,i -k);
}
int main(int argc ,char *argv[])
{
	int Array[arraysize];
	int i;
	int test;//第几小
	srand(time(NULL));
	for (i=0; i< arraysize ; i++)
	{
		Array[i]=rand()%1000;
		cout << Array[i] << " " ;
		if ((i+1)%10 ==0 )
			cout << endl;
	}
	cout << " 输入想查第几小的数 : " ;
	cin >> test;
	cout << RandomSelect(Array,0,arraysize-1,test) << endl;;
	return 0;
}
       它的递归划分直接引用了快排的随机划分过程,不过和快排不同,快排递归处理2边,它只处理划分的一边。所以快排Θ(nlgn),它是Θ(n)。分治都是高级货!划分之后只需要确定第i小的位于2个子数组中的哪一个就够了,然后继续处理。

      算法的证明没有细看,回头有空详细研究一下,本算法,神奇的一米啊。

      9.3提出个SELECT算法,没有去实现,虽然可以保证划分良好,不过分为n/5组,总感觉太诡异了点,后面是它的证明,没细看。

      对于习题9-1,提出个,已排序的i个最大数问题。描述如下:

     给定一个含n个元素的集合,我们希望能用一个基于比较的算法来找出按顺序排列的i个最大元素。请找出能实现下列每一种方法的、具有最佳的渐进最坏运行时间的算法,并分析各种方法的运行时间(用n和i表示)。

    a)对于输入数排序,并列出i个最大的数。

    b)对输入数建立一个优先级队列,并调用EXTRACT-MAX过程i次。

    c)利用一个顺序统计量算法来找到第i个最大元素,然后划分输入数组,再对i个最大数排序。

    对于a,我们对输入排序,以快排为例,时间为O(nlgn),后面列出那i个,时间复杂度常数了吧

    如果是b,其实以前也有过一个问题,就是1000个数,我需要找出最大的5个并按顺序排列,曾经想到的是堆排序,其实只需要EXTRACT-MAX就可以了,没必要整个的全部排序。那么时间复杂度呢?对有n个元素的集合,建一个最大堆,时间复杂度为Θ(n) ,接着i次EXTRACT-MAX操作,时间复杂度为O(i*lgn),总感觉也可以i*O(lgn),那总的时间复杂度就是O(i*lgn)。(话说,以前还真没想过时间复杂度算上个i这种东东的)

     对于c,用顺序统计算法,找到第i个最大元素,时间复杂度为Θ(n),划分输入数组,时间复杂度为Θ(n),最后对i个最大数排序,时间复杂度Θ(i*lgi) ,总复杂度为Θ(n+i*lgi),高级货啊。

     习题9-2参考http://blog.csdn.net/zhanglei8893/article/details/6293037

     至此,本章,over


      菜鸟goes on ~~~

 

      又发现个好像还不错的博客,存着先,嘿嘿:http://www.cnblogs.com/v-July-v/archive/2011/03/20/2002189.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值