Подсчет максимального количества элементов на основе стековых операций c ++ - PullRequest
0 голосов
/ 28 мая 2019

Вам дан набор из N целых чисел. В одной операции вы можете либо извлечь элемент из стека, либо вставить любой вытолкнутый элемент в стек. Вам необходимо максимизировать верхний элемент стека после выполнения ровно K операций. Если стек становится пустым после выполнения операций K, и нет другого способа сделать стек непустым, выведите -1. ​​

Я динамически распределяю память и затем освобождаю память. Я не могу понять, почему я сталкиваюсь с этой проблемой.

#include "pch.h"
#include<iostream>
using namespace std;
int main()
{
int n, x, max;
cin >> n;
cin >> x;
int* arr = new int[n];
    //Storing the values from the last, since the first element represents 
    //top of the stack, so the first element would be latest element which 
    //will be pushed into the stack
for (int i = n; i > 0; i--)
{
    cin >> arr[i];
}
max = arr[n];
    //Finding the max by iterating from the last position to the no of 
    //stack operations performed.
for (int i = n; i >= x; i--)
{
    if (arr[i] > max)
    {
        max = arr[i];
    }
}
cout << max;
delete arr;
return 0;
}

Ввод:

6 4
1 2 4 3 3 5

Ожидаемый результат:

4

Ошибка:

Error Message : Debug Error ! Program :- Heap Corruption detected : after 
normal block c#2368 at 0x01d21e30. CRT detected that the application wrote 
memory after end of heap buffer.

Ответы [ 3 ]

2 голосов
/ 28 мая 2019

В вашем коде есть несколько ошибок: три ошибки индексации и одна ошибка освобождения памяти. Прежде всего, в C ++ индексирование массива всегда начинается с 0. Таким образом, первый действительный индекс массива n-элементов равен 0, а последний действительный индекс - n-1.

1) По этим причинам первый цикл должен быть таким:

for (int i = n-1; i >= 0; i--) { ... }

2) Нижний элемент, который вы называете 'max', должен быть инициализирован так:

max = arr[n-1];

3) То же замечание по поводу второго цикла:

for (int i = n-2; i >= x; i--) { ... }

4) Выделение массива должно выполняться с оператором delete[] вместо delete. В противном случае у вас будет утечка памяти и неопределенное поведение. Здесь вы можете найти дополнительную информацию об этих операторах:

delete[] arr;
1 голос
/ 28 мая 2019

В массиве размером n допустимый индекс от 0 до n-1, а не от 1 до n

Предупреждение, когда вы выделяете массив с новым , вы должны освободить его с помощью delete []

Я также рекомендую вам проверить при чтении значения, что чтение успешно, иначе текущий контейнер не установлен и все следующее чтение ничего не сделает

Например, из вашего кода:

#include <iostream>

using namespace std;

int main()
{
  int n, x, max;

  if ((! (cin >> n)) || (n < 1))
    cerr << "invalid size" << endl;
  else if ((! (cin >> x)) || (x < 0) || (x >= n))
    cerr << "invalid min index" << endl;
  else {
    int* arr = new int[n];
    //Storing the values from the last, since the first element represents 
    //top of the stack, so the first element would be latest element which 
    //will be pushed into the stack
    for (int i = n-1; i >= 0; i--)
    {
      if (!(cin >> arr[i])) {
        cerr << "invalid value" << endl;
        return 0;
      }
    }
    max = arr[n-1];
    //Finding the max by iterating from the last position to the no of 
    //stack operations performed.
    for (int i = n-2; i >= x; i--)
    {
      if (arr[i] > max)
        {
          max = arr[i];
        }
    }
    cout << max << endl;
    delete arr; // must be delete [] arr;
  }
  return 0;
}

Из-за того, что я проверяю, что было введено целое число, я также проверяю, что размер / мин индексы строго положительны, а также проверяет правильность минимального индекса

Также бесполезно делать цикл, чтобы найти максимум, сравнивающий arr[n-1] с самим собой, поэтому первый рассматриваемый индекс - n-2

Кажется странным заполнять массив из последнего индекса

Вы используете массив, но вы также можете использовать vector<int>, std::vector очень практичны

Компиляция и исполнения:

pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra v.cc
pi@raspberrypi:/tmp $ ./a.out
aze
invalid size
pi@raspberrypi:/tmp $ ./a.out
-1
invalid size
pi@raspberrypi:/tmp $ ./a.out
3 qsd
invalid min index
pi@raspberrypi:/tmp $ ./a.out
3 4
invalid min index
pi@raspberrypi:/tmp $ ./a.out
6 4
1 2 4 3 3 5
2
pi@raspberrypi:/tmp $ 

Обратите внимание, что результатом является 2, а не 4 из-за сдвига в индексе, если вы хотите, чтобы индекс начинался с 1 для пользователя, выполните

#include<iostream>

using namespace std;

int main()
{
  int n, x, max;

  if ((! (cin >> n)) || (n < 1))
    cerr << "invalid size" << endl;
  else if ((! (cin >> x)) || (x < 1) || (x > n))
    cerr << "invalid min index" << endl;
  else {
    x -= 1;

    int * arr = new int[n];
    //Storing the values from the last, since the first element represents 
    //top of the stack, so the first element would be latest element which 
    //will be pushed into the stack
    for (int i = n-1; i >= 0; i--)
    {
      if (!(cin >> arr[i])) {
        cerr << "invalid value" << endl;
        return 0;
      }
    }
    max = arr[n-1];
    //Finding the max by iterating from the last position to the no of 
    //stack operations performed.
    for (int i = n-2; i >= x; i--)
    {
      if (arr[i] > max)
        {
          max = arr[i];
        }
    }
    cout << max << endl;
    delete arr; // must be delete [] arr;
  }
  return 0;
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra v.cc
pi@raspberrypi:/tmp $ ./a.out
6 4
1 2 4 3 3 5
4
pi@raspberrypi:/tmp $ 

Выполнение под valgrind с указанием неверного free arr:

pi@raspberrypi:/tmp $ valgrind ./a.out
==3761== Memcheck, a memory error detector
==3761== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3761== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3761== Command: ./a.out
==3761== 
6 4
1 2 4 3 3 5
4
==3761== Mismatched free() / delete / delete []
==3761==    at 0x48491EC: operator delete(void*) (vg_replace_malloc.c:576)
==3761==    by 0x10BE7: main (in /tmp/a.out)
==3761==  Address 0x4bcb388 is 0 bytes inside a block of size 24 alloc'd
==3761==    at 0x48485F0: operator new[](unsigned int) (vg_replace_malloc.c:417)
==3761==    by 0x10A9F: main (in /tmp/a.out)
==3761== 
==3761== 
==3761== HEAP SUMMARY:
==3761==     in use at exit: 0 bytes in 0 blocks
==3761==   total heap usage: 4 allocs, 4 frees, 22,296 bytes allocated
==3761== 
==3761== All heap blocks were freed -- no leaks are possible
==3761== 
==3761== For counts of detected and suppressed errors, rerun with: -v
==3761== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 3)
pi@raspberrypi:/tmp $ 
0 голосов
/ 28 мая 2019

Сначала вам нужно получить требование прямо в голове:

Вам дан набор из N целых чисел. В одной операции вы можете либо извлечь элемент из стека, либо вставить любой вытолкнутый элемент в стек. Вам необходимо максимизировать верхний элемент стека после выполнения ровно K операций. Если стек становится пустым после выполнения операций K, и нет другого способа сделать стек непустым, выведите -1. ​​

  • Итак, если N равно 0, вы печатаете -1, в противном случае ...
  • Если K равно 0, вы печатаете top (), в противном случае ...
  • Если K равно 1, вы должны pop (), потому что вам нечего толкать, поэтому, если N равно 1, ваш стек пуст и вы должны вывести -1, в противном случае выведите top (): независимо от того, какой у вас элемент 2nd-top случилось быть; в противном случае ...
  • если x
    • если x == N, обратите внимание, что это означает, что вы все еще не вытолкнули окончательное значение из стека, поэтому, если это самый большой элемент, вам не повезло: вам придется отбросить 2-й по величине назад на вершине стека в противном случае ...
  • если x> N, вы можете вытолкнуть все элементы, тратить любые операции до тех пор, пока не останется только 1 операция (поочередно сдвигая любое из не самых больших значений, тогда, если у вас есть другая операция, чтобы тратить ее на извлечение) выкл), затем с помощью последней операции вернуть наибольшее значение обратно в стек; это эквивалент для нахождения наибольшего значения в стеке

