简体   繁体   中英

function that returns second element of a stack without altering the stack in C++

I am thinking that the best way to return the second element of a stack without popping the stack is to create a function is to uses peek but peek returns the top element. How would I override peek so that it returned the second element, or use peek in some other fashion to accomplish my goal?

This is java like pseudo algorithm. What you do is use a variable to store the top of the stack (pop if it exists), use another to store the second element of the stack (peek if it exists), push the top element back and then return the second element.

Object obj = stack.empty() ? null : stack.pop();
if(obj == null)
    return null;
Object ret = stack.empty() ? null : stack.peek();
stack.push(obj);
return ret;

But everything depends on how the stack is implemented. In C++, you'll have to do something like this.

if(stck.size() < 2) throw "Stack has no second element!";
Object obj = stck.top();
stck.pop();
Object ret = stck.top();
stack.push(obj);
return ret

According to the C++ Standard std::stack contains a protected member variable for the container named c . Knowing this and using a little bit of magic you can gain access to it with a pointer to this member variable. Once you have access to the underlying container ( std::deque by default) you can access the contained data.

template<class T /* value type */, class C /* container */>
typename std::stack<T, C>::container_type& GetContainer(std::stack<T,C>& adapter)
{
    struct AdapterAccessor : std::stack<T, C>
    {
        static std::stack<T, C>::container_type& Get(std::stack<T, C>& adapter)
        {
            return adapter.*&AdapterAccessor::c;
        }
    };

    return AdapterAccessor::Get(adapter);
}

This works because although AdapterAccessor does not have direct access to the contents of adapters it does have indirect access via the pointer-to-member.

You can also make it usable with other container adapters.

template <template<class, class> class Adapter, class T, class... Args>
typename Adapter<T, Args...>::container_type&
GetContainer(Adapter<T, Args...>& adapter)
{
    struct AdapterAccessor : Adapter<T, Args...>
    {
        static Adapter<T, Args...>::container_type& Get(Adapter<T, Args...>& adapter)
        {
            return adapter.*&AdapterAccessor::c;
        }
    };

    return AdapterAccessor::Get(adapter);
}

Example usage:

int main()
{
    std::stack<char> st;
    st.push('1');
    st.push('2');
    st.push('3');
    st.push('4');

    auto& contents = GetContainer(st);
    std::cout << contents[0] << std::endl;
    std::cout << contents[3] << std::endl;
    std::cout << contents[1] << std::endl;
    std::cout << contents[2] << std::endl;
}

I'm not sure if it is possible, since a stack is based off of the principle last in first out. All you have is a pointer to the stack, and from there you can pop off from the top of the stack, but you cannot pop off within the stack. The only way I can think of to do it would be to create a function like.

object returnSecond(stack<object> a){
 a.pop();
 return a.top();
}

or a more general one function like

object peekN(stack<object> a, int n){
 for(int i = 0;i<n;i++){
  a.pop();
 }
return a.top();
}

Not to be restricted in "Stack". It is an abstract datatype, so you can define the datatype of yourself. If you just don't want to define datatype and want to use some functions of stack. I advise you to define a function of yourself(like the answer of Sudo Andrew). But it seems far-fetched and not like stack.

just use std::vector instead.

std::vector<int>numbers;

numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);

int secondElem = *(nums.end() - 2);

cout << secondElem << endl;

prints 2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM