顺序统计量(选择问题)

定义

在一个由n个元素组成的集合中,第i个顺序统计量是该集合中第i小的元素,例如,在一个元素集合中,最小值是第一个顺序统计量(i = 1),最大值是第n个顺序统计量(i = n)。

查找最小值

在一个有n个元素的集合中,需要做多少次比较才能确定其最小元素呢?一个简单的思路就是:依次遍历集合中的每个元素,并记录当前最小的元素,在下面的排序中,假设该集合元素存放在数组A中,且A.length = n。

MINIMUM(A)

min = A[1]

for i = 2 to A.length

if min < A[i]

min = A[i]

return min

当然,最大值也可以进行n-1次比较找出来

同时找到最大最小值

最简单的方法就是分别独立地找出最大值和最小值,这各需要n-1次比较,共需要2n – 2次比较,事实上,只需要最多3*floor(n/2)(floor()函数是向下取整的意思)次比较就可以同时找出最大最小值。具体方法是记录已知的最大最小值,但并不是将每一个输入元素与当前的最小值和最大值进行比较—这样做的代价是每个元素都需要2次比较,而是对输入元素成对地进行处理,首先,将一对输入元素相互进行比较,然后把较小的元素与当前最小值进行比较,把较大的值与当前最大值进行比较,这样,两个元素一共需要3次比较。

如何设定已知的最大值和最小值依赖于n是奇数还是偶数,如果n是奇数,就将最小值和最大值的初值设置为第一个元素的值,然后成对地处理余下的元素。如果n是偶数,就对前两个元素做一次比较,以决定最小值和最大值的初值,然后与n是奇数的情况一样,成对地处理余下的元素。

如果n是奇数,那么共进行3*(n-1)/2次比较,如果n是偶数,则先进行一次初始比较,然后进行3(n-2)/2次比较,共进行3n/2-2次比较,因此,不管哪一种情况,总的比较次数至多是3*floor(n/2)次。

期望为线性时间的选择算法

一般选择问题看起来要比找出最小值这样的问题更难,但是,这两个问题的渐近运行时间却是相同的:θ(n)。下面是一种解决选择问题的分治算法,与快速排序一样,将输入数组进行递归划分,但与快速排序算法不同的是,快速排序会递归处理划分的两边,而RANDOMIZED_SELECT只处理划分的一边,快速排序的期望运行时间为θ(nlgn),而RANDOMIZED_SELECT的期望运行时间为θ(n),这里,假设输入数据都是互异的。

伪代码

//i是要选择的第几个最大值,k则是通过分区后得到该主元为第几个最大值

RANDOMIZED_SELECT(A, p, r, i)

if p == r

return A[p]

q = RANDOMIZED_PARTITION(A, p, r);

k = q - p + 1

if k == i

return A[q]

else if i < k

return RANDOMINZE_SELECT(A, p, q-1, i)

else

return RANDOMIZED_SELECT(A, q+1, r, i - k)

性能分析

RANDOMIZED_SELECT的最坏情况运行时间为θ(n2),即使是找最小元素也是如此,因为在每次划分时可能极不走远地总是按余下元素中最大的进行划分,而划分操作需要θ(n)时间,但是该算法是随机划分的,所以不存在一个特定的会导致出现最坏情况的输入数据。

该算法的期望运行时间为θ(n),具体证明参考《算法导论》P121

C语言代码实现

#include<stdio.h>

#include<stdlib.h>

#include<time.h>

void randomized_select(int *array, int begin, int end, int position);

int randomized_partion(int *array, int begin, int end);

int partion(int *array, int begin, int end);

void swap(int *array, int p, int q);

void quicksort(int *array, int begin, int end);

main(){

         int array[]={23,3,35,5,7,28,34,45,73,21,9,33,64};

         int i, k;

         printf("排序前的数组:\n");

         for (i = 0; i < 13; i++)

                   printf("%d\t",array[i]);

         putchar(‘\n‘);   

        putchar(‘\n‘);

        quicksort(array, 0, 11);

        printf("排好序的数组:\n");

         for (i = 0; i < 13; i++)

                   printf("%d\t",array[i]);

         for(k = 1; k <= 13; k++){

                   putchar(‘\n‘);   

                   printf("\n由小到大排序,排在第%d位的数为: ",k);

                   randomized_select(array, 0, 12, k);

         }       

         putchar(‘\n‘);

}

void swap(int *array, int p, int q){

         int temp;

         temp = array[p];

         array[p] = array[q];

         array[q] = temp;

}

int randomized_partion(int *array, int begin, int end){

         //temp是一个随机数,用来选择主元的位置

         int piviot_position, temp;

         srand((unsigned int) time(NULL));//srand函数用参数值对随机数发生器进行初始化,此处使用当天的当前时间作为随机数产生器的种子

         temp = rand() % (end - begin );

         piviot_position = temp + begin;

         swap(array, begin, piviot_position);

         return partion(array, begin, end);

}

int partion(int *array, int begin, int end){

         //选择第一个元素作为主元

         int piviot;

         int last, ptr;

         piviot = array[begin];        

         for (last = begin, ptr = begin + 1; ptr <= end; ptr++){

                   if (array[ptr] <= piviot){

                            swap(array, ++last, ptr);

                   }

         }

         swap(array, last, begin);

         return last;

}

void randomized_select(int *array, int begin, int end, int position){

         //number的值就是主元在排好序的数组中的位置

         int piviot_position;

         int number;

         if (begin == end){

                   printf("%d\n", array[begin]);

                   return;

         }

         piviot_position = randomized_partion(array, begin, end);

         number = piviot_position - begin + 1;

         if (number == position)

                   printf("%d\n", array[piviot_position]);      

         else if (position < number)

                   randomized_select(array, begin, piviot_position-1, position);

         else

                   randomized_select(array, piviot_position+1, end, position - number);

}

