在向量中查找最小项目的列表

finding list of minimum items in a vector

本文关键字:小项目 列表 查找 向量      更新时间:2023-10-16

我有一个向量示例向量myVec;

例如,我的向量中有100个元素。现在我想遍历100个元素,找到向量中可能的10个最小元素。

//一种方法是使用排序算法按递增顺序对矢量项目进行排序,并获得前10个项目。然后在这里,我必须创建另一个向量来存储原始和排序的向量。这里的原始程序需要知道向量中排序值的每10个的行号——这在我的程序中。

但现在我需要一个最简单的for循环或while语句来在不排序的情况下找到向量中的10个最小值?。

通常,我建议您使用其他答案中建议的std库排序、partial_sort、nth_element等。

然而,找到一个最小值并避免排序和避免复制向量并不困难,

以防你要求时真的是认真的

我需要一个最简单的for循环或while语句来查找10没有排序的向量中的最小值?。

这里有一种方法:(参见下面的注释"查找10个最小值")

#include <iomanip>
#include <iostream>
#include <vector>
#include <chrono>
#include <algorithm>  // shuffle
  typedef std::vector< int >     IntVec;
  typedef std::vector< size_t >  IndxVec;
  const size_t SMALLEST_10 = 10;
  void myVecShow(IntVec& intVec, const std::string label); // below

  // ///////////////////////////////////////////////////////
  size_t findIndxOfMinValue(const IntVec& intVec)
  {
     size_t minIndx = 0; // search from beginning
     for (size_t j = 0;
          j < intVec.size();  // compare each
          ++j)
     {
        if(intVec[j] < intVec[minIndx])
           minIndx = j; // capture smallest
     }
     return(minIndx);
  }

  // ///////////////////////////////////////////////////////
  int t258()
  {
     IntVec myVec;
     {
        // fill myVec
        for (int i=0; i<100; ++i)
           myVec.push_back(100-i);    // "my vector for instance has 100 elements in it."
        //myVecShow(myVec, "n unshuffled values: ");
        // shuffle myVec
        time_t seed = std::chrono::system_clock::now().time_since_epoch().count();
        std::shuffle (myVec.begin(), myVec.end(), std::default_random_engine(seed));
        myVecShow(myVec, "n Values: ");
     }
     IndxVec indxVec; // to be filled with index of the smallest elements
     indxVec.reserve(SMALLEST_10);
     IntVec  origVal; // capture original values of smallest elements
     origVal.reserve(SMALLEST_10);
     // ///////////////////////////////////////////////////////
     // find 10 smallest values
     {
        for (size_t i=0; i<SMALLEST_10; ++i)
        {
           size_t minValIndx = findIndxOfMinValue(myVec);
           indxVec.push_back (minValIndx);         // capture index
           origVal.push_back (myVec[minValIndx]);  // capture value at index
           myVec[minValIndx] = std::numeric_limits<int>::max(); // mark min value (so its no longer min)
        }
        std::cout << std::endl;
     }
     // restore original values prior to report
     for (size_t i=0; i<indxVec.size(); ++i)
     {
        size_t indx = indxVec[i];
        myVec [indx] = origVal[i];
     }
     // ///////////////////////////////////////////////////////
     // report results
     std::cout << "nSmallest 10 elements: " << std::endl;
     std::cout << "     indx   value" << std::endl;
     for (size_t i=0; i<indxVec.size(); ++i)
     {
        size_t indx = indxVec[i];
        std::cout << "myVec[" << std::setw(2) << indx
                  << "] = "   << std::setw(3) << myVec[indx]
                  << std::endl;;
     }
     std::cout << std::endl;
     return(0);
  } // int t258(void)

  // ///////////////////////////////////////////////////////
  void myVecShow(IntVec& intVec, const std::string label)
  {
     std::cout << label << std::endl;
     size_t j = intVec.size() - 1;
     // header:
     {
        std::cout << "      ";
        for (size_t i=0; i<SMALLEST_10;  ++i) std::cout << std::setw(3) << i << "   ";
        std::cout << std::endl;
     }
     std::cout << std::setw(3) << 0 << ":  ";
     for (size_t i=0; i<intVec.size(); ++i)
     {
        std::cout << std::setw(3) << intVec[i] << "   ";
        if ((i < j) && (9 == (i % 10)))
        {
           size_t row = 1 + (i / 10);
           std::cout << std::endl << std::setw(3) << row << ":  ";
        }
     }
     std::cout << std::endl;
  }

