【问题标题】:function that returns second element of a stack without altering the stack in C++在 C++ 中返回堆栈的第二个元素而不更改堆栈的函数
【发布时间】:2014-04-21 02:00:25
【问题描述】:

我认为返回堆栈的第二个元素而不弹出堆栈的最佳方法是创建一个函数是使用 peek 但 peek 返回顶部元素。我将如何覆盖 peek 以便它返回第二个元素,或者以其他方式使用 peek 来实现我的目标?

【问题讨论】:

  • “堆栈”是抽象数据类型。如果您想要具体的答案 - 显示您尝试更改的堆栈实现或解释您尝试实现通用“peek(n)”方法,该方法适用于只有“推送”和“弹出”的抽象堆栈......跨度>
  • 创建另一个堆栈来保存第二个之上的所有元素。之后取第二个元素的值,然后从第二个堆栈中弹出元素并放回原始堆栈
  • 一个栈应该只支持头部和尾部的操作。如果你想取第二个元素,你需要的不仅仅是一个堆栈。由于您使用c++ 标记它,我建议您直接使用std::dequestd::stack 默认情况下只是一个包装器。
  • 您需要符合标准吗?如果不是,我敢打赌这些元素在内存中彼此接近,即接近&top。倒数第二个元素可能位于&top-1

标签: c++ stack


【解决方案1】:

这是类似java的伪算法。您所做的是使用一个变量来存储堆栈的顶部(如果存在则弹出),使用另一个来存储堆栈的第二个元素(如果存在则查看),将顶部元素推回,然后返回第二个元素。

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

但一切都取决于堆栈的实现方式。在 C++ 中,您必须这样做。

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

【讨论】:

  • 首先我要感谢所有为这篇文章做出贡献的人。这是 Tony Gaddis 在我的 C++ 书中提出的一个练习。我能想到的最好的理想是改变这个复制堆栈函数,以便它在复制第一个堆栈时会计算出第二个元素,然后销毁它为清理而制作的副本
  • 模板 void stackType::copyStack(const stackType& otherStack) { delete[] list; maxStackSize = otherStack.maxStackSize; stackTop = otherStack.stackTop;列表 = 新类型 [maxStackSize]; //将 otherStack 复制到这个栈中 for (int j = 0; j
  • 对不起,我不知道如何格式化我的代码这里是我添加的两行,我希望实现目标: for (int i = 0; i
  • @Darnell 您目前想要实现的目标是未知的。您问题的标题与正文略有矛盾。您能否在标题和正文中尽可能清楚地说明您的问题?
【解决方案2】:

根据 C++ 标准,std::stack 包含一个名为 c 的容器的受保护成员变量。知道这一点并使用一点魔法,您可以通过指向该成员变量的指针来访问它。一旦您有权访问底层容器(默认为std::deque),您就可以访问包含的数据。

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);
}

这是因为虽然AdapterAccessor 不能直接访问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);
}

示例用法:

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;
}

【讨论】:

    【解决方案3】:

    我不确定这是否可能,因为堆栈是基于后进先出的原则。您所拥有的只是一个指向堆栈的指针,您可以从那里从堆栈顶部弹出,但不能在堆栈中弹出。我能想到的唯一方法就是创建一个类似的函数。

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

    或更通用的功能,例如

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

    【讨论】:

    • +0: 可能的开始...请查看帖子的标题“不改变堆栈” - 显然您的代码不足以满足这一点。
    • 它不应该改变堆栈,因为您正在函数中创建一个本地堆栈并且不应该影响正在使用的堆栈。您还可以将弹出的值推送到新堆栈中,当您获得所需的值时,重新填充原始堆栈。
    • 抱歉错过了您的复制...现在peek2 是 O(n) 而不是 O(1)... 绝对是一个解决方案,但我认为这不是一个好方法。
    【解决方案4】:

    在“堆栈”中不受限制。它是一种抽象数据类型,因此您可以定义自己的数据类型。如果您只是不想定义数据类型并想使用堆栈的某些功能。我建议您定义自己的功能(如 Sudo Andrew 的回答)。但这似乎牵强,不像堆栈。

    【讨论】:

    • for (int i = 0; i
    【解决方案5】:

    只需使用 std::vector 代替。

    std::vector<int>numbers;
    
    numbers.push_back(1);
    numbers.push_back(2);
    numbers.push_back(3);
    
    int secondElem = *(nums.end() - 2);
    
    cout << secondElem << endl;
    

    打印 2

    【讨论】:

      猜你喜欢
      • 2011-09-08
      • 1970-01-01
      • 2012-11-10
      • 1970-01-01
      • 2021-06-15
      • 2014-09-06
      • 2021-03-05
      • 2015-04-23
      • 1970-01-01
      相关资源
      最近更新 更多