如何在不使用数组或循环的情况下找到第二个最小数字

时间:2017-12-05 15:21:07

标签: c++

我尝试编写一个从用户5整数接收的程序并打印第二个最小数字。
以下是我尝试过的示例:

#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
if (a>b && a<c && a<d && a<e)
    cout<<a<<endl;
if (b>a && b<c && b<d && b<e)
    cout<<b<<endl;
if (c>a && c<b && c<d && c<e)
    cout<<c<<endl;
if (d>a && d<b && d<c && d<e)
    cout <<d<<endl;
if (e>a && e<b && e<c && e<d)
cout <<e<<endl;
return 0;

}

当我输入1 2 3 4 5时,它会打印第二个最小值,但是当我输入
5 4 3 2 1屏幕上不会打印任何内容。我做错了什么?还有其他方法来编写我的程序吗?

8 个答案:

答案 0 :(得分:4)

您对逻辑的问题在于,您不强制自己只打印1个项目,至少打印一个项目。 使用&#39; else&#39; if / else语法的一部分,您将确保只能命中一个分支。然后,您可以在最后使用其他内容进行跟进,因为您知道所有其他条件都是错误的。

完成此操作后,您将看到您打印的最后一个值,(1)而不是预期的(4)。这是因为你关于如何找到第二低的逻辑是错误的。对于案例5,4 ...

,b> a是假的

注意: 每个受雇的工程师都会在std :: vector / std :: array中创建一个循环,我建议你将老师指向这篇文章,因为鼓励循环是一件好事而不是坏事。

这样的东西
vector<int> data;
for (int i=0; i<5; ++i) {
    int t;
    cin >> t;
    data.push_back(t);
}
std::nth_element(data.begin(), data.begin()+1, data.end(), std::greater<int>());
cout << data[1];

答案 1 :(得分:3)

5个元素有120种可能的排列。您的代码应输出所有这些代码的正确数字。因此,一个傻瓜式的代码将使用120次重复检查,如下所示:

if (a > b && b > c && c > d && d > e) // the order is a>b>c>d>e
    cout << d;
else if (a > b && b > c && c > e && e > d) // the order is a>b>c>e>d
    cout << e;
...
else if (e > d && d > c && c > a && e > b) // the order is e>d>c>a>b
    cout << a;
else // the order is e>d>c>b>a
    cout << b;

这是一个非常长,低效且棘手的代码。如果你只在一个变量中输入拼写错误,它会在极少数情况下输出错误的答案。此外,它无法处理某些输入相等的可能性。

如果排序算法的输入数是已知的小常数,则可以使用名为sorting networks的方法。这是一个定义明确的计算机科学问题,它为少量输入提供了众所周知的最优解决方案,而且肯定很小。用于5个输入的最佳分类网络包含9个比较器,并且例如描述了这些比较器。 here

由于您不需要对数字进行排序,只知道第二个最小的输入,您可以进一步减小网络的大小,为7个比较器。

完整的排序网络(没有从9减少到7)转换为C ++:

if (b < c)
    swap(b, c);
if (d < e)
    swap(d, e);
if (b < d)
    swap(b, d);
if (a < c)
    swap(a, c);
if (c < e)
    swap(c, e);
if (a < d)
    swap(a, d);
if (a < b)
    swap(a, b);
if (c < d)
    swap(c, d);
if (b < c)
    swap(b, c);
// now the order is a ≥ b ≥ c ≥ d ≥ e
cout << d;

这段代码也很模糊 - 根本不明显它是如何以及为什么有效 - 但至少它很小并且在某种意义上是最佳的。此外,很明显它总是打印一些东西(因此它解决了原始问题)并支持部分相等输入的情况。

如果您在较大的项目中使用此类代码,则应记录从中获取该代码的位置并对其进行测试。幸运的是,有120种不同的可能性(或32,如果你使用的话 zero-one principle),因此有一种方法可以证明此代码没有错误。

答案 2 :(得分:2)

这对你有用。 (请注意,它可能不是最好的方法,您可以通过计算min和secondMin的函数来最小化它,而不是逻辑的丑陋复制粘贴,但它会让您开始:

#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
int min, secondMin;


cin>>a>>b;

min = a < b ? a : b;
secondMin = a < b ? b : a;

cin>>c;

if (c < min)
{
    secondMin = min;
    min = c;
}
else if (c < secondMin)
{
    secondMin = c;
}

cin>>d;

if (d < min)
{
    secondMin = min;
    min = d;
}
else if (c < secondMin)
{
    secondMin = d;
}

cin>>e;

if (e < min)
{
    secondMin = min;
    min = e;
}
else if (e < secondMin)
{
    secondMin = e;
}

cout << "min = " << min << ", secondMin = " << secondMin << endl;

return 0;

}

如果您有任何问题,请随时在评论中提问

答案 3 :(得分:2)

#include <set>

std::set<int> values = { a, b, c, d, e }; // not an array.
int second_min = *std::next(values.begin(), 1); // not a loop

答案 4 :(得分:1)