结果:(随机洗牌)

  Values: 
        0     1     2     3     4     5     6     7     8     9   
  0:   50    85     6    62    48    34    40    73    86    11   
  1:   94    58    46    96    66    56    42    15    25    13   
  2:   92    30     7    35    65    37     5    69    90    68   
  3:  100     3     2    87    21    93    43    99    10    98   
  4:   44    24    70    41    59    95    72    49    78    81   
  5:    4    23    47    51    36    54    12    67    91    14   
  6:   53    97    71    52    77    27    20    29    76    83   
  7:   80    28    17    38    32    16    39     9    74    18   
  8:   84    31    61    45     8    33    82    55    63    89   
  9:   60    26    88    79     1    19    57    75    64    22   

Smallest 10 elements: 
     indx   value
myVec[94] =   1
myVec[32] =   2
myVec[31] =   3
myVec[50] =   4
myVec[26] =   5
myVec[ 2] =   6
myVec[22] =   7
myVec[84] =   8
myVec[77] =   9
myVec[38] =  10

更新-当最小的10中的值重复时会发生什么:

我添加了

myVec[6] = 7;

重新运行代码(所以,这是一个不同的随机洗牌),输出为:

Smallest 10 elements: 
     indx   value
myVec[ 7] =   0
myVec[78] =   1
myVec[83] =   2
myVec[79] =   3
myVec[11] =   4
myVec[87] =   5
myVec[12] =   7
myVec[67] =   7
myVec[42] =   8
myVec[51] =   9

更新-我们如何修改此代码以显示最小的10个唯一值的索引

注意:未运行测试,第一次尝试代码(可能)无法正确处理少于10个唯一值的100元素数组

 // find 10 smallest **unique** values
 {
    for (size_t i=0; i<SMALLEST_10; ++i)
    {
       size_t minValIndx = findIndxOfMinValue(myVec);
       indxVec.push_back (minValIndx);         // capture index
       origVal.push_back (myVec[minValIndx]);  
       myVec[minValIndx] = std::numeric_limits<int>::max(); 
       // now hide any duplicate of this minValue, 
       for (size_t j=0; j<myVec.size(); ++j)  // search all
       {
          if(myVec[j] == origVal.back()) 
          {
             indxVec.push_back (j);    // capture index
             origVal.push_back (myVec[j]); 
             myVec[minValIndx] = std::numeric_limits<int>::max(); 
          }
       }   
    }
    std::cout << std::endl;
 }

检查此示例:

// partial_sort example
#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort
#include <vector>       // std::vector
int main () {
  int myints[] = {9,8,7,6,5,4,3,2,1};
  std::vector<int> myvector (myints, myints+9);
  // using default comparison (operator <):
  std::partial_sort (myvector.begin(), myvector.begin()+5, myvector.end());
  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << 'n';
  return 0;
}

输出:

myvector contains: 1 2 3 4 5 9 8 7 6

它使用std::partial_sort(正如Jarod42所说),它对第一个n值(在您的例子中是10)进行排序,同时将其他值按任意顺序保留。现在,您一定可以修改它以满足您的需求。

实际上,假设您只需要知道10个最小的项目(不需要按顺序排列这10个),则可以使用std::nth_element而不是std::partial_sort。这正是你所要求的,没有任何额外的东西,所以它很有可能更高效。

为了避免复制输入,您可以创建一个索引向量,用于对原始数组进行索引,并对索引而不是原始数组进行操作。

总体思路如下:

std::vector<foo> input;
// ...
// This is our index. It'll be filled with 0..I (where I = size of input).
std::vector<std::size_t> index(input.size());
std::iota(index.begin(), index.end(), 0);
// This is the number of smallest items we need to find:
const int N = 10;

if (index.size() <= N) // if we have fewer elements, do nothing.
    return;
// sort our index according to the values in the input:
std::nth_element(index.begin(), index.begin() + N, index.end(),
    [&input](size_t a, size_t b) { return input[a] < input[b]; });
// write out the N smallest items of the input.
for (int i = 0; i < N; i++)
    std::cout << input[index[i]] << "t";

当然,你可以使用指向原始项的指针向量,而不是索引,但你说你需要"行号",所以我编写了代码来提供这一点。

如果您需要自己编写代码,请使用快速选择来查找第10个最小的元素。这将把数组分成几个部分,左边是最小到第九小的,但没有排序,第十小的作为轴心,右边是元素>=第十小元素。Wiki文章:

http://en.wikipedia.org/wiki/Quickselect