zoukankan      html  css  js  c++  java
  • 递归算法学习系列之寻找第K大

    1. 概述

            国人向来喜欢论资排辈的,每个人都想当老大,实在当不成,当个老二,老三,老K也不错,您一定看过这样的争论: 两个人吵架,一个人非常强势,另外一个忍受不住了便说:"你算老几呀?",下面就通过这篇文章就是要解决找出老几的问题!

        2.   应用场景

            在向量V[first,last)中查找出第K大元素的值

        3.  分析

            如果利用排序算法将向量V排好序,那么第K大元素就是索引为v.length-k的元素了,这样能解决问题,但效率不高,因为这相当于为了歼灭敌人一个小队而动用了我们全军的力量,得不偿失,回想快速排序中的分表,每次都将目标向量分为两个子表,左子表中全部小于中间元素v[mid],右边都大于中间元素v[mid],这样就可以减小了查找范围,因为我可以只查找左子表或者右子表就能找到目标元素了。如下图所示,我们可以将向量 v划分成如下

      Left(<=KLargest) KLargest     Right(>=KLargest)

    按照这样的思路,我们仍使用快速排序中的分表策略,首先将向量V从中间位置分开,分成左和右,分好后,中间值的索引如果恰恰等于K,就找到了,否则如果中间元素索引大于K,则在左子表中继续查找,忽略右子表,如果中间值索引小于K,则在右子表中继续查找,如此循环往复。

    快速排序中的子表划分函数为:

      /// <summary>
            
    /// 交换位置
            
    /// </summary>
            
    /// <param name="v"></param>
            
    /// <param name="index1"></param>
            
    /// <param name="index2"></param>

            private void Swrap(int[] v, int index1, int index2)
            
    {
                
    int temp = v[index1];
                v[index1] 
    = v[index2];
                v[index2] 
    = temp;
            }

            
    /// <summary>
            
    /// 将向量V中索引{first,last)划分成两个左子表和右子表
            
    /// </summary>
            
    /// <param name="v">向量V</param>
            
    /// <param name="first">开始位置</param>
            
    /// <param name="last">结束位置</param>

            private int PivotIndex(int[] v, int first, int last)
            
    {
                
    if (last == first)
                
    {
                    
    return last;
                }

                
    if (last - first == 1)
                
    {
                    
    return first;
                }

                
    int mid = (first + last) / 2;
                
    int midVal = v[mid];
                
    //交换v[first]和v[mid]
                Swrap(v, first, mid);
                
    int scanA = first + 1;
                
    int scanB = last - 1;
                
    for (; ; )
                
    {

                    
    while (scanA <= scanB && v[scanA] < midVal)
                    
    {
                        scanA
    ++;
                    }

                    
    while (scanB > first && midVal <= v[scanB])
                    
    {
                        scanB
    --;
                    }

                    
    if (scanA >= scanB)
                    
    {
                        
    break;
                    }

                    Swrap(v, scanA, scanB);
                    scanA
    ++;
                    scanB
    --;
                }

                Swrap(v, first, scanB);
                
    return scanB;

            }

       设计一个函数,FindKLargest(int[] v,int first,int last,int k);这个函数包括四个参数:向量V,开始位置first,结束位置last,和第k大中的K,则该函数为:

    调用FindKLargest后,因为数组是从小到大排序,所以第K大元素的值为V[v.Length-k];

    void FindKLargest(int[] v, int first, int last, int k)
            
    {

                
    //表示分表中值的索引
                int index = 0;
                index 
    = PivotIndex(v, first, last);
                
    if (index == k)
                
    {
                    
    //找到了K大
                    return;
                }


                
    if (index > k)
                
    {
                    
    //只在左子表中查找
                    FindKLargest(v, first, index, k);
                }


                
    else
                
    {
                    
    //只在右子表中查找
                    FindKLargest(v, index, last, k);
                }

            }

    4.运行结果:
      原向量 :v  = { 100, 200, 50, 23, 300, 560, 789, 456, 123, 258
      first = 0; last = v.Length;k=3
      输出:456

    5.结论
      利用递归算法可以将比较复杂的问题划分为越来越小的小问题,这样能够使复杂问题简单化,这样的思路在系统设计和架构中同样有着至关重要的作用,一个好的架构师,面对复杂的问题,能庖丁解牛般化腐朽为神奇,而坏的却往往适得其反,他们的特长是简单问题复杂化。

    6.  项目文件
       /Files/jillzhang/FindK.rar
     
       上几篇文章索引: 
        1.算法:【一列数的规则如下: 1、1、2、3、5、8、13、21、34 ,求第30位数是多少, 用递归算法实现。(C#语言)】
        2.大牛生小牛的问题 
        3.递归算法学习系列一(分而治之策略)
        4. 递归算法学习系列二(归并排序)
        5.递归算法学习系列之三(快速排序)



    -------------------------------------------------------
    人老了,脑袋不好用了,偶尔用算法来练练脑子,可以防止早衰。呵呵
                                                            jillzhang jillzhang@126.com

  • 相关阅读:
    Vue-cli的安装和使用
    Codeforces Round #182 (Div. 1) B. Yaroslav and Time 最短路
    HDU 4745 Two Rabbits 区间dp_回文序列
    Codeforces Round #284 (Div. 1) C. Array and Operations 二分图最大匹配
    HDU 4734 F(x) 数位dp
    HDU 4389 X mod f(x) 数位dp
    HDU 5900 QSC and Master 区间dp
    Codeforces Round #235 (Div. 2) D. Roman and Numbers 状压dp+数位dp
    HDU 3709 Balanced Number 数位dp
    Codeforces Round #304 (Div. 2) E. Soldier and Traveling 最大流
  • 原文地址:https://www.cnblogs.com/jillzhang/p/913478.html
Copyright © 2011-2022 走看看