最坏情况为线性的选择算法

基本思想

主体上是在期望为线性的选择算法上进行改进,将其中的随机的划分元素改为取中位数,使划分更均匀,从而达到最坏时时间复杂度也为线性.需要注意的是实现时里面的索引很晕,别搞混了.我就是先写了个很乱,然后实在改不下去了,就重写了,总共我大概写了5,6个小时吧.(可能我太菜了)

图解

代码

伪代码

这里书中未给伪代码,仅给了整个算法的流程,但并不影响我们的实现

C代码

#include <stdio.h>
#define N 50

void show(int *a, int p, int r);
int Partition(int * a, int p, int r, int x)//以值x来进行分割
{
    int k;
    int pos;
    for(k = p; k <= r; k++)//先把值x与末尾r交换位置,不太好,因为我还遍历了数组来找x的索引值
    {
        if(a[k] == x)
            pos = k;
    }
    int temp;
    int t = a[pos];
    a[pos] = a[r];
    a[r] = t;
    int i, j;
    i = p-1;
    for(j = p; j <= r; j++)
    {
        if(a[j] <= t)
        {
            i+=1;
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    return i;//返回划分后的x所对应的索引
}

int Insertion_sort(int * a, int p, int r)//用来对每组元素进行插排
{
    int i, j;
    for(i = p+1; i <= r; i++)
    {
        j = i;
        while(j > p && a[j] < a[j-1])
        {
            int temp = a[j];
            a[j] = a[j-1];
            a[j-1] = temp;
            j--;
        }
    }
}

int Select(int *a, int p, int r, int i, int len)//返回第i个元素的值
{
    if(p==r)//仅一个元素时直接返回
    {
        return a[p];
    }

    int midval[N];
    int group = len%5==0 ? len/5 : len/5+1;
    if(len%5==0)//每组刚好5人
    {
        int i;
        for(i = 0; i < group; i++)
        {
            Insertion_sort(a,p+5*i,p+5*i+4);
            midval[i] = a[p+i*5+2];
        }
    }
    else//最后一组不满5人
    {
        int i;
        for(i = 0; i < group-1; i++)
        {
            Insertion_sort(a,p+5*i,p+5*i+4);
            midval[i] = a[p+i*5+2];
        }
        //单独处理最后一组
        int lastgroupsize = len%5;
        Insertion_sort(a,p+5*i,r);
        midval[i] = a[p+i*5+lastgroupsize/2];
    }

    int pos2 = Select(midval,0,group-1,group/2,group);//对midval[]递归查找其中位数
    int q = Partition(a,p,r,pos2);//以中位数pos2来划分元素

    int k = q-p;//划分元素的相对位置
    if(i == k)
        return a[q];//划分元素刚好为所查元素,返回
    else if(i < k)
        return Select(a,p,p+k-1,i,k);//继续处理左半边
    else
        return Select(a,p+k+1,r,i-k-1,r-p-k);//继续处理右半边
}

int main()
{
    int a[]  = {34,65,21,32,555,11,4,78,64,99,25,100,24};
    int len = sizeof(a)/sizeof(int);
    int k;
    int i;
    for(i = 0; i < len; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\ninput nth to search\n");
    scanf("%d",&k);
    int ans = Select(a,0,12,k,13);
    printf("ans %d\n", ans);
    return 0;
}
//算法流程不难,但实现起来其中的细节很多,尤其这里面的下标很绕人

时间复杂度

O(n)

原文地址:https://www.cnblogs.com/w-j-c/p/10086899.html

时间: 2024-08-06 14:00:40

最坏情况为线性的选择算法的相关文章

最坏情况为线性时间的选择算法

求给定输入中第k大的数的算法. 这是一个常见面试题,通常的解法也很明显,使用类似快排的思想. 每趟运行,把数组的值分成两部分,一部分比pivot大,一部分比pivot小,因为我们知道pivot在数组中的位置,所以比较k和pivot的位置就知道第k大的值在哪个范围,我们不断的进行recursion, 直到pivot就是第k大的值. 这个算法的时间预期是O(n).这里需要注意的是讲的仅限于它的预期,对于这个算法,其在最差情况下,时间复杂度则为n的平法. 参阅快速排序的无敌对手一文,我们是可以构建出一

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

randomized_select函数的期望运行时间是Θ(n),这里假设输入数据都是互异的.它返回数组A[p, r]中第i小的元素.该函数最坏情况运行时间为Θ(n2),即使是找最小元素也是如此,以为在每次划分时可能极不走运地总是按余下的元素中最大的来进行划分,而划分操作需要Θ(n)时间.我们也将看到该算法有线性的期望运行时间,又因为它是随机化的,所以不存在一个特定的会导致其最坏情况发生的输入数据. 输入:数组A,整数i(i不大于数组的个数). 输出:数组A中第i小的元素. 期望运行时间:Θ(n)

转:算法的最坏情况与平均情况 复杂度就要看最坏情况

转自:算法的最坏情况与平均情况 如果一个程序运行多次,则有时候它会快点儿,有时候它会慢点儿.算法也一样,在输入1的情况下和输入2的情况下,其执行效率不一定一样.即算法会随着输入数据的不同而有秩序效率的不同,有时候会快点儿,有时候会慢点儿.例如,对一个已经排好序的序列进行排序就要相对容易一些.另外,输入规模的大小也影响算法的运行时间.例如,一个短的序列就比一个很长的序列容易排序. 一般来说,我们希望获得一个算法的时间效率下限,因为所有人都喜欢某种保证:即算法无论如何不会低于我们保证的效率.这种分析

第九章 中位数和顺序统计量 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

线性选择算法(未完成)

#include "stdafx.h" #include<iostream> #include <stdlib.h> #include <time.h> using namespace std; #define SB -1 int RANDOM(int p, int r) { srand((unsigned)time(NULL)); return (rand() % (r - p + 1)) + p; } int partition(int a[],

算法系列笔记2(静态表顺序统计-随机选择算法)

问题:当给定存在静态表(如数组)中的n个元素,如何快速找到其中位数.最小值.最大值.第i小的数? 首先想到的方法是先对数组元素进行排序,然后找到第i小的元素.这样是可行的,但比较排序最快也需要O(nlgn),能否在线性时间内解决呢.这就是随机的分治法-随机选择. 思想:利用随机划分(在快速排序中介绍过)找到主元r,这样就将小于等于r的元素放在了其左边,大于r的元素放在了其右边.这是可以计算出r的rank为k,如果正好等于i,则就返回该元素:如果k大于i,则在左边中寻找第i小的元素,否则在右边中寻

基于实数编码(离散杂交+自适应变异),线性排名选择的遗传算法(附代码)

我们来看一个很简单的小问题f=x1+x2+x3+x4,x1.x2.x3.x4是大于等于10小于等于100的实数,求f的最大值. 这个小学生就能解决的问题我今天打算用遗传算法来解决,你可能说这不是智障吗?但是其实这只是一个小例子,因为用同样的方法,你可以解决f=x1^x2*x3^x4/x2^x1*x4^x3甚至是更复杂的问题,下面就来详细讲一讲. 基于对遗传算法的一般性了解,我就不再赘述详细过程(其实是因为上一篇写过了懒得再写一遍),只谈谈实数编码和线性排名选择策略. 实数编码顾名思义就是用实数进

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

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

随机选择算法

随机选择算法和快速排序原理相似,所以有时候也称作“快速选择算法”,一般选择问题可以证明都能在O(n)时间内完成.随机选择算法的期望运行时间为线性时间,即Θ(n),但其最坏情况运行时间为O(n^2).最坏情况与快排一样,都是运气不好导致划分不均匀. 代码: #include "stdafx.h" #include <iostream> #include <vector> #include <stdlib.h> class QuicklySelect {