• 《算法导论》学习总结 — 9.第九章 中位数和顺序统计学


    这一章的内容很简单,基本都是一些概念。

    第i个顺序统计量:在一个由n个元素组成的集合中,第i个顺序统计量(order statistic)是该集合中第i小的元素。

    最小值是第1个顺序统计量(i=1)

    最大值是第n个顺序统计量(i=n)

    中位数:一个中位数(median)是它所在集合的“中点元素”,当n为奇数时,i=(n+1)/2,当n为偶数是,中位数总是出现在1 (下中位数)和2 (上中位数)。

    找最大值/最小值问题,通过比较n-1次可以得出结果。

    MINIMUM(A)
    1  minA[1]
    2  for i ← 2 to length[A]
    3         do if min > A[i]
    4                then minA[i]
    5  return min

    如果要同时找出最大值和最小值,则比较次数最少并不是2*n-2,而是3 ,我们可以将一对元素比较,然后把较大者于max比较,较小者与min比较,这样就只需要3 。

    如果是一般的选择问题,即找出一段序列第i小的数,看起来要比找最大值或最小值要麻烦,其实两种问题的渐进时间都是4 。

    首先看看这个强悍的伪代码:

    RANDOMIZED-SELECT(A, p, r, i)
    1  if p = r
    2      then return A[p]
    3  q ← RANDOMIZED-PARTITION(A, p, r)
    4  kq - 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)

    这个算法利用了随机化的Partition算法,这个实在第七章的随机化快排中讲到:http://www.wutianqi.com/?p=2368,不记得的可以先复习下前面的快排。

    这个随机化的选择算法返回数组A[p..r]中第i小的元素。

    具体实现如下:

    /*
    Author: Tanky Woo
    Blog:   www.WuTianQi.com
    About:  《算法导论》第9章 查找序列第i小的数字
    */
    
    #include 
    #include 
    using namespace std;
    
    int Partition(int *arr, int beg, int end)
    {
    	int sentinel = arr[end];
    	int i = beg-1;
    	for(int j=beg; j<=end-1; ++j)
    	{
    		if(arr[j] <= sentinel)
    		{
    			i++;
    			swap(arr[i], arr[j]);
    		}
    	}
    	swap(arr[i+1], arr[end]);
    
    	return i+1;
    }
    
    int RandomPartition(int *arr, int beg, int end)
    {
    	int i = beg + rand() % (end-beg+1);
    	swap(arr[i], arr[end]);
    	return Partition(arr, beg, end);
    }
    
    int RandomSelect(int *a, int p, int r, int i)
    {
    	if(p == r)
    		return a[p];
    	int q = Partition(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 a[] = {0, 89, 100, 21, 5, 2, 8, 33, 27, 63};
        int num = 9;
        int ith;
    	cout << "序列为: ";
        for(int i=1; i<=num; ++i)
            cout << a[i] << " ";
    	cout << endl;
        ith = RandomSelect(a, 1, num, 2);
    	cout << "序列中第2小的数字是: " << ith << endl;
    	getchar();
    
        return 0;
    }
    

    结果如图:
    5

    在(89, 100, 21, 5, 2, 8, 33, 27, 63)中查找第二小的数字是5. 

    该算法的平均情况性能较好,并且又是随机化的,所有没有哪一种特别的输入会导致最坏情况发生。

  • 相关阅读:
    二叉树
    oracle 查看某session的历史执行sql情况
    mongodb备份与恢复
    MongoDB数据库基本用法
    常见Oracle HINT的用法
    提高Oracle的WHERE语句性能一些原则
    javascript的类、委托、事件
    Swift数据类型简介(二)
    arcgis api 3.x for js 入门开发系列十七在线天地图、百度地图、高德地图(附源码下载)
    arcgis api 4.x for js之图层管理篇
  • 原文地址:https://www.cnblogs.com/downtjs/p/3357937.html
Copyright © 2020-2023  润新知