Таким образом, код, который всегда находит наименьший элемент в верхних элементах стека "x", не моделирует операции стека, которые вы должны иметь в наличии.

Теперь, если вы понимаете, какое значение должна возвращать ваша программа, это не значит, что вы не должны точно моделировать операции. Для меня это звучит так, как будто вы должны использовать операции стека, push, pop и top, а также отслеживать значения, которые вы выдавали, чтобы вы могли отбросить их обратно, если это необходимо, и вам, возможно, понадобится найти наибольшее значение, которое вы '' мы специально положили его обратно * 1027

Чтобы сделать все это, проще всего использовать структуру данных std::stack и сказать std::multiset для хранения вытолкнутых элементов в отсортированном порядке (так что вы можете найти самый большой легко).

Код выглядит следующим образом. Это можно сделать более эффективным / короче, но я оставлю это вам.

#include <iostream>
#include <set>
#include <stack>

#define ASSERT(WHAT, MSG) \
    do { \
        if (!(WHAT)) { \
            std::cerr << "ASSERTION FAILURE AT LINE " \
                << __LINE__ << ": " #WHAT "\n" << MSG << '\n'; \
        } \
    } while (false)

#define DBG(MSG) std::cout << "DBG :" << __LINE__ << " " << MSG << '\n'

// helper functions to be able to stream out containers we're using...
std::ostream& operator<<(std::ostream& os, const std::multiset<int>& s)
{
    os << "{ ";
    for (const auto& x : s) std::cout << x << ' ';
    return os << '}';
}

// note this makes a deep copy of the stack (because "s" is passed by value
// not by reference), so we can pop all the elements destructively
std::ostream& operator<<(std::ostream& os, std::stack<int> s)
{
    os << "{ ";
    while (!s.empty())
    {
        std::cout << s.top() << ' ';
        s.pop();
    }
    return os << '}';
}

int main()
{
    std::stack<int> s;
    std::multiset<int> popped;

    int n, k;

    ASSERT(std::cin >> n >> k, "input must have parseable int values for n and k");

    DBG("n " << n << ", k " << k);
    ASSERT(n >= 0, "n must not be negative");
    ASSERT(k >= 0, "k must not be negative");

    for (int i = 0; i < n; ++i)
    {
        int x;
        ASSERT(std::cin >> x, "input must have parseable int for value #" << i + 1);
        s.push(x);
    }

    DBG("initial stack " << s);

    if (n == 0)
        std::cout << -1 << '\n';
    else if (k == 0)
        std::cout << s.top() << '\n';
    else if (k == 1)
    {
        if (n == 1)
            std::cout << -1 << '\n';
        else
        {
            s.pop(); // have to use up our k1 operation as a pop
            std::cout << s.top() << '\n';
        }
    }
    else if (k <= n) // can't pop all the values
    {
        for (int i = 1; i < k; ++i)
        {
            DBG("popping " << s.top());
            popped.insert(s.top()); // add to popped...
            s.pop(); // ...and remove from stack
        }
        DBG("popped k-1 elements (sorted) " << popped);
        DBG("stack " << s);
        // use the last operation to put the largest popped value back
        // (if the stack's has size 2 or more, could pop another one instead -
        //  no way to know which is better, but if the values are random then
        //  the max of all the popped elements is likely to be more than any
        //  given element)
        s.push(*popped.rbegin());  // largest value seen...
        std::cout << s.top() << '\n';
    }
    else // k > n so can pop all the values...
    {
        DBG("k > n");
        while (!s.empty())
        {
            popped.insert(s.top());
            s.pop();
        }
        // waste however many spare operations we have...
        for (int i = 0; i < k - n - 1; ++i)
            if (i % 2 == 0) // on first, third, fifth iteration...
            {
                DBG("push " << *popped.begin());
                s.push(*popped.begin());  // push lowest value seen back to stack...
                popped.erase(popped.begin());  // ...remove it from popped multiset
            }
            else
            {
                DBG("pop " << s.top());
                popped.insert(s.top());
                s.pop();
            }
        DBG("popped elements (sorted) " << popped);
        DBG("stack " << s);
        s.push(*popped.rbegin());  // push largest value...
        std::cout << s.top() << '\n';
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...