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

Posted

技术标签:

【中文标题】查找向量中的最小项目列表【英文标题】:finding list of minimum items in a vector 【发布时间】:2015-11-17 13:42:13 【问题描述】:

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

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

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

但现在我需要一个最简单的 for 循环或 while 语句来查找向量中的 10 个最小值而不进行排序?

【问题讨论】:

std::partial_sort 足以胜过std::sort 这是作业吗?到目前为止,您在代码中尝试过什么? 行号?你是说索引? 前(最小)10 个元素的顺序重要吗? 【参考方案1】:

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

不过,求一个min并不难,而且避免排序,避免重复向量,

如果你在要求时真的是认真的:

我需要一个最简单的 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;
 

【讨论】:

如果这个向量中有两个相似的整数怎么办..例如两个10 @Snowman888 - 你有什么特别想发生的吗?当 2 个元素(最小的 10 个)具有相同值时,首先找到该最小值的较低索引并首先报告(接下来报告第二个元素)。 我也有同样的想法。我想知道是否还有其他更短的路线可以解决这个问题。我所做的是,遍历整个向量找到最小值然后增加最小元素的值并再次迭代直到向量大小达到 10.. 谢谢【参考方案2】:

检查这个例子:

// 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)进行排序,同时以任何顺序保留其他值。现在您可以肯定地对其进行修改以满足您的需求。

【讨论】:

【参考方案3】:

实际上,鉴于您只需要知道 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";

当然,您可以使用指向原始项目的指针向量而不是索引,但您说您需要“行号”,所以我编写了代码来提供它。

【讨论】:

【参考方案4】:

如果您需要自己编写代码,请使用快速选择来查找第 10 个最小的元素。这会将数组分成几部分,左边的最小到第 9 个最小但未排序,第 10 个最小的作为枢轴,右边的元素 >= 10th 最小的元素。维基文章:

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

【讨论】:

以上是关于查找向量中的最小项目列表的主要内容,如果未能解决你的问题,请参考以下文章

查找列表中的最小元素(递归) - Python

在哈希表或排序列表中查找项目哪个更快?

根据结构列表上的条件查找 FirstOrDefault

查找项目对之间的全局最小距离的算法

查找数字序列中的空白

使用 STL 算法在表(向量的向量、二维数组)中查找最小值/最大值的优雅方法