欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#递归算法寻找数组中第K大的数

程序员文章站 2023-11-18 11:55:40
1.概述   国人向来喜欢论资排辈的,每个人都想当老大,实在当不成,当个老二,老三,老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.项目文件
http://xiazai.jb51.net/201606/yuanma/findk(jb51.net).rar