如何使用堆栈和队列非递归地生成所有可能的n元素集子集?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用堆栈和队列非递归地生成所有可能的n元素集子集?相关的知识,希望对你有一定的参考价值。
这是来自Michael T Goodrich和Robert Tamassia的Java数据结构和算法的问题。这该怎么做?任何帮助赞赏。
这就是我的想法,如果我错了,请纠正我:
将元素存储在Stack中。弹出第一个元素并将其存储在队列中,而Stack中的其余元素构成一个子集。恢复堆栈,现在弹出第二个元素(队列中首先弹出,队列中弹出第二个,从队列中弹出)和其他子集中的其余元素。同样弹出第三个元素然后第四个。现在轮到两个元素然后三个元素呢?我是否误解了这个问题并将其拉得太远了?
只是半眯眼的:
- 创建堆栈并忽略它;
- 创建队列并忽略它;
- 以长度为N的二进制形式输出(迭代地)从0到(2 ^ N)-1的数字,具有前导零。
通过将每个1位解释为包含,并且将每个0位解释为排除,可以从生成的整数的二进制表示容易地生成子集的任何所需的替代表示。
从技术上讲,这符合标准,因为它(a)创建了一个堆栈; (b)建立一个队列; (c)非递归地生成N个元素集的所有可能的子集。堆栈和队列对于迭代解决方案来说是严格冗余的,因此为什么要求它们没有任何进一步的指导/约束就使我失望。
更新:
通过将其视为循环缓冲区,可以使用队列替换对输入集的随机访问。 (当然,它不能用于其他任何事情。)可以将一个标记元素添加到队列中以指示每个周期何时完成,但是如上所述的算法更自然的是一次处理N个元素, N提前知道。当每个元素出列时,它被处理(为当前子集添加或忽略)并再次入队。
我想我有一个合理的解决方案,从这里被盗:http://arstechnica.com/civis/viewtopic.php?f=20&t=96354&sid=e74a29103e9297050680afbba6b72f32&start=40
因此,想法是Queue将保存子集,并且您的堆栈将保留您的原始集。空集是每个集的子集,因此我们用它初始化Queue。然后,对于堆栈中的每个元素,我们将其弹出。现在对于队列中的每个子集,我们将该子集出列并将两个副本排队: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;
}
我们使用完全相同的想法,其中Queue迭代地构造subsets
并且原始集存储在Stack中。
GenerateSubsets(Stack originalSetAsStack)
{
var queue = new Queue { new Set() };
while (!originalSetAsStack.IsEmpty)
{
var elem = originalSetAsStack.Pop();
while (true)
{
var currSubset = queue.Dequeue();
// This is key. This is how we know when to start
// the next iteration!
// This also assumes that any two empty sets are equal...
if (currSubset == new Set())
{
break;
}
var subsetWithElem = currSubset.Clone();
subsetWithElem.Add(elem);
// Add back in current subset. This has to be first!
// for our break to work above
queue.Queue(currSubset);
queue.Queue(subsetWithElem);
}
}
return queue;
}
为了说明为什么这个解决方案源于递归解决方案。观察:我们迭代地构造子集:
-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()类
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}
以上是关于如何使用堆栈和队列非递归地生成所有可能的n元素集子集?的主要内容,如果未能解决你的问题,请参考以下文章