Algorithm 如何使用堆栈和队列非递归地生成n元素集上所有可能的子集?
这是Michael T Goodrich和Robert Tamassia在Java中的数据结构和算法提出的问题。如何做到这一点?谢谢你的帮助 这就是我的想法,如果我错了,请纠正我: 在堆栈中存储元素。弹出第一个元素并将其存储在队列中,堆栈中的其余元素形成一个子集。恢复堆栈,现在从另一个子集中弹出第二个元素(在队列中弹出第一个、在队列中弹出第二个和从队列中推送)和堆栈中的其余元素。类似地,弹出第三个元素,然后是第四个元素。现在,轮到我们用两个元素和三个元素做同样的事情了?我是不是误解了这个问题,把它扯得太远了 只是半开玩笑地说:Algorithm 如何使用堆栈和队列非递归地生成n元素集上所有可能的子集?,algorithm,data-structures,stack,queue,push,Algorithm,Data Structures,Stack,Queue,Push,这是Michael T Goodrich和Robert Tamassia在Java中的数据结构和算法提出的问题。如何做到这一点?谢谢你的帮助 这就是我的想法,如果我错了,请纠正我: 在堆栈中存储元素。弹出第一个元素并将其存储在队列中,堆栈中的其余元素形成一个子集。恢复堆栈,现在从另一个子集中弹出第二个元素(在队列中弹出第一个、在队列中弹出第二个和从队列中推送)和堆栈中的其余元素。类似地,弹出第三个元素,然后是第四个元素。现在,轮到我们用两个元素和三个元素做同样的事情了?我是不是误解了这个问题,把
通过将队列视为循环缓冲区,可以使用队列替换对输入集的随机访问。(当然,它不能用于其他任何事情。)可以将标记元素添加到队列中,以指示每个循环何时完成,但对于上面介绍的算法来说,更自然的是一次处理N个元素,N是预先知道的。当每个元素退出队列时,会对其进行处理(为当前子集添加或忽略)并再次进入队列。我认为我有一个合理的解决方案,从这里偷来: 因此,这个想法是队列将保存子集,而堆栈将保存原始集合。空集是每个集合的子集,因此我们使用它初始化队列。然后,对于堆栈上的每个元素,我们将其弹出。现在,对于队列上的每个子集,我们将该子集出列,并将两个副本放入队列:1)一个没有新元素(即与原始元素相同),2)一个有新元素。棘手的部分是跟踪何时需要弹出堆栈的下一个元素(即何时完成当前元素)。一种方法是检查整个队列是否有匹配集(这意味着您已经添加了您构建的这个子集…所以停止)。但是一个好的/更干净的方法是使用空集作为标记 基本上,您有典型的递归解决方案:
GenerateSubsets(Set set)
{
if (set == Set.EmptySet)
return new List<Set>(set);
var elem = set.Remove();
var subsets = GenerateSubsets(set);
// Add all of thew subsets that contain elem (i.e. partition all subsets
// by whether they contain elem or do not contain elem)
subsets.AddRange(subsets.Map(subset => subset.Add(elem));
return subsets;
}
以说明此解决方案源自递归解决方案的原因。注意:
我们迭代构造子集:
-Start with the empty set => ({})
-Take some element from the stack
-Now for each element in the Queue, enqueue two: one with the current
element, and one without => ({}, {elem})
-Now take the next element and do the same => ({}, {elem}, {nextElem},
{elem, NextElem})
-Now take the third element and do the same => ({}, {elem}, {nextElem},
{elem, nextElem}, {thirdElem}, {thirdElem, elem}, {thirdElem, nextElem},
{elem, nextElem, thirdElem})
-...
我已经定义了ArrayStack()和ArrayQueue()类
您的解决方案假设您有一个存储原始元素的索引集合。我认为问题的关键在于只使用堆栈和队列。不切实际的当然但这是一个家庭作业问题。@roliu:听起来不错;但是如何非递归地恢复原始堆栈以生成第二个以及所有后续的子集呢?我只是在上面的回答中回答这个问题,因为我不能在这里真正格式化。如果我正确理解了您的解决方案,问题是您只会删除相邻的元素。例如,假设您正在移除{1,2,3,4,5}上的“一次两个元素”。然后移除{3,4},但不移除{2,4}。但是你是对的。。。由于有一种系统化的方法弹出
i
th元素,因此您可以使用下面Pieter建议的带有位掩码的简单解决方案。但我认为这不是最干净的/预期的解决方案。在构造第一个子集之后,原始集合如何存储在堆栈中?不是。我猜这名字不好吧?它从原始集合开始,但随着我们处理元素,它的大小会缩小。需要第三个存储:对原始集合的随机访问,或者对电源集合中的所有元素进行随机访问。显然,第一种方法的性能要高得多。我的解决方案如何需要随机访问“正在进行的工作”电源集。它将它们存储在队列中。。。不是名单。但你是对的,这个问题的措辞非常糟糕。我认为这是预期的解决方案,因为他们明确规定不应该有递归解决方案。
-Start with the empty set => ({})
-Take some element from the stack
-Now for each element in the Queue, enqueue two: one with the current
element, and one without => ({}, {elem})
-Now take the next element and do the same => ({}, {elem}, {nextElem},
{elem, NextElem})
-Now take the third element and do the same => ({}, {elem}, {nextElem},
{elem, nextElem}, {thirdElem}, {thirdElem, elem}, {thirdElem, nextElem},
{elem, nextElem, thirdElem})
-...
n=[1,2,3,4,5]
st=ArrayStack()
q=ArrayQueue()
q.enqueue(set())
for i in range(len(n)):
st.push(n[i])
while st.is_empty()==False:
cur_el=st.pop()
print('cur',cur_el)
for i in range(len(q)):
a=q.dequeue()
print('a',a)
q.enqueue(a)
b=a|{cur_el}
q.enqueue(b)
print('b',b)
while q.isempty()==False:
x=q.dequeue()
print(x)
OUTPUT
cur 5
a set()
b {5}
cur 4
a set()
b {4}
a {5}
b {4, 5}
cur 3
a set()
b {3}
a {4}
b {3, 4}
a {5}
b {3, 5}
a {4, 5}
b {3, 4, 5}
cur 2
a set()
b {2}
a {3}
b {2, 3}
a {4}
b {2, 4}
a {3, 4}
b {2, 3, 4}
a {5}
b {2, 5}
a {3, 5}
b {2, 3, 5}
a {4, 5}
b {2, 4, 5}
a {3, 4, 5}
b {2, 3, 4, 5}
cur 1
a set()
b {1}
a {2}
b {1, 2}
a {3}
b {1, 3}
a {2, 3}
b {1, 2, 3}
a {4}
b {1, 4}
a {2, 4}
b {1, 2, 4}
a {3, 4}
b {1, 3, 4}
a {2, 3, 4}
b {1, 2, 3, 4}
a {5}
b {1, 5}
a {2, 5}
b {1, 2, 5}
a {3, 5}
b {1, 3, 5}
a {2, 3, 5}
b {1, 2, 3, 5}
a {4, 5}
b {1, 4, 5}
a {2, 4, 5}
b {1, 2, 4, 5}
a {3, 4, 5}
b {1, 3, 4, 5}
a {2, 3, 4, 5}
b {1, 2, 3, 4, 5}
set()
{1}
{2}
{1, 2}
{3}
{1, 3}
{2, 3}
{1, 2, 3}
{4}
{1, 4}
{2, 4}
{1, 2, 4}
{3, 4}
{1, 3, 4}
{2, 3, 4}
{1, 2, 3, 4}
{5}
{1, 5}
{2, 5}
{1, 2, 5}
{3, 5}
{1, 3, 5}
{2, 3, 5}
{1, 2, 3, 5}
{4, 5}
{1, 4, 5}
{2, 4, 5}
{1, 2, 4, 5}
{3, 4, 5}
{1, 3, 4, 5}
{2, 3, 4, 5}
{1, 2, 3, 4, 5}