3.6 最快效率求出乱序数组中第k小的数

Chapter3: 更好的查找与排序算法

6. 最快效率求出乱序数组中第k小的数

题目

以尽量高的效率求一个乱序数组中第k小的元素

算法

算法1

用快排先将数组排序,然后直接找第k个元素,时间复杂度为O(nlgn)

算法2

思路

用分区查找的思想,同样有点排序的感觉,毕竟分区就是将小于主元的元素放左边,大于主元的元素放右边。

与排序完再查找不同的是:

  • 这个思路不用将所有元素排序完毕,找到指定元素就停止。
  • 排序的分区每次递归将数组分为两部分,两部分都需要分别递归进行分区;而这个思路每次确定元素在左数组还是右数组后,只需要继续对其中一个进行分区,另一个不用

对于一次递归调用来说:

  • 首先只用快排的分区函数:选取一个主元,将比主元小的元素放在左边,比主元大的元素放在右边

  • 比较输入k和主元的位置(注意和下标的转换,nowQ=q-begin+1即为主元在当前划分数组中是第几个元素)

    • 如果输入k在主元之前,即在数组的左部分,则下一次递归调用时,k的相对位置不变,传参到直接传k即可
    • 如果输入k在主元之后,即在数组的右部分,则下一次递归调用时,k的相对位置发现变化,k = k-nowQ 即k在当前划分数组中的位置

    比如原来数组10个元素,假设主元为第4个元素,如果位置(不是下标)k为3,则下次划分为前5个元素,它的位置还是3;

    如果k为6,则下次划分为的数组为第5-10个元素,它的位置为6-4=2,即第2个位置

时间复杂度分析
最好情况

每次主元的选取都选中整个数组的中值,由于每次分区后只在原来的一半进行查找,所以如果找到最后才找到的话(即待查位置的元素每次都不是主元),那时间复杂度为O(lgn)

最差情况

如果每次主元都选中边界前一个的话(左边n-1个元素,右边1个),如果找到最后才找到的话(即待查位置的元素每次都不是主元),那要进行n(1+n)/2 次运算,时间复杂度为O(n^2)

平均情况

三点分区法选取的中值比较合理,如果找到最后才找到的话(即待查位置的元素每次都不是主元),时间复杂度也是O(lgn)

代码
int selectK(int* arr,int begin, int end,int k){
    int q = partition2(arr,begin,end);//主元的下标 
    int nowQ=q-begin+1;//nowK:主元在当前的数组划分中是第几个元素(注意不是下标) 
    if(nowQ<k)//当前主元位置小于k,即k在主元右侧 
        return selectK(arr,q+1,end,k-nowQ);//在右数组中k新的相对位置下标(代入nowQ的值发现等价与k+begin-(q+1))//即新的k的下标    
    else if(nowQ>k)
                return selectK(arr,begin,q-1,k);//k在当前数组划分的左半部分,位置还是ke 
    else
        return arr[q];//索引元素值的时候又得用回下标q了 
}

其中的分区函数要用到之前快排的分区函数,这里用双向扫描分区法,主元的选取采用3点中值法

/*快速排序-双向扫描分区分区法
功能:选取一个主元,将小于主元的数放数组左边,大于主元的数放右边
//三点中值法确定主元
*/
int partition2(int* arr,int begin,int end){
    //int pivot=arr[begin];
    int pivot;//三点中值法确定主元 
    int mid = begin+((end-begin)>>1);
    /*判断这3个数哪个是中位数,并将中位数与第一个数交换*/
    if(arr[begin]>=arr[end]&&arr[begin]<=arr[mid]){
        pivot=arr[begin];
    }
    else if(arr[begin]<=arr[end]&&arr[begin>=arr[mid]]){
        pivot=arr[begin];
    }
    else if(arr[begin]<=arr[end]&&arr[begin]<=arr[mid]){
        if(arr[end]<=arr[mid]){ 
            pivot=arr[end];
            int tmp=arr[begin];//交换值 
            arr[begin]=arr[end];
            arr[end]=tmp; 
        } 
        else{ 
            pivot=arr[mid];
            int tmp=arr[begin];
            arr[begin]=arr[mid];
            arr[mid]=tmp; 
        }   
    }
    else if(arr[begin]>=arr[end]&&arr[begin]>=arr[mid]){
        if(arr[end]<=arr[mid]){ 
            pivot=arr[mid];
            int tmp=arr[begin];
            arr[begin]=arr[mid];
            arr[mid]=tmp;           
        } 
        else{ 
            pivot=arr[end]; 
            int tmp=arr[begin];
            arr[begin]=arr[end];
            arr[end]=tmp; 
        }       
    }
    
    int left=begin+1;
    int right=end;
    while(left<=right){
        while(left<=right&&arr[left]<=pivot)//因为left在变化所以这里也要有left<=right的判断条件
            left++;
        while(left<=right&&arr[right]>pivot)
            right--;
        if(left<right){//如果left==right就没有交换的必要了
            int tmp=arr[left];
            arr[left]=arr[right];
            arr[right]=tmp;
        }
    }
    int tmp=arr[begin];//交换主元到右指针的位置
    arr[begin]=arr[right];
    arr[right]=tmp;
    
    return right;
} 

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,269评论 0 9
  • 排序(下):如何用开排思想在O(n)内查找第K大元素 上一节我讲了冒泡排序、插入排序、选择排序这三种排序算法,它们...
    GhostintheCode阅读 820评论 0 0
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,173评论 0 52
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,250评论 0 2
  • 1 初级排序算法 排序算法关注的主要是重新排列数组元素,其中每个元素都有一个主键。排序算法是将所有元素主键按某种方...
    深度沉迷学习阅读 1,400评论 0 1