递归更通用方法怎么样? 没有数组没有循环,并且不仅限于5个整数。

以下函数get_2nd_min()跟踪从std::cin读取的总共count次的两个最低整数:

#include <climits>
#include <cstddef>
#include <iostream>

int get_2nd_min(size_t count, int min = INT_MAX, int second_min = INT_MAX)
{
   if (!count)
      return second_min; // end of recursion

   // read next value from cin
   int value;
   std::cin >> value;

   // Does second_min need to be updated?
   if (value < second_min) {

     // Does min also need to be updated?
     if (value < min) {
        // new min found
        second_min = min; // move the so far min to second_min
        min = value; // update the new min
     } else {
        // value is lower than second_min but higher than min
        second_min = value; // new second_min found, update it
     }
   }
   // perform recursion
   return get_2nd_min(count - 1, min, second_min);
}

为了读取5个整数并获得第二个最低值:

int second_min = get_2nd_min(5);

答案 5 :(得分:0)

<强>更新 在此解决方案中,我使用 min 函数:

#include <iostream>
using namespace std;


int minDifferentFromFirstMin(int x, int y, int firstMin) {
    if(x < y) {
        if(x != firstMin) {
            return x;
        }
        else {
            return y;
         }
    }

    if(y < x) {
        if(y != firstMin) {
            return y;
        }
        else {
            return x;
         }
    }
    //if x & y are equals, return one of them
    return x;
}

int main () {
 int a,b,c,d,e;
 int iter11, iter12, iter13;
 int iter21, iter22, iter23;
 int firstMinimum, secondMinimum;
 cin>>a>>b>>c>>d>>e;

 //iteration 1: find the first minimum
 iter11 = min(a, b);
 iter12 = min(c, d);
 iter13 = min(iter11, iter12);
 firstMinimum = min(iter13, e);

 //iteration 2: find the second minimum
 iter21 = minDifferentFromFirstMin(a, b, firstMinimum);
 iter22 = minDifferentFromFirstMin(c, d, firstMinimum);
 iter23 = minDifferentFromFirstMin(iter21, iter22, firstMinimum);
 secondMinimum = minDifferentFromFirstMin(iter23, e, firstMinimum);

 cout<<secondMinimum<<endl;
}

答案 6 :(得分:0)

一种方法是首先找到最小数字min,然后找到不是min的最小值。要做到这一点,首先要找到最小值:

int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));

现在我们需要再次执行相同操作,但忽略min。我们可以使用一个名为triMin的函数来执行此操作,该函数接受3个值并丢弃任何最小值:

int triMin(int currentMin, int left, int right)
{
    if(currentMin == left) return right;
    if(currentMin == right) return left;

    return std::min(left, right);
}

您现在可以将它们组合起来得到答案:

int a = 5, b = 4, c = 3, d = 2, e = 1;

int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
int min2 = triMin(min, a, triMin(min, b, triMin(min, c, triMin(min, d, e))));

std::cout << "Second min = " << min2 << std::endl;

这会打印2

答案 7 :(得分:0)

可以使用one-pass算法来完成此任务。不需要使用任何集合(数组,集合或任何东西) 这种一次通过算法具有内存效率 - 它不需要将所有元素存储在集合中(并浪费内存),并且当其他解决方案因内存不足而失败时,甚至可以使用大量元素。 这个算法的一般想法是这样的:

  • 按顺序记下每个号码
  • 您需要两个变量来存储所有已见号码中的minimumsecond minimum个数字。
  • 当您获得号码时,您需要使用当前minumum对其进行测试,以确定它是否为新的最小号码。
    • 如果将其存储为minimum,请将旧最小值存储在second minimum数字
  • 否则检查它是否小于second minimum个数字。
    • 如果将其存储为second minimum号码。
  • 现在second minimum号码包含所有已见号码的答案。
  • 重复,但没有看到数字。

调查所有数字后second minimum都包含答案 这是使用c ++ 17(link to wandbox):

的实现
#include <iostream>
#include <optional>

int main()
{
    int a, b, c, d, e;
    std::cin >> a >> b >> c >> d >> e;

    // you can find second minimal number while going through each number once
    auto find_current_answer = [minimum = std::optional<int>{}, next_to_minimum = std::optional<int>{}](int next) mutable {
        // when receiving next number
        // 1. check if it is new minimum
        if (!minimum || minimum > next) {
            // move values like this: next_to_minimum <- minimum <- next
            next_to_minimum = std::exchange(minimum, next);
        }
        // 2. else check if it is new next_to_minimum
        else if (!next_to_minimum || next_to_minimum > next) {
            next_to_minimum = next;
        }
        // 3. return current answer
        return next_to_minimum;
    };

    // repeat as much as you like
    find_current_answer(a);
    find_current_answer(b);
    find_current_answer(c);
    find_current_answer(d);
    // store answer that is interesting to you
    auto result = find_current_answer(e);

    // if it has value - it is the answer
    if (result) {
        std::cout << "Answer: " << *result << '\n';
    }
    else {
        std::cout << "Not enough numbers!\n";
    }
}