void quicksort(int *array, int begin, int end){

         int medium;

         if (begin < end){

                   medium = partion(array, begin, end);

                   quicksort(array, begin, medium-1);

                   quicksort(array, medium+1, end);

         }

}

顺序统计量(选择问题)

时间: 2024-10-28 15:32:33

顺序统计量(选择问题)的相关文章

算法导论之所有排序算法的Python实现

最近一段时间学习了算法导论第二版书的第一部分和第二部分的内容,自己编写了其中排序相关的几乎全部算法,包括冒泡排序(bubble sort).选择排序( selection sort).插入排序(insertion sort).希尔排序(shell sort).归并排序(merge sort).快速排序(quick sort).计数排序(count sort).基数排序(radix sort).桶排序(bucket sort).期望线性时间的第k个顺序统计量选择.最坏情况线性时间的中位数选择,并给

算法导论第九章中位数和顺序统计量(选择问题)

本章如果要归结成一个问题的话,可以归结为选择问题,比如要从一堆数中选择最大的数,或最小的数,或第几小/大的数等, 这样的问题看似很简单,似乎没有什么可研究的必要,因为我们已经知道了排序算法,运用排序+索引的方式不就轻松搞定了?但细想,排序所带来的时间复杂度是不是让这个问题无形之中变得糟糕.那算法研究不就是要尽可能避免一个问题高复杂度地解决,让那些不敢肯定有无最优解的问题变得不再怀疑,这也是算法研究者所追求的一种极致哲学.既然排序让这个问题解决的性能无法确定,那我们就抛开排序,独立研究问题本身,看

第九章 中位数和顺序统计量 9.2 期望为线性时间的选择算法

package chap09_Medians_and_Order_Statistics; import static org.junit.Assert.*; import java.util.Random; import org.junit.Test; public class SearchAlorithms { /** * 分割(快速排序中对数组的分割) * * @param n * @param start * @param end * @return */ protected static

算法导论之七(中位数和顺序统计量之选择算法)

实际生活中,我们经常会遇到这类问题:在一个集合,谁是最大的元素?谁是最小的元素?或者谁是第二小的元素?....等等.那么如何在较短的时间内解决这类问题,就是本文要阐述的. 先来熟悉几个概念: 1.顺序统计量: 在一个由n个元素组成的集合中,第i个顺序统计量(order statistic)是该集合中第i小的元素.最小值是第1个顺序统计量(i=1),最大值是第n个顺序统计量(i=n).   2.中位数: 一个中位数是它所属集合的"中点元素",当n为奇数时,中位数是唯一的,位于i=(n+1

顺序统计量

在一个n个元素组成的集合中,第i个顺序统计量是该集合中第i小的元素. 使用选择算法,可以在Θ(n)时间内找到第i个顺序统计量 对序列A进行划分,使得[s...p-1] < [p] < [p+1...e] 如果p==i,则返回A[p] 如果p>i,对[s...p-1]重新划分,反之对[p+1...e]重新划分 private static int Select(List<int> sq, int s, int e, int i) { //如果s=e了,说明找到了 if (s &

9.中位数与顺序统计量

摘要: 本章所讨论的问题是在一个由n个不同数值构成的集合中选择第i个顺序统计量问题.主要讲的内容是如何在线性时间内O(n)时间内在集合S中选择第i小的元素,最基本的是选择集合的最大值和最小值.一般情况下选择的元素是随机的,最大值和最小值是特殊情况,书中重点介绍了如何采用分治算法来实现选择第i小的元素,并借助中位数进行优化处理,保证最坏保证运行时间是线性的O(n). 1.基本概念 顺序统计量:在一个由n个元素组成的集合中,第i个顺序统计量是值该集合中第i小的元素.例如最小值是第1个顺序统计量,最大

Selection Problem (选择问题)

在一个由n个元素组成的集合中,第i个“顺序统计量(order statistic)”是该集合中第i小的元素.例如,在一个由n个元素组成的集合中,最小值是第1个顺序统计量,最大值是第n个顺序统计量.而“中位数(median)”总是出现在low((n+1)/2)或者high((n+1)/2)处,其中low是向下取整(“下中位数”),high是向上取整(“上中位数”),当n为奇数的时候,只有“下中位数”,而n为偶数的时候,同时有“下中位数”和“上中位数”. 选择问题的定义如下. 输入:一个包含n个不同

选择排序算法总结

选择算法 选择算法之选取最大数或最小数 选取最大数或最小数代码实现 选择算法之选取最大数和最小数 选取最大数和最小数代码实现 选取最大数和最小数代码优化 快速选择算法 快速选择算法分析 快速选择算法编码实现 快速选择算法代码优化 BFPRT选择算法 BFPRT选择算法主元选择 BFPRT选择算法性能分析 BFPRT选择算法代码实现 注:本文中的所有代码都在这里 选择算法 选择算法就是用来解决在一堆数里面选出第k大的数的问题.选择算法的设计方法有很多,比如将这堆数据先进行排序,然后取出对应的第k个

【算法导论】学习笔记——第9章 中位数和顺序统计量

在一个由n个元素组成的集合中,第i个顺序统计量(order statistic)是该集合中第i小的元素.用非形式化的描述来说,一个中位数(median)使它所属集合的“中点元素”.当n为奇数时,中位数是唯一的,位于i=(n+1)/2处.当n为偶数时,存在两个中位数,分别位于i=n/2和i=n/2+1处.因此不考虑n的奇偶性,中位数总是出现在i=floor((n+1)/2)处(下中位数)与i=ceil((n+1)/2)处(上中位数).本章将讨论一个由n个互异的元素构成的集合中选择第i个顺序统计量的